diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ff5fa0de6..991ac37df 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -7,7 +7,7 @@ - [ ] Only relevant files were touched - [ ] Only one feature/fix was added per PR and the code change compiles without warnings - [ ] The code change is tested and works with Tasmota core ESP8266 V.2.7.6 - - [ ] The code change is tested and works with Tasmota core ESP32 V.2.0.14 + - [ ] The code change is tested and works with Tasmota core ESP32 V.3.0.0 - [ ] I accept the [CLA](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla). _NOTE: The code change must pass CI tests. **Your PR cannot be merged unless tests pass**_ diff --git a/.github/workflows/Tasmota_build_devel.yml b/.github/workflows/Tasmota_build_devel.yml index aada97400..96fa3ac74 100644 --- a/.github/workflows/Tasmota_build_devel.yml +++ b/.github/workflows/Tasmota_build_devel.yml @@ -46,10 +46,14 @@ jobs: run: | cd lib/libesp32_lvgl/lv_binding_berry ../../libesp32/berry/berry -s -g solidify_all.be + - name: HASPmota Berry Code + run: | + cd lib/libesp32_lvgl/lv_haspmota + ../../libesp32/berry/berry -s -g solidify_all.be - uses: jason2866/upload-artifact@v2.0.3 with: - name: '["berry_tasmota", "berry_matter", "berry_animate", "berry_lvgl", "berry_header"]' - path: '["./lib/libesp32/berry_tasmota/src/solidify", "./lib/libesp32/berry_matter/src/solidify", "./lib/libesp32/berry_animate/src/solidify", "./lib/libesp32_lvgl/lv_binding_berry/src/solidify", "./lib/libesp32/berry/generate"]' + name: '["berry_tasmota", "berry_matter", "berry_animate", "berry_lvgl", "berry_haspmota", "berry_header"]' + path: '["./lib/libesp32/berry_tasmota/src/solidify", "./lib/libesp32/berry_matter/src/solidify", "./lib/libesp32/berry_animate/src/solidify", "./lib/libesp32_lvgl/lv_binding_berry/src/solidify", "./lib/libesp32_lvgl/lv_haspmota/src/solidify", "./lib/libesp32/berry/generate"]' push_solidified: needs: be_solidify @@ -69,12 +73,14 @@ jobs: berry_matter berry_animate berry_lvgl + berry_haspmota berry_header path: | ./lib/libesp32/berry_tasmota/src/solidify ./lib/libesp32/berry_matter/src/solidify ./lib/libesp32/berry_animate/src/solidify ./lib/libesp32_lvgl/lv_binding_berry/src/solidify + ./lib/libesp32_lvgl/lv_haspmota/src/solidify ./lib/libesp32/berry/generate - uses: stefanzweifel/git-auto-commit-action@v5 with: @@ -88,17 +94,17 @@ jobs: strategy: matrix: variant: - - tasmota32solo1-safeboot - tasmota32-safeboot + - tasmota32solo1-safeboot + - tasmota32c2-safeboot - tasmota32c3-safeboot - - tasmota32c3cdc-safeboot + - tasmota32c3ser-safeboot - tasmota32s2-safeboot - tasmota32s2cdc-safeboot - tasmota32s3-safeboot - - tasmota32s3cdc-safeboot - - tasmota32c2-safeboot + - tasmota32s3ser-safeboot - tasmota32c6-safeboot - - tasmota32c6cdc-safeboot + - tasmota32c6ser-safeboot steps: - uses: actions/checkout@v4 with: @@ -111,10 +117,17 @@ jobs: run: | pip install wheel pip install -U platformio - cp ./platformio_tasmota_core3_env_sample.ini ./platformio_tasmota_core3_env.ini cp ./platformio_override_sample.ini ./platformio_override.ini + - name: Add SHA to footer + run: | + COMMIT_SHA_LONG=$(git rev-parse --short HEAD || echo "") + SHA=${COMMIT_SHA_LONG::7} + sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT $SHA-/g" ./tasmota/include/tasmota_version.h - name: Run PlatformIO run: platformio run -e ${{ matrix.variant }} + #- name: Use esp32-solo1 safeboot for esp32 too + #run: | + #cp ./build_output/firmware/tasmota32solo1-safeboot.bin ./build_output/firmware/tasmota32-safeboot.bin - name: Upload safeboot firmware artifacts uses: jason2866/upload-artifact@v2.0.3 with: @@ -151,6 +164,11 @@ jobs: run: | pip install wheel pip install -U platformio + - name: Add SHA to footer + run: | + COMMIT_SHA_LONG=$(git rev-parse --short HEAD || echo "") + SHA=${COMMIT_SHA_LONG::7} + sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT $SHA-/g" ./tasmota/include/tasmota_version.h - name: Run PlatformIO run: platformio run -e ${{ matrix.variant }} - name: Upload firmware artifacts @@ -175,15 +193,13 @@ jobs: - tasmota32-display - tasmota32-ir - tasmota32-lvgl + - tasmota32c2 - tasmota32c3 - - tasmota32c3cdc + - tasmota32c6 - tasmota32s2 - tasmota32s2cdc - tasmota32s3 - - tasmota32s3cdc - tasmota32solo1 - - tasmota32c2-arduino30 - - tasmota32c6cdc-arduino30 steps: - uses: actions/checkout@v4 with: @@ -196,16 +212,17 @@ jobs: run: | pip install wheel pip install -U platformio - cp ./platformio_tasmota_core3_env_sample.ini ./platformio_tasmota_core3_env.ini cp ./platformio_override_sample.ini ./platformio_override.ini - name: Download safeboot firmwares uses: jason2866/download-artifact@v3.0.4 with: name: firmware_safeboot path: ./firmware - - name: Display downloaded files + - name: Add SHA to footer run: | - ls -R ./firmware/ + COMMIT_SHA_LONG=$(git rev-parse --short HEAD || echo "") + SHA=${COMMIT_SHA_LONG::7} + sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT $SHA-/g" ./tasmota/include/tasmota_version.h - name: Run PlatformIO run: platformio run -e ${{ matrix.variant }} - name: Upload firmware artifacts @@ -235,16 +252,17 @@ jobs: run: | pip install wheel pip install -U platformio - cp ./platformio_tasmota_core3_env_sample.ini ./platformio_tasmota_core3_env.ini cp ./platformio_override_sample.ini ./platformio_override.ini - name: Download safeboot firmwares uses: jason2866/download-artifact@v3.0.4 with: name: firmware_safeboot path: ./firmware - - name: Display downloaded files + - name: Add SHA to footer run: | - ls -R ./firmware/ + COMMIT_SHA_LONG=$(git rev-parse --short HEAD || echo "") + SHA=${COMMIT_SHA_LONG::7} + sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT $SHA-/g" ./tasmota/include/tasmota_version.h - name: Run PlatformIO run: platformio run -e ${{ matrix.variant }}-${{ matrix.language }} - name: Upload language firmware artifacts diff --git a/.github/workflows/Tasmota_build_master.yml b/.github/workflows/Tasmota_build_master.yml index c7b5af17c..d52e5a2ea 100644 --- a/.github/workflows/Tasmota_build_master.yml +++ b/.github/workflows/Tasmota_build_master.yml @@ -21,17 +21,17 @@ jobs: strategy: matrix: variant: - - tasmota32solo1-safeboot - tasmota32-safeboot + - tasmota32solo1-safeboot + - tasmota32c2-safeboot - tasmota32c3-safeboot - - tasmota32c3cdc-safeboot + - tasmota32c3ser-safeboot - tasmota32s2-safeboot - tasmota32s2cdc-safeboot - tasmota32s3-safeboot - - tasmota32s3cdc-safeboot - - tasmota32c2-safeboot + - tasmota32s3ser-safeboot - tasmota32c6-safeboot - - tasmota32c6cdc-safeboot + - tasmota32c6ser-safeboot steps: - uses: actions/checkout@v4 with: @@ -44,8 +44,10 @@ jobs: run: | pip install wheel pip install -U platformio - cp ./platformio_tasmota_core3_env_sample.ini ./platformio_tasmota_core3_env.ini cp ./platformio_override_sample.ini ./platformio_override.ini + - name: Add "release" to footer + run: | + sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT release-/g" ./tasmota/include/tasmota_version.h - name: Run PlatformIO run: platformio run -e ${{ matrix.variant }} - name: Upload safeboot firmware artifacts @@ -83,6 +85,10 @@ jobs: run: | pip install wheel pip install -U platformio + cp ./platformio_override_sample.ini ./platformio_override.ini + - name: Add "release" to footer + run: | + sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT release-/g" ./tasmota/include/tasmota_version.h - name: Run PlatformIO run: platformio run -e ${{ matrix.variant }} - name: Upload firmware artifacts @@ -107,12 +113,12 @@ jobs: - tasmota32-display - tasmota32-ir - tasmota32-lvgl + - tasmota32c2 - tasmota32c3 - - tasmota32c3cdc + - tasmota32c6 - tasmota32s2 - tasmota32s2cdc - tasmota32s3 - - tasmota32s3cdc - tasmota32solo1 steps: - uses: actions/checkout@v4 @@ -126,6 +132,7 @@ jobs: run: | pip install wheel pip install -U platformio + cp ./platformio_override_sample.ini ./platformio_override.ini - name: Download safeboot firmwares uses: jason2866/download-artifact@v3.0.4 with: @@ -134,6 +141,9 @@ jobs: - name: Display downloaded files run: | ls -R ./firmware/ + - name: Add "release" to footer + run: | + sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT release-/g" ./tasmota/include/tasmota_version.h - name: Run PlatformIO run: platformio run -e ${{ matrix.variant }} - name: Upload firmware artifacts @@ -163,6 +173,7 @@ jobs: run: | pip install wheel pip install -U platformio + cp ./platformio_override_sample.ini ./platformio_override.ini - name: Download safeboot firmwares uses: jason2866/download-artifact@v3.0.4 with: @@ -171,6 +182,9 @@ jobs: - name: Display downloaded files run: | ls -R ./firmware/ + - name: Add "release" to footer + run: | + sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT release-/g" ./tasmota/include/tasmota_version.h - name: Run PlatformIO run: platformio run -e ${{ matrix.variant }}-${{ matrix.language }} - name: Upload language firmware artifacts diff --git a/.github/workflows/build_all_the_things.yml b/.github/workflows/build_all_the_things.yml index 3984a31ab..365b1ca81 100644 --- a/.github/workflows/build_all_the_things.yml +++ b/.github/workflows/build_all_the_things.yml @@ -25,7 +25,7 @@ jobs: fail-fast: true matrix: variant: - - tasmota32-safeboot + - tasmota32solo1-safeboot steps: - uses: actions/checkout@v4 - name: Set up Python @@ -91,32 +91,27 @@ jobs: - tasmota-sensors - tasmota-zbbridge - tasmota32 + - tasmota32solo1 + - tasmota32c2 - tasmota32c3 - - tasmota32c6cdc-arduino30 + - tasmota32c6 - tasmota32s2 + - tasmota32s2cdc - tasmota32s3 - tasmota32-zbbrdgpro - tasmota-zigbee - tasmota32-bluetooth - - tasmota32-core2 - tasmota32-nspanel - tasmota32-display - tasmota32-ir - tasmota32-lvgl - - tasmota32c3cdc - - tasmota32s2cdc - - tasmota32s3cdc - - tasmota32solo1 - - tasmota32solo1-safeboot - - tasmota32c3-safeboot - - tasmota32c3cdc-safeboot + - tasmota32-safeboot - tasmota32s2-safeboot - tasmota32s2cdc-safeboot - tasmota32s3-safeboot - - tasmota32s3cdc-safeboot - tasmota32c2-safeboot + - tasmota32c3-safeboot - tasmota32c6-safeboot - - tasmota32c6cdc-safeboot steps: - uses: actions/checkout@v4 - name: Set up Python @@ -130,7 +125,6 @@ jobs: pip install -U platformio #platformio upgrade --dev #platformio update - cp ./platformio_tasmota_core3_env_sample.ini ./platformio_tasmota_core3_env.ini cp ./platformio_override_sample.ini ./platformio_override.ini - name: Run PlatformIO run: platformio run -e ${{ matrix.variant }} diff --git a/.github/workflows/pr_comment.yml.off b/.github/workflows/pr_comment.yml.off new file mode 100644 index 000000000..af4b9a773 --- /dev/null +++ b/.github/workflows/pr_comment.yml.off @@ -0,0 +1,61 @@ +name: Comment on pull request +on: + workflow_run: + workflows: [Tasmota CI] + types: [completed] +jobs: + pr_comment: + if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v7 + with: + # This snippet is public-domain, taken from + # https://github.com/oprypin/nightly.link/blob/master/.github/workflows/pr-comment.yml + script: | + async function upsertComment(owner, repo, issue_number, purpose, body) { + const {data: comments} = await github.rest.issues.listComments( + {owner, repo, issue_number}); + + const marker = ``; + body = marker + "\n" + body; + + const existing = comments.filter((c) => c.body.includes(marker)); + if (existing.length > 0) { + const last = existing[existing.length - 1]; + core.info(`Updating comment ${last.id}`); + await github.rest.issues.updateComment({ + owner, repo, + body, + comment_id: last.id, + }); + } else { + core.info(`Creating a comment in issue / PR #${issue_number}`); + await github.rest.issues.createComment({issue_number, body, owner, repo}); + } + } + + const {owner, repo} = context.repo; + const run_id = ${{github.event.workflow_run.id}}; + + const pull_requests = ${{ toJSON(github.event.workflow_run.pull_requests) }}; + if (!pull_requests.length) { + return core.error("This workflow doesn't match any pull requests!"); + } + + const artifacts = await github.paginate( + github.rest.actions.listWorkflowRunArtifacts, {owner, repo, run_id}); + if (!artifacts.length) { + return core.error(`No artifacts found`); + } + let body = `Download the artifacts for this pull request:\n`; + for (const art of artifacts) { + body += `\n* [${art.name}.zip](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; + } + + core.info("Review thread message body:", body); + + for (const pr of pull_requests) { + await upsertComment(owner, repo, pr.number, + "nightly-link", body); + } diff --git a/BUILDS.md b/BUILDS.md index 09450ed6d..4f9aed466 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -2,282 +2,279 @@ l = lite, t = tasmota (ESP8266 / ESP32), k = knx, s = sensors, i = ir, d = display -Note: `minimal` variant is not listed as it shouldn't be used outside of the [upgrading](https://tasmota.github.io/docs/Upgrading/) process. +Note: the `minimal` variant is not listed as it shouldn't be used outside of the [upgrading](https://tasmota.github.io/docs/Upgrading/) process. -| Feature or Sensor | l | t | k | s | i | d | Remarks -|---------------------------|---|-------|---|---|---|---|-------- -| MY_LANGUAGE en_GB | x | x / x | x | x | x | x | -| USE_IMPROV | x | x / x | x | x | x | x | -| USE_UFILESYS | - | - / x | - | - | - | - | -| USE_ARDUINO_OTA | - | - / - | - | - | - | - | -| USE_DOMOTICZ | - | x / x | x | x | x | - | -| USE_HOME_ASSISTANT | - | - / - | - | - | - | - | -| USE_TASMOTA_DISCOVERY | x | x / x | x | x | x | x | -| USE_MQTT_TLS* | - | - / x | - | - | - | - | -| USE_MQTT_AWS_IOT | - | - / - | - | - | - | - | -| USE_4K_RSA | - | - / - | - | - | - | - | -| USE_TELEGRAM | - | - / - | - | - | - | - | -| USE_KNX | - | - / x | x | - | - | - | -| USE_WEBSERVER | x | x / x | x | x | x | x | -| USE_WEBSEND_RESPONSE | - | - / - | - | - | - | - | -| USE_EMULATION_HUE | x | x / x | - | x | - | - | -| USE_EMULATION_WEMO | x | x / x | - | x | - | - | -| USE_DISCOVERY | - | - / - | - | - | - | - | -| WEBSERVER_ADVERTISE | - | x / - | x | - | - | x | -| MQTT_HOST_DISCOVERY | - | - / - | - | - | - | - | -| USE_TIMERS | x | x / x | x | x | x | x | -| USE_TIMERS_WEB | x | x / x | x | x | x | x | -| USE_SUNRISE | x | x / x | x | x | x | x | -| USE_RULES | x | x / x | x | x | x | x | -| USE_SCRIPT | - | - / - | - | - | - | - | -| USE_EXPRESSION | - | - / x | - | - | - | - | Every ESP32 + ESP8266 > 1MB -| SUPPORT_IF_STATEMENT | - | - / x | - | - | - | - | Every ESP32 + ESP8266 > 1MB -| USE_HOTPLUG | - | - / - | - | - | - | - | -| USE_PROMETHEUS | - | - / - | - | - | - | - | -| USE_PING | - | - / - | - | - | - | - | -| | | | | | | | -| Feature or Sensor | l | t | k | s | i | d | Remarks -| ROTARY_V1 | - | x / x | - | x | - | - | -| USE_SONOFF_RF | - | x / - | x | x | - | - | -| USE_RF_FLASH | - | x / - | x | x | - | - | -| USE_SONOFF_SC | - | x / - | x | x | - | - | -| USE_TUYA_MCU | x | x / - | x | x | - | x | -| USE_ARMTRONIX_DIMMERS | - | x / - | x | - | - | - | -| USE_PS_16_DZ | - | x / - | x | - | - | - | -| USE_SONOFF_IFAN | - | x / - | x | - | - | - | -| USE_BUZZER | - | x / x | x | x | - | - | -| USE_ARILUX_RF | - | x / - | x | - | - | - | -| USE_SHUTTER | - | x / x | x | - | - | - | -| USE_DEEPSLEEP | - | x / x | - | x | - | - | -| USE_EXS_DIMMER | - | x / - | x | - | - | - | -| USE_DEVICE_GROUPS | - | x / x | - | - | - | - | -| USE_PWM_DIMMER | - | x / - | x | - | - | - | -| USE_KEELOQ | - | - / - | - | - | - | - | -| USE_SONOFF_D1 | - | x / - | x | - | - | - | -| USE_SHELLY_DIMMER | - | x / - | - | - | - | - | -| USE_AC_ZERO_CROSS_DIMMER | - | x / x | x | x | x | x | -| | | | | | | | -| Feature or Sensor | l | t | k | s | i | d | Remarks -| USE_LIGHT | x | x / x | x | x | x | x | -| USE_WS2812 | - | x / x | x | x | - | x | -| USE_WS2812_DMA | - | - / - | - | - | - | - | -| USE_MY92X1 | - | x / - | x | x | - | x | -| USE_SM16716 | - | x / - | x | x | - | x | -| USE_SM2135 | - | x / - | x | x | - | x | -| USE_SM2335 | - | x / - | x | x | - | x | -| USE_BP5758D | - | x / - | x | x | - | x | -| USE_BP1658CJ | - | x / - | x | x | - | x | -| USE_SONOFF_L1 | - | x / - | x | x | - | x | -| USE_ELECTRIQ_MOODL | - | x / - | x | x | - | x | -| | | | | | | | -| USE_ENERGY_SENSOR | - | x / x | x | x | - | - | -| USE_ENERGY_DUMMY | - | x / x | x | x | - | - | -| USE_PZEM004T | - | x / x | x | x | - | - | -| USE_PZEM_AC | - | x / x | x | x | - | - | -| USE_PZEM_DC | - | x / x | x | x | - | - | -| USE_MCP39F501 | - | x / - | x | x | - | - | -| USE_SDM72 | - | - / x | - | x | - | - | -| USE_SDM120 | - | - / x | - | x | - | - | -| USE_SDM230 | - | - / x | - | - | - | - | -| USE_SDM630 | - | - / x | - | x | - | - | -| USE_DDS2382 | - | - / x | - | x | - | - | -| USE_DDSU666 | - | - / x | - | x | - | - | -| USE_SOLAX_X1 | - | - / - | - | - | - | - | -| USE_LE01MR | - | - / - | - | - | - | - | -| USE_BL09XX | - | x / x | x | x | - | - | -| USE_TELEINFO | - | - / - | - | - | - | - | -| USE_IEM3000 | - | - / - | - | - | - | - | -| USE_WE517 | - | - / x | - | - | - | - | -| USE_MODBUS_ENERGY | - | - / x | - | - | - | - | -| | | | | | | | -| USE_ADC_VCC | x | - / - | - | - | x | - | -| USE_COUNTER | - | x / x | x | x | - | x | -| USE_DS18x20 | - | x / x | x | x | - | x | -| USE_DHT | - | x / x | x | x | - | x | -| USE_MAX31855 | - | - / x | - | x | - | - | -| USE_MAX31865 | - | - / - | - | - | - | - | -| USE_THERMOSTAT | - | - / - | - | - | - | - | -| USE_LMT01 | - | - / x | - | x | - | - | -| | | | | | | | -| Feature or Sensor | l | t | k | s | i | d | Remarks -| USE_I2C | - | x / x | x | x | - | x | -| USE_SHT | - | - / x | - | x | - | - | -| USE_HTU | - | - / x | - | x | - | - | -| USE_BMP | - | - / x | - | x | - | - | -| USE_BME68X | - | - / x | - | x | - | - | -| USE_BH1750 | - | - / x | - | x | - | - | -| USE_VEML6070 | - | - / x | - | x | - | - | -| USE_ADS1115 | - | - / x | - | x | - | - | -| USE_INA219 | - | - / x | - | x | - | - | -| USE_INA226 | - | - / - | - | - | - | - | -| USE_INA3221 | - | - / - | - | - | - | - | -| USE_SHT3X | - | - / x | - | x | - | - | -| USE_TSL2561 | - | - / - | - | - | - | - | -| USE_TSL2591 | - | - / - | - | - | - | - | -| USE_MGS | - | - / x | - | x | - | - | -| USE_SGP30 | - | - / x | - | x | - | - | -| USE_SGP40 | - | - / x | - | x | - | - | -| USE_SGP4X | - | - / x | - | - | - | - | -| USE_SEN5X | - | - / x | - | x | - | - | -| USE_SI1145 | - | - / - | - | - | - | - | -| USE_LM75AD | - | - / x | - | x | - | - | -| USE_APDS9960 | - | - / - | - | - | - | - | -| USE_MCP230xx | - | - / - | - | - | - | - | -| USE_MCP23XXX_DRV | - | - / - | - | - | - | - | -| USE_PCA9632 | - | - / - | - | - | - | - | -| USE_PCA9685 | - | - / - | - | - | - | - | -| USE_PCA9685_V2 | - | - / - | - | - | - | - | -| USE_MPR121 | - | - / - | - | - | - | - | -| USE_CCS811 | - | - / - | - | x | - | - | -| USE_CCS811_V2 | - | - / x | - | - | - | - | -| USE_ENS16x | - | - / - | - | - | - | - | -| USE_ENS210 | - | - / - | - | - | - | - | -| USE_MPU6050 | - | - / - | - | - | - | - | -| USE_DS3231 | - | - / - | - | - | - | - | -| USE_MGC3130 | - | - / - | - | - | - | - | -| USE_MAX44009 | - | - / - | - | - | - | - | -| USE_SCD30 | - | - / x | - | x | - | - | -| USE_SCD40 | - | - / x | - | - | - | - | -| USE_SPS30 | - | - / - | - | - | - | - | -| USE_ADE7880 | - | - / - | - | - | - | - | -| USE_ADE7953 | - | x / x | x | x | - | x | -| USE_VL53L0X | - | - / x | - | x | - | - | -| USE_VL53L1X | - | - / - | - | - | - | - | -| USE_MLX90614 | - | - / - | - | - | - | - | -| USE_CHIRP | - | - / - | - | - | - | - | -| USE_PAJ7620 | - | - / - | - | - | - | - | -| USE_PCF8574 | - | - / - | - | - | - | - | -| USE_PMSA003I | - | - / - | - | - | - | - | -| USE_LOX_O2 | - | - / x | - | x | - | - | -| USE_GDK101 | - | - / - | - | - | - | - | -| USE_TC74 | - | - / - | - | - | - | - | -| USE_PCA9557 | - | - / - | - | - | - | - | -| | | | | | | | -| Feature or Sensor | l | t | k | s | i | d | Remarks -| USE_HIH6 | - | - / x | - | x | - | - | -| USE_DHT12 | - | - / x | - | x | - | - | -| USE_DS1624 | - | - / x | - | x | - | - | -| USE_AHT1x | - | - / - | - | - | - | - | -| USE_HDC1080 | - | - / - | - | - | - | - | -| USE_WEMOS_MOTOR_V1 | - | - / x | - | x | - | - | -| USE_IAQ | - | - / x | - | x | - | - | -| USE_AS3935 | - | - / x | - | x | - | - | -| USE_VEML6075 | - | - / - | - | - | - | - | -| USE_VEML7700 | - | - / - | - | - | - | - | -| USE_MCP9808 | - | - / - | - | - | - | - | -| USE_MLX90640 | - | - / - | - | - | - | - | -| USE_HP303B | - | - / - | - | - | - | - | -| USE_EZOCO2 | - | - / - | - | - | - | - | -| USE_EZODO | - | - / - | - | - | - | - | -| USE_EZOEC | - | - / - | - | - | - | - | -| USE_EZOFLO | - | - / - | - | - | - | - | -| USE_EZOHUM | - | - / - | - | - | - | - | -| USE_EZOO2 | - | - / - | - | - | - | - | -| USE_EZOORP | - | - / - | - | - | - | - | -| USE_EZOPH | - | - / - | - | - | - | - | -| USE_EZOPMP | - | - / - | - | - | - | - | -| USE_EZOPRS | - | - / - | - | - | - | - | -| USE_EZORGB | - | - / - | - | - | - | - | -| USE_EZORTD | - | - / - | - | - | - | - | -| USE_SEESAW_SOIL | - | - / - | - | - | - | - | -| USE_TOF10120 | - | - / - | - | - | - | - | -| USE_BM8563 | - | - / - | - | - | - | - | -| USE_AM2320 | - | - / - | - | - | - | - | -| USE_T67XX | - | - / - | - | - | - | - | -| USE_HM330X | - | - / - | - | - | - | - | -| USE_HDC2010 | - | - / - | - | - | - | - | -| USE_PCF85363 | - | - / - | - | - | - | - | -| USE_DS3502 | - | - / - | - | - | - | - | -| USE_HYT | - | - / - | - | - | - | - | -| USE_LUXV30B | - | - / - | - | - | - | - | -| USE_HMC5883L | - | - / - | - | - | - | - | -| USE_QMC5883L | - | - / - | - | - | - | - | -| | | | | | | | -| Feature or Sensor | l | t | k | s | i | d | Remarks -| USE_SPI | - | - / - | - | - | - | x | -| USE_RC522 | - | - / - | - | - | - | - | -| USE_CANSNIFFER | - | - / - | - | - | - | - | -| USE_MHZ19 | - | - / x | - | x | - | - | -| USE_SENSEAIR | - | - / x | - | x | - | - | -| USE_PMS5003 | - | - / x | - | x | - | - | -| USE_NOVA_SDS | - | - / x | - | x | - | - | -| USE_HPMA | - | - / x | - | x | - | - | -| USE_SERIAL_BRIDGE | - | x / x | x | x | - | x | -| USE_MODBUS_BRIDGE | - | - / x | - | - | - | - | -| USE_MP3_PLAYER | - | - / x | - | x | - | - | -| USE_AZ7798 | - | - / - | - | - | - | - | -| USE_PN532_HSU | - | - / x | - | x | - | - | -| USE_RDM6300 | - | - / x | - | x | - | - | -| USE_IBEACON | - | - / x | - | x | - | - | -| USE_GPS | - | - / - | - | - | - | - | -| USE_HM10 | - | - / - | - | x | - | - | -| USE_HRXL | - | - / x | - | x | - | - | -| USE_TASMOTA_CLIENT | - | - / - | - | - | - | - | -| USE_OPENTHERM | - | - / - | - | - | - | - | -| USE_MIEL_HVAC | - | - / - | - | - | - | - | -| USE_PROJECTOR_CTRL | - | - / - | - | - | - | - | -| USE_AS608 | - | - / - | - | - | - | - | -| USE_LD2410 | - | - / - | - | - | - | - | -| USE_GM861 | - | - / - | - | - | - | - | -| USE_TCP_BRIDGE | - | - / - | - | - | - | - | zbbridge / zbbrdgpro -| | | | | | | | -| USE_NRF24 | - | - / - | - | - | - | - | -| USE_MIBLE | - | - / - | - | - | - | - | -| USE_ZIGBEE | - | - / - | - | - | - | - | -| USE_ZIGBEE_ZNP | - | - / - | - | - | - | - | -| USE_ZIGBEE_EZSP | - | - / - | - | - | - | - | Sonoff ZbBridge -| | | | | | | | -| USE_IR_REMOTE | - | x / - | x | x | x | x | -| USE_IR_RECEIVE | - | x / - | x | x | x | x | -| USE_IR_REMOTE_FULL | - | - / - | - | - | x | - | Enable ALL protocols -| | | | | | | | -| USE_SR04 | - | - / - | - | x | - | - | -| USE_ME007 | - | - / - | - | - | - | - | -| USE_DYP | - | - / - | - | - | - | - | -| USE_TM1638 | - | - / x | - | x | - | - | -| USE_HX711 | - | - / x | - | x | - | - | -| USE_TX2x_WIND_SENSOR | - | - / - | - | - | - | - | -| USE_WINDMETER | - | - / - | - | - | - | - | -| USE_RC_SWITCH | - | - / x | - | x | - | - | -| USE_RF_SENSOR | - | - / x | - | x | - | - | AlectoV2 only -| USE_HRE | - | - / x | - | x | - | - | -| USE_A4988_STEPPER | - | - / - | - | - | - | - | -| USE_NEOPOOL | - | - / - | - | - | - | - | -| USE_FLOWRATEMETER | - | - / - | - | - | - | - | -| | | | | | | | -| Feature or Sensor | l | t | k | s | i | d | Remarks -| USE_DISPLAY | - | - / - | - | - | - | x | -| USE_DISPLAY_LCD | - | - / - | - | - | - | x | -| USE_DISPLAY_SSD1306 | - | - / - | - | - | - | x | -| USE_DISPLAY_MATRIX | - | - / - | - | - | - | x | -| USE_DISPLAY_SH1106 | - | - / - | - | - | - | x | -| USE_DISPLAY_ILI9341 | - | - / - | - | - | - | x | -| USE_DISPLAY_EPAPER_29 | - | - / - | - | - | - | x | -| USE_DISPLAY_EPAPER_42 | - | - / - | - | - | - | x | -| USE_DISPLAY_SSD1351 | - | - / - | - | - | - | x | -| USE_DISPLAY_RA8876 | - | - / - | - | - | - | x | -| USE_DISPLAY_ST7789 | - | - / - | - | - | - | x | -| USE_DISPLAY_TM1637 | - | - / - | - | - | - | x | -| USE_DISPLAY_TM1621_SONOFF | - | - / x | - | - | - | - | -| USE_DISPLAY_TM1650 | - | - / - | - | - | - | - | -| | | | | | | | -| USE_FT5206 | - | - / - | - | - | - | - | -| USE_FTC532 | - | - / - | - | - | - | - | -| USE_BS814A2 | - | - / - | - | - | - | - | -| | | | | | | | -| ESP32 Feature | l | t | k | s | i | d | Remarks -| USE_HALLEFFECT | | / x | | | | | -| USE_MI_ESP32 | | / x | | | | | See SetOption115 -| USE_IBEACON_ESP32 | | / - | | | | | -| USE_WEBCAM | | / - | | | | | -| USE_ETHERNET | | / x | | | | | -| USE_I2S_AUDIO | | / - | | | | | -| USE_TTGO_WATCH | | / - | | | | | -| USE_SONOFF_SPM | | / x | | | | | -| USE_DISPLAY_TM1621_SONOFF | | / x | | | | | -| USE_SHELLY_PRO | | / x | | | | | -| USE_DALI | | / - | | | | | -| USE_DINGTIAN_RELAY | | / - | | | | | -| USE_MATTER_DEVICE | | / x | | | | | See SetOption151 +| **Feature or Sensor** | **l** | **t** | **k** | **s** | **i** | **d** | **Remarks** | +| ------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | --------------------------- | +| MY_LANGUAGE en_GB | x | x / x | x | x | x | x | +| USE_IMPROV | x | x / x | x | x | x | x | +| USE_UFILESYS | - | - / x | - | - | - | - | +| USE_ARDUINO_OTA | - | - / - | - | - | - | - | +| USE_DOMOTICZ | - | x / x | x | x | x | - | +| USE_HOME_ASSISTANT | - | - / - | - | - | - | - | +| USE_TASMOTA_DISCOVERY | x | x / x | x | x | x | x | +| USE_MQTT_TLS\* | - | - / x | - | - | - | - | +| USE_MQTT_AWS_IOT | - | - / - | - | - | - | - | +| USE_4K_RSA | - | - / - | - | - | - | - | +| USE_TELEGRAM | - | - / - | - | - | - | - | +| USE_KNX | - | - / x | x | - | - | - | +| USE_WEBSERVER | x | x / x | x | x | x | x | +| USE_WEBSEND_RESPONSE | - | - / - | - | - | - | - | +| USE_EMULATION_HUE | x | x / x | - | x | - | - | +| USE_EMULATION_WEMO | x | x / x | - | x | - | - | +| USE_DISCOVERY | - | - / - | - | - | - | - | +| WEBSERVER_ADVERTISE | - | x / - | x | - | - | x | +| MQTT_HOST_DISCOVERY | - | - / - | - | - | - | - | +| USE_TIMERS | x | x / x | x | x | x | x | +| USE_TIMERS_WEB | x | x / x | x | x | x | x | +| USE_SUNRISE | x | x / x | x | x | x | x | +| USE_RULES | x | x / x | x | x | x | x | +| USE_SCRIPT | - | - / - | - | - | - | - | +| USE_EXPRESSION | - | - / x | - | - | - | - | Every ESP32 + ESP8266 > 1MB | +| SUPPORT_IF_STATEMENT | - | - / x | - | - | - | - | Every ESP32 + ESP8266 > 1MB | +| USE_HOTPLUG | - | - / - | - | - | - | - | +| USE_PROMETHEUS | - | - / - | - | - | - | - | +| USE_PING | - | - / - | - | - | - | - | +| | | | | | | | +| **Feature or Sensor** | **l** | **t** | **k** | **s** | **i** | **d** | **Remarks** | +| ROTARY_V1 | - | x / x | - | x | - | - | +| USE_SONOFF_RF | - | x / - | x | x | - | - | +| USE_RF_FLASH | - | x / - | x | x | - | - | +| USE_SONOFF_SC | - | x / - | x | x | - | - | +| USE_TUYA_MCU | x | x / - | x | x | - | x | +| USE_ARMTRONIX_DIMMERS | - | x / - | x | - | - | - | +| USE_PS_16_DZ | - | x / - | x | - | - | - | +| USE_SONOFF_IFAN | - | x / - | x | - | - | - | +| USE_BUZZER | - | x / x | x | x | - | - | +| USE_ARILUX_RF | - | x / - | x | - | - | - | +| USE_SHUTTER | - | x / x | x | - | - | - | +| USE_DEEPSLEEP | - | x / x | - | x | - | - | +| USE_EXS_DIMMER | - | x / - | x | - | - | - | +| USE_DEVICE_GROUPS | - | x / x | - | - | - | - | +| USE_PWM_DIMMER | - | x / - | x | - | - | - | +| USE_KEELOQ | - | - / - | - | - | - | - | +| USE_SONOFF_D1 | - | x / - | x | - | - | - | +| USE_SHELLY_DIMMER | - | x / - | - | - | - | - | +| USE_AC_ZERO_CROSS_DIMMER | - | x / x | x | x | x | x | +| | | | | | | | +| **Feature or Sensor** | **l** | **t** | **k** | **s** | **i** | **d** | **Remarks** | +| USE_LIGHT | x | x / x | x | x | x | x | +| USE_WS2812 | - | x / x | x | x | - | x | +| USE_WS2812_DMA | - | - / - | - | - | - | - | +| USE_MY92X1 | - | x / - | x | x | - | x | +| USE_SM16716 | - | x / - | x | x | - | x | +| USE_SM2135 | - | x / - | x | x | - | x | +| USE_SM2335 | - | x / - | x | x | - | x | +| USE_BP5758D | - | x / - | x | x | - | x | +| USE_BP1658CJ | - | x / - | x | x | - | x | +| USE_SONOFF_L1 | - | x / - | x | x | - | x | +| USE_ELECTRIQ_MOODL | - | x / - | x | x | - | x | +| | | | | | | | +| USE_ENERGY_SENSOR | - | x / x | x | x | - | - | +| USE_ENERGY_DUMMY | - | x / x | x | x | - | - | +| USE_PZEM004T | - | x / x | x | x | - | - | +| USE_PZEM_AC | - | x / x | x | x | - | - | +| USE_PZEM_DC | - | x / x | x | x | - | - | +| USE_MCP39F501 | - | x / - | x | x | - | - | +| USE_SDM72 | - | - / x | - | x | - | - | +| USE_SDM120 | - | - / x | - | x | - | - | +| USE_SDM230 | - | - / x | - | - | - | - | +| USE_SDM630 | - | - / x | - | x | - | - | +| USE_DDS2382 | - | - / x | - | x | - | - | +| USE_DDSU666 | - | - / x | - | x | - | - | +| USE_SOLAX_X1 | - | - / - | - | - | - | - | +| USE_LE01MR | - | - / - | - | - | - | - | +| USE_BL09XX | - | x / x | x | x | - | - | +| USE_TELEINFO | - | - / - | - | - | - | - | +| USE_IEM3000 | - | - / - | - | - | - | - | +| USE_WE517 | - | - / x | - | - | - | - | +| USE_MODBUS_ENERGY | - | - / x | - | - | - | - | +| | | | | | | | +| USE_ADC_VCC | x | - / - | - | - | x | - | +| USE_COUNTER | - | x / x | x | x | - | x | +| USE_DS18x20 | - | x / x | x | x | - | x | +| USE_DHT | - | x / x | x | x | - | x | +| USE_MAX31855 | - | - / x | - | x | - | - | +| USE_MAX31865 | - | - / - | - | - | - | - | +| USE_THERMOSTAT | - | - / - | - | - | - | - | +| USE_LMT01 | - | - / x | - | x | - | - | +| | | | | | | | +| **Feature or Sensor** | **l** | **t** | **k** | **s** | **i** | **d** | **Remarks** | +| USE_I2C | - | x / x | x | x | - | x | +| USE_SHT | - | - / x | - | x | - | - | +| USE_HTU | - | - / x | - | x | - | - | +| USE_BMP | - | - / x | - | x | - | - | +| USE_BME68X | - | - / x | - | x | - | - | +| USE_BH1750 | - | - / x | - | x | - | - | +| USE_VEML6070 | - | - / x | - | x | - | - | +| USE_ADS1115 | - | - / x | - | x | - | - | +| USE_INA219 | - | - / x | - | x | - | - | +| USE_INA226 | - | - / - | - | - | - | - | +| USE_INA3221 | - | - / - | - | - | - | - | +| USE_SHT3X | - | - / x | - | x | - | - | +| USE_TSL2561 | - | - / - | - | - | - | - | +| USE_TSL2591 | - | - / - | - | - | - | - | +| USE_MGS | - | - / x | - | x | - | - | +| USE_SGP30 | - | - / x | - | x | - | - | +| USE_SGP40 | - | - / x | - | x | - | - | +| USE_SGP4X | - | - / x | - | - | - | - | +| USE_SEN5X | - | - / x | - | x | - | - | +| USE_SI1145 | - | - / - | - | - | - | - | +| USE_LM75AD | - | - / x | - | x | - | - | +| USE_APDS9960 | - | - / - | - | - | - | - | +| USE_MCP230xx | - | - / - | - | - | - | - | +| USE_MCP23XXX_DRV | - | - / - | - | - | - | - | +| USE_PCA9632 | - | - / - | - | - | - | - | +| USE_PCA9685 | - | - / - | - | - | - | - | +| USE_PCA9685_V2 | - | - / - | - | - | - | - | +| USE_MPR121 | - | - / - | - | - | - | - | +| USE_CCS811 | - | - / - | - | x | - | - | +| USE_CCS811_V2 | - | - / x | - | - | - | - | +| USE_ENS16x | - | - / - | - | - | - | - | +| USE_ENS210 | - | - / - | - | - | - | - | +| USE_MPU6050 | - | - / - | - | - | - | - | +| USE_DS3231 | - | - / - | - | - | - | - | +| USE_MGC3130 | - | - / - | - | - | - | - | +| USE_MAX44009 | - | - / - | - | - | - | - | +| USE_SCD30 | - | - / x | - | x | - | - | +| USE_SCD40 | - | - / x | - | - | - | - | +| USE_SPS30 | - | - / - | - | - | - | - | +| USE_ADE7880 | - | - / - | - | - | - | - | +| USE_ADE7953 | - | x / x | x | x | - | x | +| USE_VL53L0X | - | - / x | - | x | - | - | +| USE_VL53L1X | - | - / - | - | - | - | - | +| USE_MLX90614 | - | - / - | - | - | - | - | +| USE_CHIRP | - | - / - | - | - | - | - | +| USE_PAJ7620 | - | - / - | - | - | - | - | +| USE_PCF8574 | - | - / - | - | - | - | - | +| USE_PMSA003I | - | - / - | - | - | - | - | +| USE_LOX_O2 | - | - / x | - | x | - | - | +| USE_GDK101 | - | - / - | - | - | - | - | +| USE_TC74 | - | - / - | - | - | - | - | +| USE_PCA9557 | - | - / - | - | - | - | - | +| | | | | | | | +| **Feature or Sensor** | **l** | **t** | **k** | **s** | **i** | **d** | **Remarks** | +| USE_HIH6 | - | - / x | - | x | - | - | +| USE_DHT12 | - | - / x | - | x | - | - | +| USE_DS1624 | - | - / x | - | x | - | - | +| USE_AHT1x | - | - / - | - | - | - | - | +| USE_HDC1080 | - | - / - | - | - | - | - | +| USE_WEMOS_MOTOR_V1 | - | - / x | - | x | - | - | +| USE_IAQ | - | - / x | - | x | - | - | +| USE_AS3935 | - | - / x | - | x | - | - | +| USE_VEML6075 | - | - / - | - | - | - | - | +| USE_VEML7700 | - | - / - | - | - | - | - | +| USE_MCP9808 | - | - / - | - | - | - | - | +| USE_MLX90640 | - | - / - | - | - | - | - | +| USE_HP303B | - | - / - | - | - | - | - | +| USE_EZOCO2 | - | - / - | - | - | - | - | +| USE_EZODO | - | - / - | - | - | - | - | +| USE_EZOEC | - | - / - | - | - | - | - | +| USE_EZOFLO | - | - / - | - | - | - | - | +| USE_EZOHUM | - | - / - | - | - | - | - | +| USE_EZOO2 | - | - / - | - | - | - | - | +| USE_EZOORP | - | - / - | - | - | - | - | +| USE_EZOPH | - | - / - | - | - | - | - | +| USE_EZOPMP | - | - / - | - | - | - | - | +| USE_EZOPRS | - | - / - | - | - | - | - | +| USE_EZORGB | - | - / - | - | - | - | - | +| USE_EZORTD | - | - / - | - | - | - | - | +| USE_SEESAW_SOIL | - | - / - | - | - | - | - | +| USE_TOF10120 | - | - / - | - | - | - | - | +| USE_BM8563 | - | - / - | - | - | - | - | +| USE_AM2320 | - | - / - | - | - | - | - | +| USE_T67XX | - | - / - | - | - | - | - | +| USE_HM330X | - | - / - | - | - | - | - | +| USE_HDC2010 | - | - / - | - | - | - | - | +| USE_PCF85363 | - | - / - | - | - | - | - | +| USE_DS3502 | - | - / - | - | - | - | - | +| USE_HYT | - | - / - | - | - | - | - | +| USE_LUXV30B | - | - / - | - | - | - | - | +| USE_HMC5883L | - | - / - | - | - | - | - | +| USE_QMC5883L | - | - / - | - | - | - | - | +| | | | | | | | +| **Feature or Sensor** | **l** | **t** | **k** | **s** | **i** | **d** | **Remarks** | +| USE_SPI | - | - / - | - | - | - | x | +| USE_RC522 | - | - / - | - | - | - | - | +| USE_CANSNIFFER | - | - / - | - | - | - | - | +| USE_MHZ19 | - | - / x | - | x | - | - | +| USE_SENSEAIR | - | - / x | - | x | - | - | +| USE_PMS5003 | - | - / x | - | x | - | - | +| USE_NOVA_SDS | - | - / x | - | x | - | - | +| USE_HPMA | - | - / x | - | x | - | - | +| USE_SERIAL_BRIDGE | - | x / x | x | x | - | x | +| USE_MODBUS_BRIDGE | - | - / x | - | - | - | - | +| USE_MP3_PLAYER | - | - / x | - | x | - | - | +| USE_AZ7798 | - | - / - | - | - | - | - | +| USE_PN532_HSU | - | - / x | - | x | - | - | +| USE_RDM6300 | - | - / x | - | x | - | - | +| USE_IBEACON | - | - / x | - | x | - | - | +| USE_GPS | - | - / - | - | - | - | - | +| USE_HM10 | - | - / - | - | x | - | - | +| USE_HRXL | - | - / x | - | x | - | - | +| USE_TASMOTA_CLIENT | - | - / - | - | - | - | - | +| USE_OPENTHERM | - | - / - | - | - | - | - | +| USE_MIEL_HVAC | - | - / - | - | - | - | - | +| USE_PROJECTOR_CTRL | - | - / - | - | - | - | - | +| USE_AS608 | - | - / - | - | - | - | - | +| USE_LD2410 | - | - / - | - | - | - | - | +| USE_GM861 | - | - / - | - | - | - | - | +| USE_TCP_BRIDGE | - | - / - | - | - | - | - | zbbridge / zbbrdgpro | +| | | | | | | | +| USE_NRF24 | - | - / - | - | - | - | - | +| USE_MIBLE | - | - / - | - | - | - | - | +| USE_ZIGBEE | - | - / - | - | - | - | - | +| USE_ZIGBEE_ZNP | - | - / - | - | - | - | - | +| USE_ZIGBEE_EZSP | - | - / - | - | - | - | - | Sonoff ZbBridge | +| | | | | | | | +| USE_IR_REMOTE | - | x / - | x | x | x | x | +| USE_IR_RECEIVE | - | x / - | x | x | x | x | +| USE_IR_REMOTE_FULL | - | - / - | - | - | x | - | Enable ALL protocols | +| | | | | | | | +| USE_SR04 | - | - / - | - | x | - | - | +| USE_ME007 | - | - / - | - | - | - | - | +| USE_DYP | - | - / - | - | - | - | - | +| USE_TM1638 | - | - / x | - | x | - | - | +| USE_HX711 | - | - / x | - | x | - | - | +| USE_TX2x_WIND_SENSOR | - | - / - | - | - | - | - | +| USE_WINDMETER | - | - / - | - | - | - | - | +| USE_RC_SWITCH | - | - / x | - | x | - | - | +| USE_RF_SENSOR | - | - / x | - | x | - | - | AlectoV2 only | +| USE_HRE | - | - / x | - | x | - | - | +| USE_A4988_STEPPER | - | - / - | - | - | - | - | +| USE_NEOPOOL | - | - / - | - | - | - | - | +| USE_FLOWRATEMETER | - | - / - | - | - | - | - | +| | | | | | | | +| **Feature or Sensor** | **l** | **t** | **k** | **s** | **i** | **d** | **Remarks** | +| USE_DISPLAY | - | - / - | - | - | - | x | +| USE_DISPLAY_LCD | - | - / - | - | - | - | x | +| USE_DISPLAY_MATRIX | - | - / - | - | - | - | x | +| USE_DISPLAY_EPAPER_29 | - | - / - | - | - | - | x | +| USE_DISPLAY_EPAPER_42 | - | - / - | - | - | - | x | +| USE_DISPLAY_RA8876 | - | - / - | - | - | - | x | +| USE_DISPLAY_TM1637 | - | - / - | - | - | - | x | +| USE_DISPLAY_TM1621_SONOFF | - | - / x | - | - | - | - | +| USE_DISPLAY_TM1650 | - | - / - | - | - | - | - | +| | | | | | | | +| USE_FT5206 | - | - / - | - | - | - | - | +| USE_FTC532 | - | - / - | - | - | - | - | +| USE_BS814A2 | - | - / - | - | - | - | - | +| | | | | | | | +| **ESP32 Feature** | **l** | **t** | **k** | **s** | **i** | **d** | **Remarks** | +| USE_HALLEFFECT | | / x | | | | | +| USE_MI_ESP32 | | / x | | | | | See SetOption115 | +| USE_IBEACON_ESP32 | | / - | | | | | +| USE_WEBCAM | | / - | | | | | +| USE_ETHERNET | | / x | | | | | +| USE_I2S_AUDIO | | / - | | | | | +| USE_TTGO_WATCH | | / - | | | | | +| USE_SONOFF_SPM | | / x | | | | | +| USE_DISPLAY_TM1621_SONOFF | | / x | | | | | +| USE_SHELLY_PRO | | / x | | | | | +| USE_DALI | | / - | | | | | +| USE_DINGTIAN_RELAY | | / - | | | | | +| USE_MATTER_DEVICE | | / x | | | | | See SetOption151 | -* USE_MQTT_TLS is enabled by default in every ESP32 variants +The following specific display drivers are replaced with uDisplay, see [uDisplay/uTouch documentation](https://tasmota.github.io/docs/Universal-Display-Driver/#migrating-to-udisplay): `USE_DISPLAY_ILI9341`, `USE_DISPLAY_SSD1306`, `USE_DISPLAY_SH1106`, `USE_DISPLAY_SSD1351`, `USE_DISPLAY_ST7789` + +- USE_MQTT_TLS is enabled by default in every ESP32 variants diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d4e5225b..ae32c9189 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,202 @@ All notable changes to this project will be documented in this file. ## [13.4.0] 20240214 - Release Quinta +## [13.4.1.2] +### Added +- ESP32 esp32_partition_app3904k_fs3392k partition scheme for 8MB ESP32S3 (#21241) +- TCP Serial bridge GPIO type `TCP Tx En` (#21269) +- Berry `webserver.content_close()` (#21276) +- ESP32 Compile option disabling PSRam check to avoid "blinking" of GPIO 16/17 at startup (#21282) +- HASPmota demo of Renaissance Watch for 480x480 displays (#21290) +- PlatformIO target reset (#21292) +- Support for AHT30 Temperature and Humidity Sensor (#19922) +- Berry wave file recorder (#21315) +- Command ``Publish3`` to send binary data encoded as Hex, disabled in safeboot (21329) +- Support for compile time hostname with `#define WIFI_DEFAULT_HOSTNAME` (#21236) +- Berry `after_teleperiod` event matching `FUNC_AFTER_TELEPERIOD` (#21351) + +### Breaking Changed +- ESP32-C3 OTA binary name from `tasmota32c3cdc.bin` to `tasmota32c3.bin` with USB HWCDC and fallback to serial (#21212) +- ESP32-C6 OTA binary name from `tasmota32c6cdc.bin` to `tasmota32c6.bin` with USB HWCDC and fallback to serial (#21212) +- ESP32-S3 OTA binary name from `tasmota32s3cdc.bin` to `tasmota32s3.bin` with USB HWCDC and fallback to serial (#21212) + +### Changed +- uDisplay fast drawing on RGB displays (#21257) +- HDMI CEC synchronously sends messages (#21270) +- Refactor I2S (#21291) +- Command ``EthType`` option selection (#21317) +- Zigbee startup event triggered after plugins are loaded (#21320) +- Reduced safeboot size by 2.9KB (#21322) +- Internal macro `APP_SLEEP` to `TASMOTA_SLEEP` to specify default sleep in ms (#21324) +- ESP32 Core3 platform update from 2024.04.12 to 2024.05.10 (#21347) +- Refactor Tensorflow (#21327) +- Seriallog set to `SERIAL_LOG_LEVEL` at boot (#21363) +- TLS Letsencrypt replace R3 CA with long-term ISRG_Root_X1 CA, which works with R3 and R10-R14 (#21352) + +### Fixed +- HASPmota `align` attribute and expand PNG cache (#21228) +- LVGL restore `lv_palette` functions (#21232) +- IPv6 support in safeboot (#21233) +- LVGL fix memory allocation of flush buffers (#21256) +- Neopool prevent possible multiple bus requests (#21267) +- Berry `web_add_handler` called before `Webserver` is initialized (#21272) +- Put back wifi IPv6 workaround (#21274) +- Async HMDI CEC (#21287) +- Berry `math.inf`, `math.isinf()` and fixed json ouput for `inf` and `nan` (#21304) +- Compilation of Ethernet when SPI drivers are disabled (#21321) +- Conflicting log_level definitions in NimBLE (#21337) +- Avoid unwanted OTA upgrade when safeboot starts for the first time (#21360) +- Matter broken NOCStruct types preventing pairing with HA (#21365) + +### Removed +- LVGL disabled vector graphics (#21242) +- ESP32 IDF 4.4 based I2S code (#21188) +- Crash recorder from safeboot (#21332) + +## [13.4.1.1] 20240418 +### Added +- HASPmota `dropdown_list` and fixes (#21208) +- Support for SPL06_007 pressure and temperature sensor (#21185) + +### Breaking Changed +- ESP32 Ethernet Phy Type number for DM9051 from 4 to 10 (#21204) + +### Changed +- ESP32 Framework (Arduino Core) from v2.0.15 to v3.0.0 (#21180) +- ESP32 Core3 platform update from 2024.04.11 to 2024.04.12 (#21199) + +### Fixed +- HASPmota dropdown class "options" attribute (#21203) +- ESP8266 physical button/switch control when no rules activated (#21187) + +### Removed +- Support for ESP32 Arduino Core 2 (#21180) +- SSD1351 driver replaced with uDisplay (#21184) +- ST7789 driver replaced with uDisplay (#21184) + +## [13.4.0.4] 20240415 +### Added +- Command ``PowerLock`` to disable power control of selected outputs (#21081) +- Command ``Wifi 6`` to enable 11ax on ESP32 Core3 +- Berry `flash.current_ota` (#21097) + +### Breaking Changed +- Removed dedicated touch drivers in favour of Universal Touch driver (#21146) + +### Changed +- ESP32 refactored Wifi for ESP32 Core3 release (#21106) +- ESP32 Core3 platform update from 2024.02.10 to 2024.04.10 (#21114) +- ESP32 Core3 platform update from 2024.04.10 to 2024.04.11 (#21142) +- SGP4x Domoticz air quality value from raw to computed (#18880) +- ESP32 Framework (Arduino Core) from v2.0.14 to v2.0.15 + +### Fixed +- NeoPool hydrolysis unit for Hidrolife, Bionet and Generic device (#21098) +- M5Core2 LoRa868 module receive exception +- Fade out on CCT bulb with `SO92 1` (#21159) + +### Removed +- Unused `#define MQTT_DATA_STRING` support +- ILI9341 driver replaced with uDisplay (#21169) +- SSD1306 driver replaced with uDisplay (#21176) +- SSD1331 driver replaced with uDisplay (#21177) +- SSH1106 driver replaced with uDisplay (#21183) + +## [13.4.0.3] 20240402 +### Added +- Zigbee support for attributes of type `uint48` used by energy monitoring (#20992) +- Support for single channel EU863-870 LoRaWanBridge (#17790) +- Support Azure iothub direct method (#21013) +- Added GPIO for SPI for Universal Touch Screen (#21025) +- Berry added `close()` to class `serial` (#21042) +- Support for Domoticz non-persistent ``DzIdx5`` to ``DzIdx32`` and disabling DOMOTICZ_OUT_TOPIC subscribe using command ``DzIdx0 0`` (#21019) + +### Breaking Changed +- Berry loading .be file does not generated .bec anymore (#21075) + +### Changed +- ESP32 LVGL library from v9.0.0 to v9.1.0 (#21008) +- berry.exe (pre-compiled for Windows) updated to latest Berry patches (#21024) +- Some `display.ini` to utouch (#21029) +- ESP32 WiFi phy modes 11n and 11ax represented as HT20, HT40 and HE20 (#19350) +- KNX format of energy to match specifications (#21074) + +### Fixed +- BTHome, prep BLE5 (#20989) +- Scripter google char memory leak (#20995) +- HASPmota demo and robotocondensed fonts (#21014) +- Berry walrus bug when assigning to self (#21015) +- Too restrictive checksum checks in Lib_teleinfo (#21033) +- Color swap option for rgb displaytext (#21049) + +### Removed +- Berry `print "a"` syntax no longer supported (#21048) + +## [13.4.0.2] 20240318 +### Added +- Berry `path.rename()` (#20840) +- HASPmota support for spangroup (styled text) (#20852) +- HASPmota support for led (#20857) +- HASPmota improve arc and img (#20894) +- Berry `string.startswith`, `string.endswith` and `%q` format (#20909) +- LVGL `lv.draw_label_dsc` and `lv_bar.get_indic_area` (#20936) +- HASPmota support for scale, percentages (#20974) +- Support for ESP32-S3 120Mhz (#20973) +- Support for MCP23S08 (#20971) + +### Breaking Changed +- Drop support for old (insecure) fingerprint format (#20842) +- LVGL remove embedded typicons font (#20872) +- LVGL remove `textarea` and `spinbox` from binaries (#20916) + +### Changed +- LVGL optimize fonts and add icons (#20880) +- LVGL improved readability of montserrat-10 (#20900) +- HASPmota moved to a distinct library `lv_haspmota` (#20929) +- HASPmota solidify server-side (#20938) +- Refactor Platformio script `post_esp32.py` (#20966) + +### Fixed +- Berry bug when parsing ternary operator (#20839) +- HASPmota widgets line, btnmatrix, qrcode, bar, checkbox (#20881) +- Filesystem save of JSON settings data +- Berry fix walrus with member or index (#20939) +- TuyaV2 suppressed dimmer updates from MQTT (#20950) + +## [13.4.0.1] 20240229 +### Added +- Support for LoRa +- HASPmota `pb.delete` to delete an object (#20735) +- LVGL and HASPmota typicons font (#20742) +- HASPmota more attributes (#20744) +- QMC5883l check for overflow and scale reading (#20643) +- TasMesh support for LWT messages (#20392) +- Show calculated heat index if temperature and humidity is available with ``#define USE_HEAT_INDEX`` (#4771) +- Berry add explicit error log when memory allocation fails (#20807) +- Support for AMS5915/AMS6915 temperature and pressure sensors (#20814) +- IR support data larger than 64 bits (#20831) + +### Changed +- ESP32 Core3 SPI ethernet support for all models +- Berry class `int64` made immutable (#20727) +- LVGL make lv_touch_3_buttons more responsive (#20728) +- ESP32 Core3 platform update from 2024.01.12 to 2024.02.10 (#20730) +- HASPmota fix and improve demo with pixel-perfect fonts (#20734) +- NeoPool webUI pH alarms (4 & 5) completed (#20743) +- Matter reduce memory usage when reading with wildcards (#20809) +- Prevent shutter MQTT broadcast with activated ShutterLock (#20827) + +### Fixed +- ESP32 PWM activity on unconfigured PWM GPIOs (#20732) +- Shutter inverted using internal commands (#20752) +- HASPmota PSRAM memory leak (#20818) +- Berry Memory leak in `import re` (#20823) + +## [Released] + +## [13.4.0] 20240214 +- Release Quinta + ## [13.3.0.5] 20240214 ### Added - Internal support for persistent JSON settings using single file @@ -411,7 +607,7 @@ All notable changes to this project will be documented in this file. - `BrRestart` now supports web handlers to work after Berry restart ### Removed -- Support for ESP32-C3 with chip rev below 3 (old development boards) +- Support for ESP32-C3 with chip revision below 0.3 (old development boards) ## [13.0.0] 20230626 - Release Qasim @@ -934,6 +1130,7 @@ All notable changes to this project will be documented in this file. - DNS lookup for .local domains (#16273) - Button response delay regression from v12.0.2.4 (#16319) - Lost module name in GUI regression from v12.0.2.4 - 20220803 (#16324) +- LVGL fix descriptors Berry mapping ## [12.1.0.1] 20220825 ### Added diff --git a/CODE_OWNERS.md b/CODE_OWNERS.md index f8b14ee9f..98bb523aa 100644 --- a/CODE_OWNERS.md +++ b/CODE_OWNERS.md @@ -84,7 +84,7 @@ In addition to @arendst the following code is mainly owned by: | xdrv_70_1_hdmi_cec | @s-hadinger | xdrv_71_magic_switch | @barbudor | xdrv_72_pipsolar | @chefpro -| xdrv_73 | +| xdrv_73_lora | @arendst | xdrv_74 | | xdrv_75 | | xdrv_76 | @@ -107,6 +107,7 @@ In addition to @arendst the following code is mainly owned by: | | | xdrv_121_gpioviewer | @arendst | xdrv_122_file_settings_demo | @arendst +| xdrv_122_file_json_settings_demo | @arendst | xdrv_127_debug | @arendst | | | Tasmota Sensors | @@ -135,7 +136,7 @@ In addition to @arendst the following code is mainly owned by: | xsns_22_sr04 | Nuno Ferreira, @arendst | xsns_23_me007 | Mathias Buder | xsns_24_si1145 | -| xsns_25 | +| xsns_25_spl06-007_sensor | @rai68 | xsns_26_lm75ad | Andre Thomas | xsns_27_apds9960 | Shawn Hymel | xsns_28 | @@ -224,6 +225,12 @@ In addition to @arendst the following code is mainly owned by: | xsns_108_tc74 | Michael Loftis | xsns_109_sgp4x | Andrew Klaus | xsns_110_max17043 | Vincent de Groot +| xsns_111_ens16x | Christoph Friese +| xsns_112_ens210 | Christoph Friese +| xsns_113_hc8 | Daniel Maier +| xsns_114_amsx915 | Bastian Urschel +| | +| xsns_127_esp32_sensors | @arendst | | | Libraries | | | diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 1a8500954..afd853929 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -13,9 +13,9 @@ Index | Define | Driver | Device | Address(es) | Bus2 | Descrip 2 | USE_PCF8574 | xdrv_28 | PCF8574 | 0x20 - 0x26 | | 8-bit I/O expander (address range overridable) 2 | USE_PCF8574 | xdrv_28 | PCF8574A | 0x39 - 0x3F | | 8-bit I/O expander (address range overridable) 3 | USE_DISPLAY_LCD | xdsp_01 | | 0x27, 0x3F | | LCD display - 4 | USE_DISPLAY_SSD1306 | xdsp_02 | SSD1306 | 0x3C - 0x3D | | Oled display + 4 | REMOVED | | | | | USE_DISPLAY_SSD1306 - REMOVED 5 | USE_DISPLAY_MATRIX | xdsp_03 | HT16K33 | 0x70 - 0x77 | | 8x8 led matrix - 6 | USE_DISPLAY_SH1106 | xdsp_07 | SH1106 | 0x3C - 0x3D | | Oled display + 6 | REMOVED | | SH1106 | 0x3C - 0x3D | | USE_DISPLAY_SH1106 - REMOVED 7 | USE_ADE7953 | xnrg_07 | ADE7953 | 0x38 | | Energy monitor 8 | USE_SHT | xsns_07 | SHT1X | Any | | Temperature and Humidity sensor 9 | USE_HTU | xsns_08 | HTU21 | 0x40 | Yes | Temperature and Humidity sensor @@ -123,5 +123,7 @@ Index | Define | Driver | Device | Address(es) | Bus2 | Descrip 83 | USE_MAX17043 | xsns_110 | MAX17043 | 0x36 | | Fuel-gauge for 3.7 Volt Lipo battery 84 | USE_ENS16x | xsns_111 | ENS16x | 0x52 - 0x53 | | Gas (TVOC, eCO2) and air quality sensor 85 | USE_ENS210 | xsns_112 | ENS210 | 0x43 - 0x44 | | Temperature and humidity sensor - + 86 | USE_AMSX915 | xsns_114 | AMS5915 | 0x28 | | Pressure (absolute/differential) and temperature sensor + 86 | USE_AMSX915 | xsns_114 | AMS6915 | 0x28 | | Pressure (absolute/differential) and temperature sensor + 87 | USE_SPL06_007 | xsns_25 | SPL06-007 | 0x76 | | Pressure and temperature sensor NOTE: Bus2 supported on ESP32 only. diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5ba086e9e..1ffb95f7a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -36,9 +36,9 @@ While fallback or downgrading is common practice it was never supported due to S This release will be supported from ESP8266/Arduino library Core version **2.7.6** due to reported security and stability issues on previous Core version. This will also support gzipped binaries. -This release will be supported from ESP32/Arduino library Core version **2.0.14**. +This release will be supported from ESP32/Arduino library Core version **3.0.0**. -Support of ESP8266 Core versions before 2.7.6 and ESP32 Core versions before 2.0.14 have been removed. +Support of ESP8266 Core versions before 2.7.6 and ESP32 Core versions before 3.0.0 have been removed. ## Support of TLS @@ -71,21 +71,25 @@ The following binary downloads have been compiled with ESP8266/Arduino library c Above binaries are also available as gzipped version allowing faster uploads. Latest released binaries can be downloaded from -- https://github.com/arendst/Tasmota-firmware/tree/main/release-firmware +- https://github.com/arendst/Tasmota-firmware/tree/firmware/release-firmware - http://ota.tasmota.com/tasmota/release Historical binaries can be downloaded from -- http://ota.tasmota.com/tasmota/release-13.4.0 +- http://ota.tasmota.com/tasmota/release-14.0.0 The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota/release/tasmota.bin.gz`` -### ESP32, ESP32-C3, ESP32-S2 and ESP32-S3 based -The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.14**. +### ESP32, ESP32-C2, ESP32-C3, ESP32-C6, ESP32-S2 and ESP32-S3 based +The following binary downloads have been compiled with ESP32/Arduino library core version **3.0.0**. - **tasmota32.bin** = The Tasmota version with most drivers including additional sensors and KNX for 4M+ flash. **RECOMMENDED RELEASE BINARY** -- **tasmota32xy.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-C3/S2/S3 and 4M+ flash. -- **tasmota32xycdc.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-C3/S2/S3 with serial over embedded USB CDC only and 4M+ flash. - **tasmota32solo1.bin** = The Tasmota version with most drivers including additional sensors and KNX for single core ESP32 and 4M+ flash. +- **tasmota32s2.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-S2 with serial and 4M+ flash. +- **tasmota32s2cdc.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-S2 with serial over embedded USB CDC only and 4M+ flash. +- **tasmota32s3.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-S3 with USB HWCDC and fallback to serial and 4M+ flash. +- **tasmota32c2.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-C2 with serial and 4M+ flash. +- **tasmota32c3.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-C2 with USB HWCDC and fallback to serial and 4M+ flash. +- **tasmota32c6.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-C6 with USB HWCDC and fallback to serial and 4M+ flash. - **tasmota32-AD.bin** to **tasmota32-VN.bin** = The Tasmota version in different languages for 4M+ flash. - **tasmota32-bluetooth.bin** = The Bluetooth version adds BLE support for 4M+ flash. - **tasmota32-display.bin** = The Display version without Energy Monitoring but adds display support for 4M+ flash. @@ -95,18 +99,12 @@ The following binary downloads have been compiled with ESP32/Arduino library cor - **tasmota32-webcam.bin** = The Webcam version adds webcam support for 4M+ flash. - **tasmota32-zbbridgepro.bin** - The Sonoff Zigbee Bridge Pro version with CC2652P firmware load support. -### ESP32-C2 and ESP32-C6 based -The following binary downloads have been compiled with ESP32/Arduino library core version **3.0.0-alpha3**. - -- **tasmota32c2-arduino30.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-C2 and 4M+ flash. -- **tasmota32c6cdc-arduino30.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-C6 with serial over embedded USB CDC or hardware USB and 4M+ flash. - Latest released binaries can be downloaded from -- https://github.com/arendst/Tasmota-firmware/tree/main/release-firmware +- https://github.com/arendst/Tasmota-firmware/tree/firmware/release-firmware - https://ota.tasmota.com/tasmota32/release Historical binaries can be downloaded from -- https://ota.tasmota.com/tasmota32/release-13.4.0 +- https://ota.tasmota.com/tasmota32/release-14.0.0 The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasmota.com/tasmota32/release/tasmota32.bin`` @@ -116,100 +114,131 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v13.4.0 Quinta +## Changelog v14.0.0 Rodney ### Added -- Command ``TimedPower [,ON|OFF|TOGGLE|BLINK]`` executes ``Power [ON|OFF|TOGGLE|BLINK] `` and after executes ``Power [OFF|ON|TOGGLE|OFF]`` -- Command ``SetOption158 1`` to disable publish of ModbusReceived MQTT messages [#20678](https://github.com/arendst/Tasmota/issues/20678) -- Command ``SetOption159 1`` to enable counting on both rising and falling edge [#20712](https://github.com/arendst/Tasmota/issues/20712) -- Display of active drivers using command ``status 4`` -- GPIO Viewer to see realtime GPIO states using assets from `https://ota.tasmota.com/tasmota/gpioviewer/gpio_viewer_13_4_0/` v2.0.8 -- Support for CST816S touch interface [#20213](https://github.com/arendst/Tasmota/issues/20213) -- Support for Sonoff Basic R4 Magic Switch [#20247](https://github.com/arendst/Tasmota/issues/20247) -- Support negative power on BL0942 using index 5..8 [#20322](https://github.com/arendst/Tasmota/issues/20322) -- Support for pipsolar inverter [#20408](https://github.com/arendst/Tasmota/issues/20408) -- Support for HardwareSerial invert [#15461](https://github.com/arendst/Tasmota/issues/15461) -- NeoPool hydrolysis FL1 and Redox flag [#20258](https://github.com/arendst/Tasmota/issues/20258) -- SML support for IM350 [#20474](https://github.com/arendst/Tasmota/issues/20474) -- GUI sensor separators [#20495](https://github.com/arendst/Tasmota/issues/20495) -- ESP32 used UART information -- ESP32 support GPIOViewer when ``define USE_ESP32_GPIO_VIEWER`` is enabled -- ESP32 MI BLE support for Xiaomi LYWSD02MMC [#20381](https://github.com/arendst/Tasmota/issues/20381) -- ESP32 support for Shelly Plus Add-On using DS18x20 or DHT11/AM2301/DHT21/DHT22/AM2302/AM2321/SI7021 on GPIO0/1 [#20580](https://github.com/arendst/Tasmota/issues/20580) -- ESP32 MI32 Legacy initial support for sensors using BTHOME packet format [#20625](https://github.com/arendst/Tasmota/issues/20625) -- ESP32 Core3 support for SPI ethernet on DM9051, W5500 and KSZ8851 -- ESP32-C3 support for GPIO11 [#18350](https://github.com/arendst/Tasmota/issues/18350) -- Berry GPIO viewer initial version using async webserver [#20416](https://github.com/arendst/Tasmota/issues/20416) -- Berry `introspect.set()` for class attributes [#20339](https://github.com/arendst/Tasmota/issues/20339) -- Berry support for `tcpclientasync` in `tcpserver` [#20401](https://github.com/arendst/Tasmota/issues/20401) -- Berry `tasmota.urlbecload(url:string) -> bool` [#20412](https://github.com/arendst/Tasmota/issues/20412) -- Berry `gpio.read_pwm` and `gpio.read_pwm_resolution` [#20414](https://github.com/arendst/Tasmota/issues/20414) -- Berry `gpio.get_pin_type` and `gpio.ger_pin_type_index` [#20415](https://github.com/arendst/Tasmota/issues/20415) -- Berry `string` to `bytes()` [#20420](https://github.com/arendst/Tasmota/issues/20420) -- Berry button to dynamically load GPIO Viewer with Berry backend [#20424](https://github.com/arendst/Tasmota/issues/20424) -- Berry `debug_panel.tapp` to display real-time heap and wifi rssi [#20436](https://github.com/arendst/Tasmota/issues/20436) -- Berry `webserver.header` to read browser sent headers [#20447](https://github.com/arendst/Tasmota/issues/20447) -- Berry provide lightweight options for `tasmota.wifi/eth/memory/rtc` [#20448](https://github.com/arendst/Tasmota/issues/20448) -- Berry `tasmota.webcolor` [#20454](https://github.com/arendst/Tasmota/issues/20454) -- Berry `debug.caller` [#20470](https://github.com/arendst/Tasmota/issues/20470) -- Berry solidification of strings longer than 255 bytes [#20529](https://github.com/arendst/Tasmota/issues/20529) -- Berry syntax coloring for Notepad++ by FransO [#20541](https://github.com/arendst/Tasmota/issues/20541) -- Berry/Zigbee web hook per device for customized status display [#20542](https://github.com/arendst/Tasmota/issues/20542) -- Berry `introspect.contains` and `bytes.addfloat` [#20635](https://github.com/arendst/Tasmota/issues/20635) -- Zigbee ``ZbEmulation`` to selectively exclude some devices from Hue/Alexa emulation [#20552](https://github.com/arendst/Tasmota/issues/20552) -- LVGL `lv.str_arr` [#20480](https://github.com/arendst/Tasmota/issues/20480) -- LVGL option to add `lv.keyboard` extra widget [#20496](https://github.com/arendst/Tasmota/issues/20496) -- HASPmota `haspmota.page_show()` to change page [#20333](https://github.com/arendst/Tasmota/issues/20333) -- HASPmota type `chart` [#20372](https://github.com/arendst/Tasmota/issues/20372) -- HASPmota support for `min` and `max` attribute in `slider` [#20582](https://github.com/arendst/Tasmota/issues/20582) -- Matter support for password for remote Tasmota devices [#20296](https://github.com/arendst/Tasmota/issues/20296) -- Matter add human readable names for TimeSync cluster [#20666](https://github.com/arendst/Tasmota/issues/20666) +- PlatformIO target reset [#21292](https://github.com/arendst/Tasmota/issues/21292) +- Command ``Wifi 6`` to enable 11ax on ESP32 +- Command ``PowerLock`` to disable power control of selected outputs [#21081](https://github.com/arendst/Tasmota/issues/21081) +- Command ``Publish3`` to send binary data encoded as Hex, disabled in safeboot [#21329](https://github.com/arendst/Tasmota/issues/21329) +- Support for calculated heat index if temperature and humidity is available with ``#define USE_HEAT_INDEX`` [#4771](https://github.com/arendst/Tasmota/issues/4771) +- Support for LoRa and single channel EU863-870 LoRaWanBridge [#17790](https://github.com/arendst/Tasmota/issues/17790) +- Support for AMS5915/AMS6915 temperature and pressure sensors [#20814](https://github.com/arendst/Tasmota/issues/20814) +- Support for LWT messages in TasMesh [#20392](https://github.com/arendst/Tasmota/issues/20392) +- Support IR data larger than 64 bits [#20831](https://github.com/arendst/Tasmota/issues/20831) +- Support for MCP23S08 [#20971](https://github.com/arendst/Tasmota/issues/20971) +- Support for ESP32-S3 120Mhz [#20973](https://github.com/arendst/Tasmota/issues/20973) +- Support Azure iothub direct method [#21013](https://github.com/arendst/Tasmota/issues/21013) +- Support for Domoticz non-persistent ``DzIdx5`` to ``DzIdx32`` and disabling DOMOTICZ_OUT_TOPIC subscribe using command ``DzIdx0 0`` [#21019](https://github.com/arendst/Tasmota/issues/21019) +- Support SPI GPIO configuration for Universal Touch Screen [#21025](https://github.com/arendst/Tasmota/issues/21025) +- Support for SPL06_007 pressure and temperature sensor [#21185](https://github.com/arendst/Tasmota/issues/21185) +- Support for AHT30 Temperature and Humidity Sensor [#19922](https://github.com/arendst/Tasmota/issues/19922) +- Support for compile time hostname with `#define WIFI_DEFAULT_HOSTNAME` (#21236)[#21236](https://github.com/arendst/Tasmota/issues/21236) +- Zigbee support for attributes of type `uint48` used by energy monitoring [#20992](https://github.com/arendst/Tasmota/issues/20992) +- QMC5883l check for overflow and scale reading [#20643](https://github.com/arendst/Tasmota/issues/20643) +- TCP Serial bridge GPIO type `TCP Tx En` [#21269](https://github.com/arendst/Tasmota/issues/21269) +- ESP32 esp32_partition_app3904k_fs3392k partition scheme for 8MB ESP32S3 [#21241](https://github.com/arendst/Tasmota/issues/21241) +- ESP32 Compile option disabling PSRam check to avoid "blinking" of GPIO 16/17 at startup [#21282](https://github.com/arendst/Tasmota/issues/21282) +- Berry explicit error log when memory allocation fails [#20807](https://github.com/arendst/Tasmota/issues/20807) +- Berry `path.rename()` [#20840](https://github.com/arendst/Tasmota/issues/20840) +- Berry `string.startswith`, `string.endswith` and `%q` format [#20909](https://github.com/arendst/Tasmota/issues/20909) +- Berry `close()` to class `serial` [#21042](https://github.com/arendst/Tasmota/issues/21042) +- Berry `flash.current_ota` [#21097](https://github.com/arendst/Tasmota/issues/21097) +- Berry `webserver.content_close()` [#21276](https://github.com/arendst/Tasmota/issues/21276) +- Berry wave file recorder [#21315](https://github.com/arendst/Tasmota/issues/21315) +- Berry `after_teleperiod` event matching `FUNC_AFTER_TELEPERIOD` [#21351](https://github.com/arendst/Tasmota/issues/21351) +- LVGL and HASPmota typicons font [#20742](https://github.com/arendst/Tasmota/issues/20742) +- LVGL `lv.draw_label_dsc` and `lv_bar.get_indic_area` [#20936](https://github.com/arendst/Tasmota/issues/20936) +- HASPmota `pb.delete` to delete an object [#20735](https://github.com/arendst/Tasmota/issues/20735) +- HASPmota improve arc and img [#20894](https://github.com/arendst/Tasmota/issues/20894) +- HASPmota support for scale, percentages [#20974](https://github.com/arendst/Tasmota/issues/20974) +- HASPmota `dropdown_list` and fixes [#21208](https://github.com/arendst/Tasmota/issues/21208) +- HASPmota demo of Renaissance Watch for 480x480 displays [#21290](https://github.com/arendst/Tasmota/issues/21290) ### Breaking Changed -- ESP32 LVGL library from v8.3.11 to v9.0.0, some small breaking changes in C, none in HASPmota [#20659](https://github.com/arendst/Tasmota/issues/20659) -- Refactoring of Berry `animate` module for WS2812 Leds [#20236](https://github.com/arendst/Tasmota/issues/20236) -- Matter aggregator relocated to endpoint 1 for Google compatibility, may break existing associations [#20654](https://github.com/arendst/Tasmota/issues/20654) +- Drop support for old (insecure) fingerprint format [#20842](https://github.com/arendst/Tasmota/issues/20842) +- Removed dedicated touch drivers in favour of Universal Touch driver [#21146](https://github.com/arendst/Tasmota/issues/21146) +- ESP32-C3 OTA binary name from `tasmota32c3cdc.bin` to `tasmota32c3.bin` with USB HWCDC and fallback to serial [#21212](https://github.com/arendst/Tasmota/issues/21212) +- ESP32-C6 OTA binary name from `tasmota32c6cdc.bin` to `tasmota32c6.bin` with USB HWCDC and fallback to serial [#21212](https://github.com/arendst/Tasmota/issues/21212) +- ESP32-S3 OTA binary name from `tasmota32s3cdc.bin` to `tasmota32s3.bin` with USB HWCDC and fallback to serial [#21212](https://github.com/arendst/Tasmota/issues/21212) +- Berry loading .be file does not generated .bec anymore [#21075](https://github.com/arendst/Tasmota/issues/21075) +- LVGL remove embedded typicons font [#20872](https://github.com/arendst/Tasmota/issues/20872) +- LVGL remove `textarea` and `spinbox` from binaries [#20916](https://github.com/arendst/Tasmota/issues/20916) ### Changed -- ESP8266 platform update from 2023.04.00 to 2024.01.01 [#20539](https://github.com/arendst/Tasmota/issues/20539) -- ESP8266 Framework (Arduino Core) from v2.7.4.9 to v2.7.6 [#20539](https://github.com/arendst/Tasmota/issues/20539) -- ESP32 Core2 platform update from 2023.11.01 to 2024.01.01 [#20473](https://github.com/arendst/Tasmota/issues/20473) -- ESP32 Core3 platform update from 2024.01.11 to 2024.01.12 [#20576](https://github.com/arendst/Tasmota/issues/20576) -- Library OneWire-Stickbreaker by TasmotaOneWire supporting Shelly Plus Add-On [#20580](https://github.com/arendst/Tasmota/issues/20580) -- Renamed button "Consoles" to "Tools" -- Refactored rule ``Subscribe`` using LList allowing full message size and enabled by default -- Refactored rules USE_EXPRESSION and SUPPORT_IF_STATEMENT replacing LinkedList with arrays and enabled by default -- Support syslog updates every sleep or every second if `#define SYSLOG_UPDATE_SECOND` [#20260](https://github.com/arendst/Tasmota/issues/20260) -- Web file upload response on upload error [#20340](https://github.com/arendst/Tasmota/issues/20340) -- Header `Host` is now collected by Webserver [#20446](https://github.com/arendst/Tasmota/issues/20446) -- Utouch optimizations, rgb i2c init [#20596](https://github.com/arendst/Tasmota/issues/20596) -- Miel HVAC lower the minimum temperature to 10C [#20628](https://github.com/arendst/Tasmota/issues/20628) -- Webcam tweaks [#20451](https://github.com/arendst/Tasmota/issues/20451) -- IP stack compatible with new Core3 IPv6 implementation [#20509](https://github.com/arendst/Tasmota/issues/20509) -- Refactored Pio filesystem download script [#20544](https://github.com/arendst/Tasmota/issues/20544) -- Matter improve `MtrInfo` [#20686](https://github.com/arendst/Tasmota/issues/20686) -- Matter redirects for Advanced Matter configuration UI [#20690](https://github.com/arendst/Tasmota/issues/20690) -- Matter implement auto-attributes [#20694](https://github.com/arendst/Tasmota/issues/20694) +- ESP32 Framework (Arduino Core) from v2.0.14 to v3.0.0 +- ESP32 platform update from 2024.01.12 to 2024.05.01 [#21347](https://github.com/arendst/Tasmota/issues/21347) +- ESP32 LVGL library from v9.0.0 to v9.1.0 [#21008](https://github.com/arendst/Tasmota/issues/21008) +- Seriallog set to `SERIAL_LOG_LEVEL` at boot [#21363](https://github.com/arendst/Tasmota/issues/21363) +- TLS Letsencrypt replace R3 CA with long-term ISRG_Root_X1 CA, which works with R3 and R10-R14 [#21352](https://github.com/arendst/Tasmota/issues/21352) +- Command ``EthType`` option selection [#21317](https://github.com/arendst/Tasmota/issues/21317) +- Refactor Platformio script `post_esp32.py` [#20966](https://github.com/arendst/Tasmota/issues/20966) +- SGP4x Domoticz air quality value from raw to computed [#18880](https://github.com/arendst/Tasmota/issues/18880) +- NeoPool webUI pH alarms (4 & 5) completed [#20743](https://github.com/arendst/Tasmota/issues/20743) +- Prevent shutter MQTT broadcast with activated ShutterLock [#20827](https://github.com/arendst/Tasmota/issues/20827) +- Some `display.ini` to utouch [#21029](https://github.com/arendst/Tasmota/issues/21029) +- KNX format of energy to match specifications [#21074](https://github.com/arendst/Tasmota/issues/21074) +- Internal macro `APP_SLEEP` to `TASMOTA_SLEEP` to specify default sleep in ms [#21324](https://github.com/arendst/Tasmota/issues/21324) +- uDisplay fast drawing on RGB displays [#21257](https://github.com/arendst/Tasmota/issues/21257) +- HDMI CEC synchronously sends messages [#21270](https://github.com/arendst/Tasmota/issues/21270) +- Refactor I2S [#21291](https://github.com/arendst/Tasmota/issues/21291) +- Zigbee startup event triggered after plugins are loaded [#21320](https://github.com/arendst/Tasmota/issues/21320) +- Refactor Tensorflow [#21327](https://github.com/arendst/Tasmota/issues/21327) +- ESP32 refactored Wifi for ESP32 Core3 release [#21106](https://github.com/arendst/Tasmota/issues/21106) +- ESP32 WiFi phy modes 11n and 11ax represented as HT20, HT40 and HE20 [#19350](https://github.com/arendst/Tasmota/issues/19350) +- berry.exe (pre-compiled for Windows) updated to latest Berry patches [#21024](https://github.com/arendst/Tasmota/issues/21024) +- Berry class `int64` made immutable [#20727](https://github.com/arendst/Tasmota/issues/20727) +- Matter reduce memory usage when reading with wildcards [#20809](https://github.com/arendst/Tasmota/issues/20809) +- LVGL make lv_touch_3_buttons more responsive [#20728](https://github.com/arendst/Tasmota/issues/20728) +- LVGL optimize fonts and add icons [#20880](https://github.com/arendst/Tasmota/issues/20880) +- LVGL improved readability of montserrat-10 [#20900](https://github.com/arendst/Tasmota/issues/20900) +- HASPmota fix and improve demo with pixel-perfect fonts [#20734](https://github.com/arendst/Tasmota/issues/20734) +- HASPmota more attributes [#20744](https://github.com/arendst/Tasmota/issues/20744) +- HASPmota support for spangroup (styled text) [#20852](https://github.com/arendst/Tasmota/issues/20852) +- HASPmota support for led [#20857](https://github.com/arendst/Tasmota/issues/20857) +- HASPmota moved to a distinct library `lv_haspmota` [#20929](https://github.com/arendst/Tasmota/issues/20929) +- HASPmota solidify server-side [#20938](https://github.com/arendst/Tasmota/issues/20938) ### Fixed -- CVE-2021-36603 Cross Site Scripting (XSS) vulnerability [#12221](https://github.com/arendst/Tasmota/issues/12221) -- Syslog server warning caused by lack of field and hostname starting with 'z' [#14689](https://github.com/arendst/Tasmota/issues/14689) -- Support for Domoticz floor/room topics. Regression from v12.0.1 [#20299](https://github.com/arendst/Tasmota/issues/20299) -- Scripter memory leak in `>w x` [#20473](https://github.com/arendst/Tasmota/issues/20473) -- Zigbee ramdom crash in main page [#20481](https://github.com/arendst/Tasmota/issues/20481) -- ESP8266 IPv6 support [#20539](https://github.com/arendst/Tasmota/issues/20539) -- ESP32 piezo ceramic buzzer doesn't buzz [#20118](https://github.com/arendst/Tasmota/issues/20118) -- ESP32 shutter exception 6 (divide by zero) on ``ShutterMode 4`` [#20524](https://github.com/arendst/Tasmota/issues/20524) -- ESP32 Zigbee Aqara attributes [#20452](https://github.com/arendst/Tasmota/issues/20452) -- ESP32 Audio for Core3, MP3Stream and Shine [#20540](https://github.com/arendst/Tasmota/issues/20540) -- ESP32 Core3 reset GPIOs 16/17 when PSRAM is not used [#20547](https://github.com/arendst/Tasmota/issues/20547) -- LVGL fix type for lv_imgbtn [#20354](https://github.com/arendst/Tasmota/issues/20354) -- Berry claiming UART0 if needed [#20324](https://github.com/arendst/Tasmota/issues/20324) -- Berry assigment to list with negative index [#20537](https://github.com/arendst/Tasmota/issues/20537) -- Berry C mapping, raise an error if too many arguments are sent [#20604](https://github.com/arendst/Tasmota/issues/20604) -- Matter Contact sensor was not triggering any update [#20232](https://github.com/arendst/Tasmota/issues/20232) -- Matter support for Alexa [#20545](https://github.com/arendst/Tasmota/issues/20545) -- Matter error when removing device from Google Home [#20665](https://github.com/arendst/Tasmota/issues/20665) -- Matter exception when fabrics is not initialized [#20667](https://github.com/arendst/Tasmota/issues/20667) +- Filesystem save of JSON settings data +- Fade out on CCT bulb with `SO92 1` [#21159](https://github.com/arendst/Tasmota/issues/21159) +- Shutter inverted using internal commands [#20752](https://github.com/arendst/Tasmota/issues/20752) +- TuyaV2 suppressed dimmer updates from MQTT [#20950](https://github.com/arendst/Tasmota/issues/20950) +- Scripter google char memory leak [#20995](https://github.com/arendst/Tasmota/issues/20995) +- Too restrictive checksum checks in Lib_teleinfo [#21033](https://github.com/arendst/Tasmota/issues/21033) +- Color swap option for rgb displaytext [#21049](https://github.com/arendst/Tasmota/issues/21049) +- NeoPool hydrolysis unit for Hidrolife, Bionet and Generic device [#21098](https://github.com/arendst/Tasmota/issues/21098) +- Neopool prevent possible multiple bus requests [#21267](https://github.com/arendst/Tasmota/issues/21267) +- Async HMDI CEC [#21287](https://github.com/arendst/Tasmota/issues/21287) +- ESP8266 physical button/switch control when no rules activated [#21187](https://github.com/arendst/Tasmota/issues/21187) +- ESP32 PWM activity on unconfigured PWM GPIOs [#20732](https://github.com/arendst/Tasmota/issues/20732) +- Avoid unwanted OTA upgrade when safeboot starts for the first time [#21360](https://github.com/arendst/Tasmota/issues/21360) +- BTHome, prep BLE5 [#20989](https://github.com/arendst/Tasmota/issues/20989) +- Conflicting log_level definitions in NimBLE [#21337](https://github.com/arendst/Tasmota/issues/21337) +- Berry Memory leak in `import re` [#20823](https://github.com/arendst/Tasmota/issues/20823) +- Berry bug when parsing ternary operator [#20839](https://github.com/arendst/Tasmota/issues/20839) +- Berry walrus with member or index [#20939](https://github.com/arendst/Tasmota/issues/20939) +- Berry walrus bug when assigning to self [#21015](https://github.com/arendst/Tasmota/issues/21015) +- Berry `web_add_handler` called before `Webserver` is initialized [#21272](https://github.com/arendst/Tasmota/issues/21272) +- Berry `math.inf`, `math.isinf()` and fixed json ouput for `inf` and `nan` [#21304](https://github.com/arendst/Tasmota/issues/21304) +- Matter broken NOCStruct types preventing pairing with HA [#21365](https://github.com/arendst/Tasmota/issues/21365) +- LVGL restore `lv_palette` functions [#21232](https://github.com/arendst/Tasmota/issues/21232) +- LVGL fix memory allocation of flush buffers [#21256](https://github.com/arendst/Tasmota/issues/21256) +- HASPmota PSRAM memory leak [#20818](https://github.com/arendst/Tasmota/issues/20818) +- HASPmota widgets line, btnmatrix, qrcode, bar, checkbox [#20881](https://github.com/arendst/Tasmota/issues/20881) +- HASPmota demo and robotocondensed fonts [#21014](https://github.com/arendst/Tasmota/issues/21014) +- HASPmota dropdown class "options" attribute [#21203](https://github.com/arendst/Tasmota/issues/21203) +- HASPmota `align` attribute and expand PNG cache [#21228](https://github.com/arendst/Tasmota/issues/21228) ### Removed -- Max number of 30 backlog entries +- Support for ESP32 Arduino Core 2 [#21180](https://github.com/arendst/Tasmota/issues/21180) +- Unused `#define MQTT_DATA_STRING` support +- ILI9341 driver replaced with uDisplay [#21169](https://github.com/arendst/Tasmota/issues/21169) +- SSD1306 driver replaced with uDisplay [#21176](https://github.com/arendst/Tasmota/issues/21176) +- SSD1331 driver replaced with uDisplay [#21177](https://github.com/arendst/Tasmota/issues/21177) +- SSH1106 driver replaced with uDisplay [#21183](https://github.com/arendst/Tasmota/issues/21183) +- SSD1351 driver replaced with uDisplay [#21184](https://github.com/arendst/Tasmota/issues/21184) +- ST7789 driver replaced with uDisplay [#21184](https://github.com/arendst/Tasmota/issues/21184) +- ESP32 IDF 4.4 based I2S code [#21188](https://github.com/arendst/Tasmota/issues/21188) +- Crash recorder from safeboot [#21332](https://github.com/arendst/Tasmota/issues/21332) +- Berry `print "a"` syntax no longer supported [#21048](https://github.com/arendst/Tasmota/issues/21048) +- LVGL disabled vector graphics [#21242](https://github.com/arendst/Tasmota/issues/21242) diff --git a/TEMPLATES.md b/TEMPLATES.md index 082dbaea7..eb9331e32 100644 --- a/TEMPLATES.md +++ b/TEMPLATES.md @@ -5,7 +5,7 @@ # Templates -Find below the available templates as of February 2024. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates) +Find below the available templates as of May 2024. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates) ## Adapter Board ``` @@ -281,7 +281,7 @@ TOMZN 1P 63A Circuit Breaker {"NAME":"TOB8-63WiFi","GPIO":[32,0,0,3104,0,0,0,0, TOMZN 2P 63A/80A Circuit Breaker {"NAME":"TOWBC-2P-T","GPIO":[0,0,0,0,0,0,0,0,64,224,0,0,288,0],"FLAG":0,"BASE":18} TOMZN 4P 80A Circuit Breaker {"NAME":"TOWBC-4P-T","GPIO":[288,0,0,0,0,0,0,0,32,224,0,0,0,0],"FLAG":0,"BASE":18} TOMZN 4P 80A Circuit Breaker {"NAME":"TOMZN4","GPIO":[32,0,0,0,0,0,0,0,224,288,0,0,0,0],"FLAG":0,"BASE":18} -Tongou 2P 63A Circuit Breaker {"NAME":"RCD_CONTACTOR","GPIO":[32,224,0,0,0,0,0,0,288,544,0,0,0,0],"FLAG":0,"BASE":18} +Tongou 2P 63A Circuit Breaker {"NAME":"RCD_CONTACTOR","GPIO":[32,224,0,3104,0,0,0,0,288,544,0,0,0,0],"FLAG":0,"BASE":18} ``` ## Dehumidifier @@ -622,7 +622,7 @@ Antsig Universal Remote Controller {"NAME":"Antsig Smart Wi-Fi IR","GPIO":[1,1, Athom {"NAME":"Athom_IR_Remote","GPIO":[32,0,0,0,1056,1088,0,0,0,576,0,0,0,0],"FLAG":0,"BASE":18} Automate Things IR Bridge {"NAME":"AT-IRBR-1.0","GPIO":[0,0,0,0,1056,1088,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"Module 0"} Automate Things IR Bridge {"NAME":"AT-IRBR-1.4","GPIO":[1088,0,0,0,1056,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"Module 0"} -auvisio S06 {"NAME":"NX-4519-675","GPIO":[0,0,0,0,288,1088,0,0,0,0,1056,0,0,0],"FLAG":0,"BASE":18} +auvisio S06 {"NAME":"NX-4519-675","GPIO":[0,0,0,0,288,1088,0,0,0,32,1056,0,0,0],"FLAG":0,"BASE":18} Avatto Temperature and Humidity Sensor and {"NAME":"S08Pro","GPIO":[0,640,0,608,288,1088,0,0,0,32,1056,0,0,0],"FLAG":0,"BASE":18} BlitzWolf BW-RC1 {"NAME":"BW-RC1","GPIO":[0,0,0,0,320,1088,0,0,0,32,1056,0,0,0],"FLAG":0,"BASE":62} Connect SmartHome Universal Remote {"NAME":"CSH IR Controller","GPIO":[1,1,1,1,320,1088,0,0,0,32,1056,0,0,0],"FLAG":0,"BASE":62} @@ -1250,7 +1250,7 @@ Geeni Spot {"NAME":"Geeni Spot","GPIO":[576,0,0,0,320,0,0,0,0, Geeni Spot Glo {"NAME":"Geeni Glo","GPIO":[0,0,0,0,320,0,0,0,224,32,225,0,0,0],"FLAG":0,"BASE":18} Geeni SWITCH {"NAME":"Geeni Switch","GPIO":[0,0,0,0,288,321,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Geeni Switch Duo {"NAME":"Geeni Duo","GPIO":[0,0,0,0,33,225,0,0,32,288,224,0,289,0],"FLAG":0,"BASE":18} -GHome EP2-A {"NAME":"GHome EP2-A","GPIO":[320,0,576,0,2656,2720,0,0,2624,32,0,224,0,0],"FLAG":0,"BASE":45} +GHome EP2-A {"NAME":"GHome EP2-A","GPIO":[576,0,320,0,2656,2720,0,0,2624,32,0,224,0,0],"FLAG":0,"BASE":45} Girier 16A {"NAME":"Girier - JR-PM01","GPIO":[0,544,0,2624,2720,2656,0,0,224,32,320,0,0,0],"FLAG":0,"BASE":68} Globe 15A {"NAME":"Globe 50329","GPIO":[0,0,0,0,320,0,0,0,224,0,32,0,0,0],"FLAG":0,"BASE":18} Globe 2 Outlet {"NAME":"Globe 50020","GPIO":[0,576,0,321,33,32,0,0,224,320,225,0,0,0],"FLAG":0,"BASE":18} @@ -1624,7 +1624,7 @@ Vettora Smart Plug {"NAME":"Vettora","GPIO":[0,0,0,32,0,0,0,0,0,320,22 Vingo {"NAME":"Karpal-01","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Vivanco 39625 Smart Home Power Adapter {"NAME":"Vivianco","GPIO":[0,0,0,32,2688,2656,0,0,2624,288,224,0,0,0],"FLAG":0,"BASE":18} Vivitar {"NAME":"Vivitar HA1003","GPIO":[576,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} -Vivitar {"NAME":"Vivitar HA1004","GPIO":[576,0,0,0,0,320,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":18} +Vivitar {"NAME":"Vivitar HA-1004","GPIO":[320,0,321,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} Vivitar HA-1006 {"NAME":"HA-1006","GPIO":[0,0,0,0,320,0,0,0,224,64,0,0,0,0],"FLAG":0,"BASE":18} Vivitar HA-1006-AU {"NAME":"HA-1006-AU","GPIO":[0,0,0,0,320,0,0,0,224,64,0,0,0,0],"FLAG":0,"BASE":18} Vivitar Plug {"NAME":"HA-1005N-AU","GPIO":[0,0,0,0,544,0,0,0,224,64,0,0,0,0],"FLAG":0,"BASE":18} @@ -2693,7 +2693,6 @@ TreatLife 3-Way {"NAME":"Treatlife 3-Way","GPIO":[0,0,0,0,224,576,0 TreatLife Single Pole ON/OFF {"NAME":"Treatlife SS02","GPIO":[0,0,0,0,288,576,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Tuya 20A {"NAME":"DS-161","GPIO":[544,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":1} Tuya 3 Gang {"NAME":"KING-Tuya-key","GPIO":[0,0,0,0,226,225,0,0,224,32,34,0,33,0],"FLAG":0,"BASE":18} -Tuya 4 Gang {"NAME":"Tuya 4 Gang Switch","GPIO":[1,34,224,32,33,0,0,0,225,576,0,0,0,0,0,0,0,0,226,227,35,1],"FLAG":0,"BASE":1} Tuya T1 2 Gang No Neutral {"NAME":"Tuya T1 Wifi 2 Gang No Neutral Switch","GPIO":[32,0,0,0,0,225,33,0,224,544,0,0,0,0],"FLAG":0,"BASE":18} Tuya T1 3 Gang No Neutral {"NAME":"Tuya T1 Wifi 3 Gang No Neutral Switch","GPIO":[32,0,0,0,226,225,33,34,224,544,0,0,0,0],"FLAG":0,"BASE":18} TY-US-L1-W {"NAME":"TY-US-L1-W","GPIO":[0,0,0,0,0,32,0,0,0,224,0,0,576,0],"FLAG":0,"BASE":18} diff --git a/boards/esp32-fix.json b/boards/esp32-fix.json index 73cf149fa..96b3828b3 100644 --- a/boards/esp32-fix.json +++ b/boards/esp32-fix.json @@ -1,10 +1,7 @@ { "build": { - "arduino":{ - "ldscript": "esp32_out.ld" - }, "core": "esp32", - "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DHAS_PSRAM_FIX -mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-strategy=memw -DESP32_4M", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DHAS_PSRAM_FIX -mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-strategy=memw -DESP32_4M", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "dio", @@ -22,8 +19,7 @@ "openocd_target": "esp32.cfg" }, "frameworks": [ - "arduino", - "espidf" + "arduino" ], "name": "Espressif Generic ESP32 >= 4M Flash, PSRAM with fix, Tasmota 2880k Code/OTA, 320k FS", "upload": { diff --git a/boards/esp32.json b/boards/esp32.json index 10c117cd7..de9159e94 100644 --- a/boards/esp32.json +++ b/boards/esp32.json @@ -1,10 +1,7 @@ { "build": { - "arduino":{ - "ldscript": "esp32_out.ld" - }, "core": "esp32", - "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DESP32_4M", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DESP32_4M", "f_cpu": "160000000L", "f_flash": "40000000L", "flash_mode": "dio", @@ -22,8 +19,7 @@ "openocd_target": "esp32.cfg" }, "frameworks": [ - "arduino", - "espidf" + "arduino" ], "name": "Espressif Generic ESP32 >= 4M Flash PSRAM, Tasmota 2880k Code/OTA, 320k FS", "upload": { diff --git a/boards/esp32_solo1.json b/boards/esp32_solo1.json index b80a58156..ec76a0504 100644 --- a/boards/esp32_solo1.json +++ b/boards/esp32_solo1.json @@ -1,10 +1,7 @@ { "build": { - "arduino":{ - "ldscript": "esp32_out.ld" - }, "core": "esp32", - "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DESP32_4M -DCORE32SOLO1", + "extra_flags": "-DARDUINO_TASMOTA -DESP32_4M -DCORE32SOLO1", "f_cpu": "240000000L", "f_flash": "40000000L", "flash_mode": "dio", @@ -22,10 +19,9 @@ "openocd_target": "esp32-solo-1.cfg" }, "frameworks": [ - "arduino", - "espidf" + "arduino" ], - "name": "Espressif Generic ESP32 >= 4M Flash, Tasmota 2880k Code/OTA, 320k FS", + "name": "Espressif Generic ESP32-solo1 >= 4M Flash, Tasmota 2880k Code/OTA, 320k FS", "upload": { "arduino": { "flash_extra_images": [ @@ -44,6 +40,6 @@ "download": { "speed": 230400 }, - "url": "https://en.wikipedia.org/wiki/ESP32", + "url": "https://www.espressif.com/sites/default/files/documentation/esp32-solo-1_datasheet_en.pdf", "vendor": "Espressif" } diff --git a/boards/esp32c2.json b/boards/esp32c2.json index ea5cbae2c..71453ec07 100644 --- a/boards/esp32c2.json +++ b/boards/esp32c2.json @@ -1,10 +1,7 @@ { "build": { - "arduino":{ - "ldscript": "esp32c2_out.ld" - }, "core": "esp32", - "extra_flags": "-DESP32_4M -DESP32C2", + "extra_flags": "-DARDUINO_TASMOTA -DESP32_4M -DESP32C2", "f_cpu": "120000000L", "f_flash": "60000000L", "flash_mode": "qio", @@ -20,8 +17,7 @@ "openocd_target": "esp32c2.cfg" }, "frameworks": [ - "arduino", - "espidf" + "arduino" ], "name": "Espressif Generic ESP32-C2 = 4M Flash, Tasmota 2880k Code/OTA, 320k FS", "upload": { diff --git a/boards/esp32c2_2M.json b/boards/esp32c2_2M.json index fbffa167c..b5592743d 100644 --- a/boards/esp32c2_2M.json +++ b/boards/esp32c2_2M.json @@ -1,10 +1,7 @@ { "build": { - "arduino":{ - "ldscript": "esp32c2_out.ld" - }, "core": "esp32", - "extra_flags": "-DESP32_2M -DESP32C2", + "extra_flags": "-DARDUINO_TASMOTA -DESP32_2M -DESP32C2", "f_cpu": "120000000L", "f_flash": "60000000L", "flash_mode": "qio", @@ -20,8 +17,7 @@ "openocd_target": "esp32c2.cfg" }, "frameworks": [ - "arduino", - "espidf" + "arduino" ], "name": "Espressif Generic ESP32-C2 = 2M Flash, Tasmota 1245kB Code/OTA, 64k FS", "upload": { diff --git a/boards/esp32c3.json b/boards/esp32c3.json index 6a49ba922..5f77c6990 100644 --- a/boards/esp32c3.json +++ b/boards/esp32c3.json @@ -1,10 +1,7 @@ { "build": { - "arduino":{ - "ldscript": "esp32c3_out.ld" - }, "core": "esp32", - "extra_flags": "-DESP32_4M -DESP32C3", + "extra_flags": "-DARDUINO_TASMOTA -DARDUINO_USB_MODE=1 -DESP32_4M -DESP32C3 -DUSE_USB_CDC_CONSOLE", "f_cpu": "160000000L", "f_flash": "80000000L", "flash_mode": "dio", @@ -17,11 +14,14 @@ "bluetooth" ], "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], "openocd_target": "esp32c3.cfg" }, "frameworks": [ - "arduino", - "espidf" + "arduino" ], "name": "Espressif Generic ESP32-C3 >= 4M Flash, Tasmota 2880k Code/OTA, 320k FS", "upload": { @@ -37,10 +37,10 @@ "maximum_ram_size": 327680, "maximum_size": 4194304, "require_upload_port": true, - "speed": 460800 + "speed": 2000000 }, "download": { - "speed": 230400 + "speed": 2000000 }, "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/hw-reference/esp32c3/user-guide-devkitm-1.html", "vendor": "Espressif" diff --git a/boards/esp32c3cdc.json b/boards/esp32c3ser.json similarity index 71% rename from boards/esp32c3cdc.json rename to boards/esp32c3ser.json index 7ee0326f0..faf5649a7 100644 --- a/boards/esp32c3cdc.json +++ b/boards/esp32c3ser.json @@ -1,10 +1,7 @@ { "build": { - "arduino":{ - "ldscript": "esp32c3_out.ld" - }, "core": "esp32", - "extra_flags": "-DARDUINO_USB_MODE=1 -DESP32_4M -DESP32C3 -DUSE_USB_CDC_CONSOLE", + "extra_flags": "-DARDUINO_TASMOTA -DESP32_4M -DESP32C3", "f_cpu": "160000000L", "f_flash": "80000000L", "flash_mode": "dio", @@ -17,15 +14,10 @@ "bluetooth" ], "debug": { - "default_tool": "esp-builtin", - "onboard_tools": [ - "esp-builtin" - ], "openocd_target": "esp32c3.cfg" }, "frameworks": [ - "arduino", - "espidf" + "arduino" ], "name": "Espressif Generic ESP32-C3 >= 4M Flash, Tasmota 2880k Code/OTA, 320k FS", "upload": { @@ -33,7 +25,7 @@ "flash_extra_images": [ [ "0x10000", - "tasmota32c3cdc-safeboot.bin" + "tasmota32c3ser-safeboot.bin" ] ] }, @@ -41,10 +33,10 @@ "maximum_ram_size": 327680, "maximum_size": 4194304, "require_upload_port": true, - "speed": 2000000 + "speed": 460800 }, "download": { - "speed": 2000000 + "speed": 230400 }, "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/hw-reference/esp32c3/user-guide-devkitm-1.html", "vendor": "Espressif" diff --git a/boards/esp32c6.json b/boards/esp32c6.json index 68feaec6e..dd5515743 100644 --- a/boards/esp32c6.json +++ b/boards/esp32c6.json @@ -1,10 +1,7 @@ { "build": { - "arduino":{ - "ldscript": "esp32c6_out.ld" - }, "core": "esp32", - "extra_flags": "-DESP32_4M -DESP32C6", + "extra_flags": "-DARDUINO_TASMOTA -DARDUINO_USB_MODE=1 -DESP32_4M -DESP32C6 -DUSE_USB_CDC_CONSOLE", "f_cpu": "160000000L", "f_flash": "80000000L", "flash_mode": "qio", @@ -17,11 +14,14 @@ "bluetooth" ], "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], "openocd_target": "esp32c6.cfg" }, "frameworks": [ - "arduino", - "espidf" + "arduino" ], "name": "Espressif Generic ESP32-C6 >= 4M Flash, Tasmota 2880k Code/OTA, 320k FS", "upload": { @@ -37,10 +37,10 @@ "maximum_ram_size": 327680, "maximum_size": 4194304, "require_upload_port": true, - "speed": 460800 + "speed": 2000000 }, "download": { - "speed": 230400 + "speed": 2000000 }, "url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html", "vendor": "Espressif" diff --git a/boards/esp32c6cdc.json b/boards/esp32c6ser.json similarity index 71% rename from boards/esp32c6cdc.json rename to boards/esp32c6ser.json index 9cde9e62b..952b79399 100644 --- a/boards/esp32c6cdc.json +++ b/boards/esp32c6ser.json @@ -1,10 +1,7 @@ { "build": { - "arduino":{ - "ldscript": "esp32c6_out.ld" - }, "core": "esp32", - "extra_flags": "-DARDUINO_USB_MODE=1 -DESP32_4M -DESP32C6 -DUSE_USB_CDC_CONSOLE", + "extra_flags": "-DARDUINO_TASMOTA -DESP32_4M -DESP32C6", "f_cpu": "160000000L", "f_flash": "80000000L", "flash_mode": "qio", @@ -17,15 +14,10 @@ "bluetooth" ], "debug": { - "default_tool": "esp-builtin", - "onboard_tools": [ - "esp-builtin" - ], "openocd_target": "esp32c6.cfg" }, "frameworks": [ - "arduino", - "espidf" + "arduino" ], "name": "Espressif Generic ESP32-C6 >= 4M Flash, Tasmota 2880k Code/OTA, 320k FS", "upload": { @@ -33,7 +25,7 @@ "flash_extra_images": [ [ "0x10000", - "tasmota32c6cdc-safeboot.bin" + "tasmota32c6ser-safeboot.bin" ] ] }, @@ -41,10 +33,10 @@ "maximum_ram_size": 327680, "maximum_size": 4194304, "require_upload_port": true, - "speed": 2000000 + "speed": 460800 }, "download": { - "speed": 2000000 + "speed": 230400 }, "url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html", "vendor": "Espressif" diff --git a/boards/esp32s2.json b/boards/esp32s2.json index 18bd9200a..0f60f5617 100644 --- a/boards/esp32s2.json +++ b/boards/esp32s2.json @@ -1,10 +1,7 @@ { "build": { - "arduino":{ - "ldscript": "esp32s2_out.ld" - }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DESP32_4M -DESP32S2", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DESP32_4M -DESP32S2", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "dio", @@ -19,7 +16,6 @@ "openocd_target": "esp32s2.cfg" }, "frameworks": [ - "espidf", "arduino" ], "name": "Espressif Generic ESP32-S2 >= 4M Flash PSRAM, Tasmota 2880k Code/OTA, 320k FS", diff --git a/boards/esp32s2cdc.json b/boards/esp32s2cdc.json index c379be423..0d85af692 100644 --- a/boards/esp32s2cdc.json +++ b/boards/esp32s2cdc.json @@ -1,10 +1,7 @@ { "build": { - "arduino":{ - "ldscript": "esp32s2_out.ld" - }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S2", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S2", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "dio", @@ -19,7 +16,6 @@ "openocd_target": "esp32s2.cfg" }, "frameworks": [ - "espidf", "arduino" ], "name": "Espressif Generic ESP32-S2 >= 4M Flash PSRAM, Tasmota 2880k Code/OTA, 320k FS", diff --git a/boards/esp32s3-opi_opi.json b/boards/esp32s3-opi_opi.json index 92803a838..25541b95d 100644 --- a/boards/esp32s3-opi_opi.json +++ b/boards/esp32s3-opi_opi.json @@ -1,14 +1,19 @@ { "build": { "arduino":{ - "ldscript": "esp32s3_out.ld", "memory_type": "opi_opi" }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DESP32_4M -DESP32S3", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "dout", + "hwids": [ + [ + "0x303A", + "0x1001" + ] + ], "mcu": "esp32s3", "variant": "esp32s3", "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" @@ -19,10 +24,13 @@ "ethernet" ], "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], "openocd_target": "esp32s3.cfg" }, "frameworks": [ - "espidf", "arduino" ], "name": "Espressif Generic ESP32-S3 >= 4M OPI Flash + PSRAM, Tasmota 2880k Code/OTA, 320k FS", @@ -39,11 +47,11 @@ "maximum_ram_size": 327680, "maximum_size": 4194304, "require_upload_port": true, - "speed": 460800 + "speed": 2000000 }, "download": { - "speed": 230400 + "speed": 2000000 }, "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/", "vendor": "Espressif" - } \ No newline at end of file + } diff --git a/boards/esp32s3-opi_opi_120.json b/boards/esp32s3-opi_opi_120.json new file mode 100644 index 000000000..ab9ef01fb --- /dev/null +++ b/boards/esp32s3-opi_opi_120.json @@ -0,0 +1,53 @@ +{ + "build": { + "arduino":{ + "memory_type": "opi_opi" + }, + "core": "esp32", + "f_cpu": "240000000L", + "f_flash": "80000000L", + "f_boot": "120000000L", + "boot": "opi", + "flash_mode": "dout", + "mcu": "esp32s3", + "variant": "esp32s3", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3", + "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth", + "ethernet" + ], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], + "openocd_target": "esp32s3.cfg" + }, + "frameworks": [ + "arduino" + ], + "name": "Espressif Generic ESP32-S3 >= 4M OPI Flash + PSRAM, Tasmota 2880k Code/OTA, 320k FS", + "upload": { + "arduino": { + "flash_extra_images": [ + [ + "0x10000", + "tasmota32s3-safeboot.bin" + ] + ] + }, + "flash_size": "4MB", + "maximum_ram_size": 327680, + "maximum_size": 4194304, + "require_upload_port": true, + "speed": 2000000 + }, + "download": { + "speed": 2000000 + }, + "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/", + "vendor": "Espressif" +} diff --git a/boards/esp32s3-qio_opi.json b/boards/esp32s3-qio_opi.json index 614831574..c005158db 100644 --- a/boards/esp32s3-qio_opi.json +++ b/boards/esp32s3-qio_opi.json @@ -1,14 +1,19 @@ { "build": { "arduino":{ - "ldscript": "esp32s3_out.ld", "memory_type": "qio_opi" }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DESP32_4M -DESP32S3", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "qio", + "hwids": [ + [ + "0x303A", + "0x1001" + ] + ], "mcu": "esp32s3", "variant": "esp32s3", "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" @@ -19,10 +24,13 @@ "ethernet" ], "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], "openocd_target": "esp32s3.cfg" }, "frameworks": [ - "espidf", "arduino" ], "name": "Espressif Generic ESP32-S3 >= 4M Flash OPI PSRAM, Tasmota 2880k Code/OTA, 320k FS", @@ -39,10 +47,10 @@ "maximum_ram_size": 327680, "maximum_size": 4194304, "require_upload_port": true, - "speed": 460800 + "speed": 2000000 }, "download": { - "speed": 230400 + "speed": 2000000 }, "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/", "vendor": "Espressif" diff --git a/boards/esp32s3cdc-qio_opi.json b/boards/esp32s3-qio_opi_120.json similarity index 72% rename from boards/esp32s3cdc-qio_opi.json rename to boards/esp32s3-qio_opi_120.json index 46b363266..42589ce05 100644 --- a/boards/esp32s3cdc-qio_opi.json +++ b/boards/esp32s3-qio_opi_120.json @@ -1,22 +1,17 @@ { "build": { "arduino":{ - "ldscript": "esp32s3_out.ld", "memory_type": "qio_opi" }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3", "f_cpu": "240000000L", "f_flash": "80000000L", + "f_boot": "120000000L", + "boot": "qio", "flash_mode": "qio", - "hwids": [ - [ - "0x303A", - "0x1001" - ] - ], "mcu": "esp32s3", "variant": "esp32s3", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3", "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" }, "connectivity": [ @@ -32,16 +27,15 @@ "openocd_target": "esp32s3.cfg" }, "frameworks": [ - "espidf", "arduino" ], - "name": "Espressif Generic ESP32-S3 >= 4M Flash OPI PSRAM, Tasmota 2880k Code/OTA, 320k FS", + "name": "Espressif Generic ESP32-S3 >= 4M QIO Flash + OPI PSRAM, Tasmota 2880k Code/OTA, 320k FS", "upload": { "arduino": { "flash_extra_images": [ [ "0x10000", - "tasmota32s3cdc-safeboot.bin" + "tasmota32s3-safeboot.bin" ] ] }, diff --git a/boards/esp32s3-qio_qspi.json b/boards/esp32s3-qio_qspi.json index 9b11a31b0..eb834f0c2 100644 --- a/boards/esp32s3-qio_qspi.json +++ b/boards/esp32s3-qio_qspi.json @@ -1,14 +1,19 @@ { "build": { "arduino":{ - "ldscript": "esp32s3_out.ld", "memory_type": "qio_qspi" }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DESP32_4M -DESP32S3", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "qio", + "hwids": [ + [ + "0x303A", + "0x1001" + ] + ], "mcu": "esp32s3", "variant": "esp32s3", "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" @@ -19,10 +24,13 @@ "ethernet" ], "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], "openocd_target": "esp32s3.cfg" }, "frameworks": [ - "espidf", "arduino" ], "name": "Espressif Generic ESP32-S3 >= 4M Flash QSPI PSRAM, Tasmota 2880k Code/OTA, 320k FS", @@ -39,10 +47,10 @@ "maximum_ram_size": 327680, "maximum_size": 4194304, "require_upload_port": true, - "speed": 460800 + "speed": 2000000 }, "download": { - "speed": 230400 + "speed": 2000000 }, "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/", "vendor": "Espressif" diff --git a/boards/esp32s3cdc-qio_qspi.json b/boards/esp32s3-qio_qspi_120.json similarity index 72% rename from boards/esp32s3cdc-qio_qspi.json rename to boards/esp32s3-qio_qspi_120.json index fa90e8509..b1d89db91 100644 --- a/boards/esp32s3cdc-qio_qspi.json +++ b/boards/esp32s3-qio_qspi_120.json @@ -1,22 +1,17 @@ { "build": { "arduino":{ - "ldscript": "esp32s3_out.ld", "memory_type": "qio_qspi" }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3", "f_cpu": "240000000L", "f_flash": "80000000L", + "f_boot": "120000000L", + "boot": "qio", "flash_mode": "qio", - "hwids": [ - [ - "0x303A", - "0x1001" - ] - ], "mcu": "esp32s3", "variant": "esp32s3", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3", "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" }, "connectivity": [ @@ -32,16 +27,15 @@ "openocd_target": "esp32s3.cfg" }, "frameworks": [ - "espidf", "arduino" ], - "name": "Espressif Generic ESP32-S3 >= 4M Flash QSPI PSRAM, Tasmota 2880k Code/OTA, 320k FS", + "name": "Espressif Generic ESP32-S3 >= 4M QIO Flash + QSPI PSRAM, Tasmota 2880k Code/OTA, 320k FS", "upload": { "arduino": { "flash_extra_images": [ [ "0x10000", - "tasmota32s3cdc-safeboot.bin" + "tasmota32s3-safeboot.bin" ] ] }, diff --git a/boards/esp32s3cdc-opi_opi.json b/boards/esp32s3ser-opi_opi.json similarity index 70% rename from boards/esp32s3cdc-opi_opi.json rename to boards/esp32s3ser-opi_opi.json index 684cba031..9069a456e 100644 --- a/boards/esp32s3cdc-opi_opi.json +++ b/boards/esp32s3ser-opi_opi.json @@ -1,20 +1,13 @@ { "build": { "arduino":{ - "ldscript": "esp32s3_out.ld", "memory_type": "opi_opi" }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DESP32_4M -DESP32S3", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "dout", - "hwids": [ - [ - "0x303A", - "0x1001" - ] - ], "mcu": "esp32s3", "variant": "esp32s3", "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" @@ -25,14 +18,9 @@ "ethernet" ], "debug": { - "default_tool": "esp-builtin", - "onboard_tools": [ - "esp-builtin" - ], "openocd_target": "esp32s3.cfg" }, "frameworks": [ - "espidf", "arduino" ], "name": "Espressif Generic ESP32-S3 >= 4M OPI Flash + PSRAM, Tasmota 2880k Code/OTA, 320k FS", @@ -41,7 +29,7 @@ "flash_extra_images": [ [ "0x10000", - "tasmota32s3cdc-safeboot.bin" + "tasmota32s3ser-safeboot.bin" ] ] }, @@ -49,11 +37,11 @@ "maximum_ram_size": 327680, "maximum_size": 4194304, "require_upload_port": true, - "speed": 2000000 + "speed": 460800 }, "download": { - "speed": 2000000 + "speed": 230400 }, "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/", "vendor": "Espressif" - } \ No newline at end of file + } diff --git a/boards/esp32s3ser-opi_opi_120.json b/boards/esp32s3ser-opi_opi_120.json new file mode 100644 index 000000000..5d370c746 --- /dev/null +++ b/boards/esp32s3ser-opi_opi_120.json @@ -0,0 +1,49 @@ +{ + "build": { + "arduino":{ + "memory_type": "opi_opi" + }, + "core": "esp32", + "f_cpu": "240000000L", + "f_flash": "80000000L", + "f_boot": "120000000L", + "boot": "opi", + "flash_mode": "dout", + "mcu": "esp32s3", + "variant": "esp32s3", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DESP32_4M -DESP32S3", + "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth", + "ethernet" + ], + "debug": { + "openocd_target": "esp32s3.cfg" + }, + "frameworks": [ + "arduino" + ], + "name": "Espressif Generic ESP32-S3 >= 4M OPI Flash + PSRAM, Tasmota 2880k Code/OTA, 320k FS", + "upload": { + "arduino": { + "flash_extra_images": [ + [ + "0x10000", + "tasmota32s3ser-safeboot.bin" + ] + ] + }, + "flash_size": "4MB", + "maximum_ram_size": 327680, + "maximum_size": 4194304, + "require_upload_port": true, + "speed": 460800 + }, + "download": { + "speed": 230400 + }, + "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/", + "vendor": "Espressif" +} diff --git a/boards/esp32s3ser-qio_opi.json b/boards/esp32s3ser-qio_opi.json new file mode 100644 index 000000000..d588b060d --- /dev/null +++ b/boards/esp32s3ser-qio_opi.json @@ -0,0 +1,47 @@ +{ + "build": { + "arduino":{ + "memory_type": "qio_opi" + }, + "core": "esp32", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DESP32_4M -DESP32S3", + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "mcu": "esp32s3", + "variant": "esp32s3", + "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth", + "ethernet" + ], + "debug": { + "openocd_target": "esp32s3.cfg" + }, + "frameworks": [ + "arduino" + ], + "name": "Espressif Generic ESP32-S3 >= 4M Flash OPI PSRAM, Tasmota 2880k Code/OTA, 320k FS", + "upload": { + "arduino": { + "flash_extra_images": [ + [ + "0x10000", + "tasmota32s3ser-safeboot.bin" + ] + ] + }, + "flash_size": "4MB", + "maximum_ram_size": 327680, + "maximum_size": 4194304, + "require_upload_port": true, + "speed": 460800 + }, + "download": { + "speed": 230400 + }, + "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/", + "vendor": "Espressif" +} diff --git a/boards/esp32s3ser-qio_opi_120.json b/boards/esp32s3ser-qio_opi_120.json new file mode 100644 index 000000000..aea5ff20e --- /dev/null +++ b/boards/esp32s3ser-qio_opi_120.json @@ -0,0 +1,49 @@ +{ + "build": { + "arduino":{ + "memory_type": "qio_opi" + }, + "core": "esp32", + "f_cpu": "240000000L", + "f_flash": "80000000L", + "f_boot": "120000000L", + "boot": "qio", + "flash_mode": "qio", + "mcu": "esp32s3", + "variant": "esp32s3", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DESP32_4M -DESP32S3", + "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth", + "ethernet" + ], + "debug": { + "openocd_target": "esp32s3.cfg" + }, + "frameworks": [ + "arduino" + ], + "name": "Espressif Generic ESP32-S3 >= 4M QIO Flash + OPI PSRAM, Tasmota 2880k Code/OTA, 320k FS", + "upload": { + "arduino": { + "flash_extra_images": [ + [ + "0x10000", + "tasmota32s3ser-safeboot.bin" + ] + ] + }, + "flash_size": "4MB", + "maximum_ram_size": 327680, + "maximum_size": 4194304, + "require_upload_port": true, + "speed": 460800 + }, + "download": { + "speed": 230400 + }, + "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/", + "vendor": "Espressif" +} diff --git a/boards/esp32s3ser-qio_qspi.json b/boards/esp32s3ser-qio_qspi.json new file mode 100644 index 000000000..aedf4f3a5 --- /dev/null +++ b/boards/esp32s3ser-qio_qspi.json @@ -0,0 +1,47 @@ +{ + "build": { + "arduino":{ + "memory_type": "qio_qspi" + }, + "core": "esp32", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DESP32_4M -DESP32S3", + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "mcu": "esp32s3", + "variant": "esp32s3", + "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth", + "ethernet" + ], + "debug": { + "openocd_target": "esp32s3.cfg" + }, + "frameworks": [ + "arduino" + ], + "name": "Espressif Generic ESP32-S3 >= 4M Flash QSPI PSRAM, Tasmota 2880k Code/OTA, 320k FS", + "upload": { + "arduino": { + "flash_extra_images": [ + [ + "0x10000", + "tasmota32s3ser-safeboot.bin" + ] + ] + }, + "flash_size": "4MB", + "maximum_ram_size": 327680, + "maximum_size": 4194304, + "require_upload_port": true, + "speed": 460800 + }, + "download": { + "speed": 230400 + }, + "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/", + "vendor": "Espressif" +} diff --git a/boards/esp8266_16M14M.json b/boards/esp8266_16M14M.json new file mode 100644 index 000000000..60f05504a --- /dev/null +++ b/boards/esp8266_16M14M.json @@ -0,0 +1,30 @@ +{ + "build": { + "arduino": { + "ldscript": "eagle.flash.16m14m.ld" + }, + "core": "esp8266", + "extra_flags": "-DARDUINO_TASMOTA -DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_16M -DESP8266_16M14M", + "f_cpu": "80000000L", + "f_flash": "40000000L", + "flash_mode": "dout", + "mcu": "esp8266", + "variant": "generic" + }, + "connectivity": [ + "wifi" + ], + "frameworks": [ + "arduino" + ], + "name": "Espressif Generic ESP8266 Tasmota 1M sketch 1M OTA 14M FS", + "upload": { + "maximum_ram_size": 81920, + "maximum_size": 995326, + "require_upload_port": true, + "resetmethod": "ck", + "speed": 115200 + }, + "url": "http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family", + "vendor": "Espressif" +} diff --git a/boards/esp8266_1M.json b/boards/esp8266_1M.json index 6c3327ae7..f07889d94 100644 --- a/boards/esp8266_1M.json +++ b/boards/esp8266_1M.json @@ -4,7 +4,7 @@ "ldscript": "eagle.flash.1m.ld" }, "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_1M", + "extra_flags": "-DARDUINO_TASMOTA -DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_1M", "f_cpu": "80000000L", "f_flash": "40000000L", "flash_mode": "dout", diff --git a/boards/esp8266_2M1M.json b/boards/esp8266_2M1M.json index 3f34da721..8ad59eee5 100644 --- a/boards/esp8266_2M1M.json +++ b/boards/esp8266_2M1M.json @@ -4,7 +4,7 @@ "ldscript": "eagle.flash.2m1m.ld" }, "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_2M -DESP8266_2M1M", + "extra_flags": "-DARDUINO_TASMOTA -DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_2M -DESP8266_2M1M", "f_cpu": "80000000L", "f_flash": "40000000L", "flash_mode": "dout", diff --git a/boards/esp8266_2M256.json b/boards/esp8266_2M256.json index 5ef9e86ae..473553fa7 100644 --- a/boards/esp8266_2M256.json +++ b/boards/esp8266_2M256.json @@ -4,7 +4,7 @@ "ldscript": "eagle.flash.2m256.ld" }, "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_2M -DESP8266_2M256", + "extra_flags": "-DARDUINO_TASMOTA -DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_2M -DESP8266_2M256", "f_cpu": "80000000L", "f_flash": "40000000L", "flash_mode": "dout", diff --git a/boards/esp8266_4M2M.json b/boards/esp8266_4M2M.json index 9708b2621..747679b16 100644 --- a/boards/esp8266_4M2M.json +++ b/boards/esp8266_4M2M.json @@ -4,7 +4,7 @@ "ldscript": "eagle.flash.4m2m.ld" }, "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_4M -DESP8266_4M2M", + "extra_flags": "-DARDUINO_TASMOTA -DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_4M -DESP8266_4M2M", "f_cpu": "80000000L", "f_flash": "40000000L", "flash_mode": "dout", diff --git a/boards/esp8266_4M3M.json b/boards/esp8266_4M3M.json index d1fe7e459..ee1dd4faf 100644 --- a/boards/esp8266_4M3M.json +++ b/boards/esp8266_4M3M.json @@ -4,7 +4,7 @@ "ldscript": "eagle.flash.4m3m.ld" }, "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_4M -DESP8266_4M3M", + "extra_flags": "-DARDUINO_TASMOTA -DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_4M -DESP8266_4M3M", "f_cpu": "80000000L", "f_flash": "40000000L", "flash_mode": "dout", diff --git a/boards/esp8266_zbbridge.json b/boards/esp8266_zbbridge.json index 726b71de3..54d4fcdef 100644 --- a/boards/esp8266_zbbridge.json +++ b/boards/esp8266_zbbridge.json @@ -4,7 +4,7 @@ "ldscript": "eagle.flash.2m256.ld" }, "core": "esp8266", - "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_2M -DESP8266_2M256", + "extra_flags": "-DARDUINO_TASMOTA -DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_2M -DESP8266_2M256", "f_cpu": "160000000L", "f_flash": "40000000L", "flash_mode": "dout", diff --git a/lib/default/Ext-printf/src/ext_printf.cpp b/lib/default/Ext-printf/src/ext_printf.cpp index df9204e3e..48499685c 100644 --- a/lib/default/Ext-printf/src/ext_printf.cpp +++ b/lib/default/Ext-printf/src/ext_printf.cpp @@ -157,6 +157,26 @@ char * U64toHex(uint64_t value, char *str) { } */ +char * ToBinary(uint32_t value, char *str, int32_t digits) { + if (digits > 32) { digits = 32; } + if (digits < 1) { digits = 1; } + int32_t digits_to_one = 1; // how many digits until we find the last `1` + str[32] = 0; // end of string + for (uint32_t i=0; i<32; i++) { // 32 digits in uint32_t + if ((value & 1) && (i+1 > digits_to_one)) { + digits_to_one = i+1; + } + str[31 - i] = (char)(value & 1)+'0'; + value = value >> 1; + } + // adjust digits to always show the total value + if (digits_to_one > digits) { digits = digits_to_one; } + if (digits < 32) { + memmove(str, str + 32 - digits, digits + 1); + } + return str; +} + char * U64toHex(uint64_t value, char *str, uint32_t zeroleads) { // str must be at least 17 bytes long str[16] = 0; // end of string @@ -235,7 +255,7 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l const uint32_t ALLOC_SIZE = 12; static const char * allocs[ALLOC_SIZE] = {}; // initialized to zeroes uint32_t alloc_idx = 0; - static char hex[20]; // buffer used for 64 bits, favor RAM instead of stack to remove pressure + static char hex[34]; // buffer used for 64 bits, favor RAM instead of stack to remove pressure for (; *fmt != 0; ++fmt) { int32_t decimals = -2; // default to 2 decimals and remove trailing zeros @@ -306,6 +326,16 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l } } break; + // '%_b' outputs a uint32_t to binary + // '%8_b' outputs a uint8_t to binary + case 'b': // Binary, decimals indicates the zero prefill + { + ToBinary(cur_val, hex, decimals); + new_val_str = copyStr(hex); + if (new_val_str == nullptr) { goto free_allocs; } + allocs[alloc_idx++] = new_val_str; + } + break; /* case 'V': // 2-byte values, decimals indicates the length, default 2 { diff --git a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h index c17da9eb3..230dd36ff 100644 --- a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h +++ b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h @@ -40,6 +40,7 @@ class TasmotaSerial : public Stream { TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback = 0, int nwmode = 0, int buffer_size = TM_SERIAL_BUFFER_SIZE, bool invert = false); virtual ~TasmotaSerial(); void setTransmitEnablePin(int tx_enable_pin); + void clearTransmitEnablePin(void) { m_tx_enable_pin = -1; } size_t setRxBufferSize(size_t size); size_t getRxBufferSize() { return serial_buffer_size; } diff --git a/lib/default/WiFiHelper/README.adoc b/lib/default/WiFiHelper/README.adoc new file mode 100644 index 000000000..66c26d5cc --- /dev/null +++ b/lib/default/WiFiHelper/README.adoc @@ -0,0 +1,19 @@ +Wifi Helper for Tasmota bridging differences between ESP8266 and ESP32 + +This Class is for compatibility with esp8266 code + +== License == + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/lib/default/WiFiHelper/library.json b/lib/default/WiFiHelper/library.json new file mode 100644 index 000000000..56676a297 --- /dev/null +++ b/lib/default/WiFiHelper/library.json @@ -0,0 +1,8 @@ +{ + "name": "WiFiHelper", + "keywords": "esp32, esp8266", + "description": "Bridges differences in Arduino WiFi between ESP32 and ESP8266", + "version": "1.0.0", + "frameworks": "arduino", + "platforms": "*" +} diff --git a/lib/default/WiFiHelper/src/WiFiHelper.h b/lib/default/WiFiHelper/src/WiFiHelper.h new file mode 100644 index 000000000..666ceba4d --- /dev/null +++ b/lib/default/WiFiHelper/src/WiFiHelper.h @@ -0,0 +1,90 @@ +/* + WiFiHelper.h - provide a wrapper for differences between ESP8266 and ESP32 WiFi + + Copyright (C) 2024 Theo Arends / Stephan Hadinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef WIFIHELPER_H +#define WIFIHELPER_H + + +// ====================================================== +// ESP8266 specific section +// ====================================================== +#ifdef ESP8266 +#include "ESP8266WiFi.h" +#endif + + +// ====================================================== +// ESP32 specific section +// ====================================================== +#ifdef ESP32 +#include + +#define ENC_TYPE_NONE WIFI_AUTH_OPEN +#define ENC_TYPE_WEP WIFI_AUTH_WEP +#define ENC_TYPE_CCMP WIFI_AUTH_WPA2_PSK +#define ENC_TYPE_TKIP WIFI_AUTH_WPA_WPA2_PSK +#define ENC_TYPE_AUTO WIFI_AUTH_MAX + 1 + +#define WIFI_NONE_SLEEP 0 +#define WIFI_LIGHT_SLEEP 1 +#define WIFI_MODEM_SLEEP 2 + +// ESP8266 +typedef enum WiFiPhyMode +{ + TAS_WIFI_PHY_MODE_LR = 0, TAS_WIFI_PHY_MODE_11B = 1, TAS_WIFI_PHY_MODE_11G = 2, TAS_WIFI_PHY_MODE_11N = 3 +#if ESP_IDF_VERSION_MAJOR >= 5 + , TAS_WIFI_PHY_MODE_11AX = 4 +#endif +} WiFiPhyMode_t; + +#endif // ESP32 + +// This is an abstract class containing wrappers to call WiFi +class WiFiHelper { +public: +#ifdef ESP32 + static wl_status_t begin(const char* wpa2_ssid, wpa2_auth_method_t method, const char* wpa2_identity=NULL, const char* wpa2_username=NULL, const char *wpa2_password=NULL, const char* ca_pem=NULL, const char* client_crt=NULL, const char* client_key=NULL, int32_t channel=0, const uint8_t* bssid=0, bool connect=true); +#endif + static wl_status_t begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); + static wl_status_t begin(char* ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); + static wl_status_t begin(); + + static void hostname(const char* aHostname); + static void setSleepMode(int iSleepMode); + static int getPhyMode(); + static bool setPhyMode(WiFiPhyMode_t mode); + + static void setOutputPower(int n); + static void forceSleepBegin(); + static void forceSleepWake(); + static bool getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t* &bssid, int32_t &channel, bool &hidden_scan); + + static int hostByName(const char* aHostname, IPAddress& aResult, int32_t timer_ms); + static int hostByName(const char* aHostname, IPAddress& aResult); + + static void scrubDNS(void); + + // With ESP32 Core3, the WiFi mac address is not valid until the wifi is actually started + // this helper function always provide a valid mac address + static String macAddress(void); +}; + + + +#endif // WIFIHELPER_H \ No newline at end of file diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp b/lib/default/WiFiHelper/src/WiFiHelper_ESP32.cpp similarity index 63% rename from lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp rename to lib/default/WiFiHelper/src/WiFiHelper_ESP32.cpp index c5cdedc3f..6741652e1 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp +++ b/lib/default/WiFiHelper/src/WiFiHelper_ESP32.cpp @@ -16,48 +16,48 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -// +#ifdef ESP32 + #include "Arduino.h" -#include +#include "WiFiHelper.h" #include extern void AddLog(uint32_t loglevel, PGM_P formatP, ...); enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE}; -// -// Wifi -// -#ifdef WiFi -#undef WiFi -#endif + +#ifdef USE_IPV6 +ip_addr_t dns_save4[DNS_MAX_SERVERS] = {}; // IPv4 DNS servers +ip_addr_t dns_save6[DNS_MAX_SERVERS] = {}; // IPv6 DNS servers +#endif // USE_IPV6 #include "tasmota_options.h" #include "lwip/dns.h" -wl_status_t WiFiClass32::begin(const char* wpa2_ssid, wpa2_auth_method_t method, const char* wpa2_identity, const char* wpa2_username, const char *wpa2_password, const char* ca_pem, const char* client_crt, const char* client_key, int32_t channel, const uint8_t* bssid, bool connect) { - scrubDNS(); - wl_status_t ret = WiFiClass::begin(wpa2_ssid, method, wpa2_identity, wpa2_username, wpa2_password, ca_pem, client_crt, client_key, channel, bssid, connect); - scrubDNS(); +wl_status_t WiFiHelper::begin(const char* wpa2_ssid, wpa2_auth_method_t method, const char* wpa2_identity, const char* wpa2_username, const char *wpa2_password, const char* ca_pem, const char* client_crt, const char* client_key, int32_t channel, const uint8_t* bssid, bool connect) { + WiFiHelper::scrubDNS(); + wl_status_t ret = WiFi.begin(wpa2_ssid, method, wpa2_identity, wpa2_username, wpa2_password, ca_pem, client_crt, client_key, channel, bssid, connect); + WiFiHelper::scrubDNS(); return ret; } -wl_status_t WiFiClass32::begin(const char* ssid, const char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) { - scrubDNS(); - wl_status_t ret = WiFiClass::begin(ssid, passphrase, channel, bssid, connect); - scrubDNS(); +wl_status_t WiFiHelper::begin(const char* ssid, const char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) { + WiFiHelper::scrubDNS(); + wl_status_t ret = WiFi.begin(ssid, passphrase, channel, bssid, connect); + WiFiHelper::scrubDNS(); return ret; } -wl_status_t WiFiClass32::begin(char* ssid, char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) { - scrubDNS(); - wl_status_t ret = WiFiClass::begin(ssid, passphrase, channel, bssid, connect); - scrubDNS(); +wl_status_t WiFiHelper::begin(char* ssid, char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) { + WiFiHelper::scrubDNS(); + wl_status_t ret = WiFi.begin(ssid, passphrase, channel, bssid, connect); + WiFiHelper::scrubDNS(); return ret; } -wl_status_t WiFiClass32::begin() { - scrubDNS(); - wl_status_t ret = WiFiClass::begin(); - scrubDNS(); +wl_status_t WiFiHelper::begin() { + WiFiHelper::scrubDNS(); + wl_status_t ret = WiFi.begin(); + WiFiHelper::scrubDNS(); return ret; } @@ -73,7 +73,7 @@ extern bool EthernetHasIPv4(void); extern bool WifiHasIPv6(void); extern bool EthernetHasIPv6(void); -void WiFiClass32::scrubDNS(void) { +void WiFiHelper::scrubDNS(void) { // String dns_entry0 = IPAddress(dns_getserver(0)).toString(); // String dns_entry1 = IPAddress(dns_getserver(1)).toString(); // scan DNS entries @@ -118,36 +118,52 @@ void WiFiClass32::scrubDNS(void) { // AddLog(LOG_LEVEL_DEBUG, "IP>: DNS: from(%s %s) to (%s %s) has4/6:%i-%i", dns_entry0.c_str(), dns_entry1.c_str(), IPAddress(dns_getserver(0)).toString().c_str(), IPAddress(dns_getserver(1)).toString().c_str(), has_v4, has_v6); } -void WiFiClass32::setSleepMode(int iSleepMode) { + +void WiFiHelper::hostname(const char* aHostname) { + WiFi.setHostname(aHostname); +} + +void WiFiHelper::setSleepMode(int iSleepMode) { // WIFI_LIGHT_SLEEP and WIFI_MODEM_SLEEP WiFi.setSleep(iSleepMode != WIFI_NONE_SLEEP); } -int WiFiClass32::getPhyMode() { - int phy_mode = 0; // " BGNL" - uint8_t protocol_bitmap; - if (esp_wifi_get_protocol(WIFI_IF_STA, &protocol_bitmap) == ESP_OK) { - if (protocol_bitmap & 1) { phy_mode = TAS_WIFI_PHY_MODE_11B; } // 1 = 11b (WIFI_PHY_MODE_11B) - if (protocol_bitmap & 2) { phy_mode = TAS_WIFI_PHY_MODE_11G; } // 2 = 11bg (WIFI_PHY_MODE_11G) - if (protocol_bitmap & 4) { phy_mode = TAS_WIFI_PHY_MODE_11N; } // 3 = 11bgn (WIFI_PHY_MODE_11N) - if (protocol_bitmap & 8) { phy_mode = 4; } // Low rate (WIFI_PHY_MODE_LR) +int WiFiHelper::getPhyMode() { + /* + typedef enum + { + WIFI_PHY_MODE_LR, // PHY mode for Low Rate + WIFI_PHY_MODE_11B, // PHY mode for 11b + WIFI_PHY_MODE_11G, // PHY mode for 11g + WIFI_PHY_MODE_HT20, // PHY mode for Bandwidth HT20 (11n) + WIFI_PHY_MODE_HT40, // PHY mode for Bandwidth HT40 (11n) + WIFI_PHY_MODE_HE20, // PHY mode for Bandwidth HE20 (11ax) + } wifi_phy_mode_t; + */ + int phy_mode = 0; // "low rate|11b|11g|HT20|HT40|HE20" + wifi_phy_mode_t WiFiMode; + if (esp_wifi_sta_get_negotiated_phymode(&WiFiMode) == ESP_OK) { + phy_mode = (int)WiFiMode; + if (phy_mode > 5) { + phy_mode = 5; + } } return phy_mode; } -bool WiFiClass32::setPhyMode(WiFiPhyMode_t mode) { - uint8_t protocol_bitmap = WIFI_PROTOCOL_11B; // 1 +bool WiFiHelper::setPhyMode(WiFiPhyMode_t mode) { + uint8_t protocol_bitmap = WIFI_PROTOCOL_11B; // 1 switch (mode) { - case 3: protocol_bitmap |= WIFI_PROTOCOL_11N; // 4 - case 2: protocol_bitmap |= WIFI_PROTOCOL_11G; // 2 +#if ESP_IDF_VERSION_MAJOR >= 5 + case 4: protocol_bitmap |= WIFI_PROTOCOL_11AX; // 16 +#endif + case 3: protocol_bitmap |= WIFI_PROTOCOL_11N; // 4 + case 2: protocol_bitmap |= WIFI_PROTOCOL_11G; // 2 } return (ESP_OK == esp_wifi_set_protocol(WIFI_IF_STA, protocol_bitmap)); } -void WiFiClass32::wps_disable() { -} - -void WiFiClass32::setOutputPower(int n) { +void WiFiHelper::setOutputPower(int n) { wifi_power_t p = WIFI_POWER_2dBm; if (n > 19) p = WIFI_POWER_19_5dBm; @@ -170,13 +186,13 @@ void WiFiClass32::setOutputPower(int n) { WiFi.setTxPower(p); } -void WiFiClass32::forceSleepBegin() { +void WiFiHelper::forceSleepBegin() { } -void WiFiClass32::forceSleepWake() { +void WiFiHelper::forceSleepWake() { } -bool WiFiClass32::getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t *&bssid, int32_t &channel, bool &hidden_scan) { +bool WiFiHelper::getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t *&bssid, int32_t &channel, bool &hidden_scan) { hidden_scan = false; return WiFi.getNetworkInfo(i, ssid, encType, rssi, bssid, channel); } @@ -199,6 +215,16 @@ static volatile uint32_t ip_addr_counter = 0; // counter for requests extern int32_t WifiDNSGetTimeout(void); extern bool WifiDNSGetIPv6Priority(void); +static volatile bool dns_found = false; + +bool DNS_TimeReached(uint32_t timer) +{ + // Check if a certain timeout has been reached. + int32_t passed = ((int32_t) (millis() - timer)); + return (passed >= 0); +} + + static void wifi32_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg) { // Serial.printf("DNS: cb name=%s ipaddr=%s arg=%i counter=%i\n", name ? name : "", IPAddress(ipaddr).toString().c_str(), (int) callback_arg, ip_addr_counter); @@ -210,13 +236,9 @@ static void wifi32_dns_found_callback(const char *name, const ip_addr_t *ipaddr, } else { dns_ipaddr = *IP4_ADDR_ANY; // set to IPv4 0.0.0.0 } - WiFiClass32::dnsDone(); + dns_found = true; // AddLog(LOG_LEVEL_DEBUG, "WIF: dns_found=%s", ipaddr ? IPAddress(*ipaddr).toString().c_str() : ""); } -// We need this helper method to access protected methods from WiFiGeneric -void WiFiClass32::dnsDone(void) { - setStatusBits(NET_DNS_DONE_BIT); -} /** * Resolve the given hostname to an IP address. @@ -225,19 +247,22 @@ void WiFiClass32::dnsDone(void) { * @return 1 if aIPAddrString was successfully converted to an IP address, * else error code */ -int WiFiClass32::hostByName(const char* aHostname, IPAddress& aResult, int32_t timer_ms) +int WiFiHelper::hostByName(const char* aHostname, IPAddress& aResult, int32_t timer_ms) { +// return WiFi.hostByName(aHostname, aResult); +// #if 0 ip_addr_t addr; aResult = (uint32_t) 0; // by default set to IPv4 0.0.0.0 dns_ipaddr = *IP4_ADDR_ANY; // by default set to IPv4 0.0.0.0 - scrubDNS(); // internal calls to reconnect can zero the DNS servers, save DNS for future use + WiFiHelper::scrubDNS(); // internal calls to reconnect can zero the DNS servers, save DNS for future use ip_addr_counter++; // increase counter, from now ignore previous responses - clearStatusBits(NET_DNS_IDLE_BIT | NET_DNS_DONE_BIT); + // clearStatusBits(NET_DNS_IDLE_BIT | NET_DNS_DONE_BIT); uint8_t v4v6priority = LWIP_DNS_ADDRTYPE_IPV4; #ifdef USE_IPV6 v4v6priority = WifiDNSGetIPv6Priority() ? LWIP_DNS_ADDRTYPE_IPV6_IPV4 : LWIP_DNS_ADDRTYPE_IPV4_IPV6; #endif // USE_IPV6 + dns_found = false; err_t err = dns_gethostbyname_addrtype(aHostname, &dns_ipaddr, &wifi32_dns_found_callback, (void*) ip_addr_counter, v4v6priority); // Serial.printf("DNS: dns_gethostbyname_addrtype errg=%i counter=%i\n", err, ip_addr_counter); if(err == ERR_OK && !ip_addr_isany_val(dns_ipaddr)) { @@ -247,8 +272,10 @@ int WiFiClass32::hostByName(const char* aHostname, IPAddress& aResult, int32_t t aResult = ip_addr_get_ip4_u32(&dns_ipaddr); #endif // USE_IPV6 } else if(err == ERR_INPROGRESS) { - waitStatusBits(NET_DNS_DONE_BIT, timer_ms); //real internal timeout in lwip library is 14[s] - clearStatusBits(NET_DNS_DONE_BIT); + uint32_t deadline = millis() + timer_ms; + while ((!DNS_TimeReached(deadline)) && !dns_found) { + delay(1); + } } if (!ip_addr_isany_val(dns_ipaddr)) { @@ -260,19 +287,29 @@ int WiFiClass32::hostByName(const char* aHostname, IPAddress& aResult, int32_t t return true; } return false; +// #endif } -int WiFiClass32::hostByName(const char* aHostname, IPAddress& aResult) +int WiFiHelper::hostByName(const char* aHostname, IPAddress& aResult) { - return hostByName(aHostname, aResult, WifiDNSGetTimeout()); + return WiFiHelper::hostByName(aHostname, aResult, WifiDNSGetTimeout()); } -void wifi_station_disconnect() { - // erase ap: empty ssid, ... - WiFi.disconnect(true, true); +#if (ESP_IDF_VERSION_MAJOR >= 5) +#include "esp_mac.h" +#endif + +String WiFiHelper::macAddress(void) { +#if (ESP_IDF_VERSION_MAJOR < 5) + return WiFi.macAddress(); +#else + uint8_t mac[6] = {0,0,0,0,0,0}; + char macStr[18] = { 0 }; + + esp_read_mac(mac, ESP_MAC_WIFI_STA); + snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return String(macStr); +#endif } -void wifi_station_dhcpc_start() { -} - -WiFiClass32 WiFi32; +#endif // ESP32 diff --git a/lib/default/WiFiHelper/src/WiFiHelper_ESP8266.cpp b/lib/default/WiFiHelper/src/WiFiHelper_ESP8266.cpp new file mode 100644 index 000000000..ab92e459b --- /dev/null +++ b/lib/default/WiFiHelper/src/WiFiHelper_ESP8266.cpp @@ -0,0 +1,80 @@ +/* + WiFi compat with ESP32 + + Copyright (C) 2021 Theo Arends / Jörg Schüler-Maroldt + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +// +#ifdef ESP8266 +#include "Arduino.h" +#include "WiFiHelper.h" + +wl_status_t WiFiHelper::begin(const char* ssid, const char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) { + return WiFi.begin(ssid, passphrase, channel, bssid, connect); +} + +wl_status_t WiFiHelper::begin(char* ssid, char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) { + return WiFi.begin(ssid, passphrase, channel, bssid, connect); +} + +wl_status_t WiFiHelper::begin() { + return WiFi.begin(); +} + +void WiFiHelper::scrubDNS(void) { +} + + +void WiFiHelper::hostname(const char* aHostname) { + WiFi.hostname(aHostname); +} + +void WiFiHelper::setSleepMode(int iSleepMode) { + WiFi.setSleepMode((WiFiSleepType_t)iSleepMode); +} + +int WiFiHelper::getPhyMode() { + return WiFi.getPhyMode(); +} + +bool WiFiHelper::setPhyMode(WiFiPhyMode_t mode) { + return WiFi.setPhyMode(mode); +} + +void WiFiHelper::setOutputPower(int n) { + WiFi.setOutputPower(n); +} +void WiFiHelper::forceSleepBegin() { + WiFi.forceSleepBegin(); +} +void WiFiHelper::forceSleepWake() { + WiFi.forceSleepWake(); +} +bool WiFiHelper::getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t* &bssid, int32_t &channel, bool &hidden_scan) { + return WiFi.getNetworkInfo(i, ssid, encType, rssi, bssid, channel, hidden_scan); +} + +int WiFiHelper::hostByName(const char* aHostname, IPAddress& aResult, int32_t timer_ms) { + return WiFi.hostByName(aHostname, aResult, timer_ms); +} +int WiFiHelper::hostByName(const char* aHostname, IPAddress& aResult) { + return WiFi.hostByName(aHostname, aResult); +} + +String WiFiHelper::macAddress(void) { + return WiFi.macAddress(); +} + +#endif // ESP8266 diff --git a/lib/lib_audio/ESP8266Audio/src/AudioFileSourceHTTPStream.h b/lib/lib_audio/ESP8266Audio/src/AudioFileSourceHTTPStream.h index 34e54663d..fc72bf909 100644 --- a/lib/lib_audio/ESP8266Audio/src/AudioFileSourceHTTPStream.h +++ b/lib/lib_audio/ESP8266Audio/src/AudioFileSourceHTTPStream.h @@ -24,6 +24,7 @@ #include #ifdef ESP32 #include + #include #else #include #endif diff --git a/lib/lib_audio/ESP8266Audio/src/AudioFileSourceICYStream.h b/lib/lib_audio/ESP8266Audio/src/AudioFileSourceICYStream.h index 97688a57d..33c0da152 100644 --- a/lib/lib_audio/ESP8266Audio/src/AudioFileSourceICYStream.h +++ b/lib/lib_audio/ESP8266Audio/src/AudioFileSourceICYStream.h @@ -24,6 +24,7 @@ #include #ifdef ESP32 #include + #include #else #include #endif diff --git a/lib/libesp32_audio/mp3_shine_esp32/COPYING b/lib/lib_audio/mp3_shine_esp32/COPYING similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/COPYING rename to lib/lib_audio/mp3_shine_esp32/COPYING diff --git a/lib/libesp32_audio/mp3_shine_esp32/LICENSE b/lib/lib_audio/mp3_shine_esp32/LICENSE similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/LICENSE rename to lib/lib_audio/mp3_shine_esp32/LICENSE diff --git a/lib/libesp32_audio/mp3_shine_esp32/README.md b/lib/lib_audio/mp3_shine_esp32/README.md similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/README.md rename to lib/lib_audio/mp3_shine_esp32/README.md diff --git a/lib/libesp32_audio/mp3_shine_esp32/changelog.txt b/lib/lib_audio/mp3_shine_esp32/changelog.txt similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/changelog.txt rename to lib/lib_audio/mp3_shine_esp32/changelog.txt diff --git a/lib/libesp32_audio/mp3_shine_esp32/component.mk b/lib/lib_audio/mp3_shine_esp32/component.mk similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/component.mk rename to lib/lib_audio/mp3_shine_esp32/component.mk diff --git a/lib/libesp32_audio/mp3_shine_esp32/library.json b/lib/lib_audio/mp3_shine_esp32/library.json similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/library.json rename to lib/lib_audio/mp3_shine_esp32/library.json diff --git a/lib/libesp32_audio/mp3_shine_esp32/library.properties b/lib/lib_audio/mp3_shine_esp32/library.properties similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/library.properties rename to lib/lib_audio/mp3_shine_esp32/library.properties diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/bitstream.cpp b/lib/lib_audio/mp3_shine_esp32/src/bitstream.cpp similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/bitstream.cpp rename to lib/lib_audio/mp3_shine_esp32/src/bitstream.cpp diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/bitstream.h b/lib/lib_audio/mp3_shine_esp32/src/bitstream.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/bitstream.h rename to lib/lib_audio/mp3_shine_esp32/src/bitstream.h diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/huffman.cpp b/lib/lib_audio/mp3_shine_esp32/src/huffman.cpp similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/huffman.cpp rename to lib/lib_audio/mp3_shine_esp32/src/huffman.cpp diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/huffman.h b/lib/lib_audio/mp3_shine_esp32/src/huffman.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/huffman.h rename to lib/lib_audio/mp3_shine_esp32/src/huffman.h diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3bitstream.cpp b/lib/lib_audio/mp3_shine_esp32/src/l3bitstream.cpp similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/l3bitstream.cpp rename to lib/lib_audio/mp3_shine_esp32/src/l3bitstream.cpp diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3bitstream.h b/lib/lib_audio/mp3_shine_esp32/src/l3bitstream.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/l3bitstream.h rename to lib/lib_audio/mp3_shine_esp32/src/l3bitstream.h diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3loop.cpp b/lib/lib_audio/mp3_shine_esp32/src/l3loop.cpp similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/l3loop.cpp rename to lib/lib_audio/mp3_shine_esp32/src/l3loop.cpp diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3loop.h b/lib/lib_audio/mp3_shine_esp32/src/l3loop.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/l3loop.h rename to lib/lib_audio/mp3_shine_esp32/src/l3loop.h diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3mdct.cpp b/lib/lib_audio/mp3_shine_esp32/src/l3mdct.cpp similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/l3mdct.cpp rename to lib/lib_audio/mp3_shine_esp32/src/l3mdct.cpp diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3mdct.h b/lib/lib_audio/mp3_shine_esp32/src/l3mdct.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/l3mdct.h rename to lib/lib_audio/mp3_shine_esp32/src/l3mdct.h diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.cpp b/lib/lib_audio/mp3_shine_esp32/src/l3subband.cpp similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/l3subband.cpp rename to lib/lib_audio/mp3_shine_esp32/src/l3subband.cpp diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.h b/lib/lib_audio/mp3_shine_esp32/src/l3subband.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/l3subband.h rename to lib/lib_audio/mp3_shine_esp32/src/l3subband.h diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/layer3.cpp b/lib/lib_audio/mp3_shine_esp32/src/layer3.cpp similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/layer3.cpp rename to lib/lib_audio/mp3_shine_esp32/src/layer3.cpp diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/layer3.h b/lib/lib_audio/mp3_shine_esp32/src/layer3.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/layer3.h rename to lib/lib_audio/mp3_shine_esp32/src/layer3.h diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/mult_mips_gcc.h b/lib/lib_audio/mp3_shine_esp32/src/mult_mips_gcc.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/mult_mips_gcc.h rename to lib/lib_audio/mp3_shine_esp32/src/mult_mips_gcc.h diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/mult_noarch_gcc.h b/lib/lib_audio/mp3_shine_esp32/src/mult_noarch_gcc.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/mult_noarch_gcc.h rename to lib/lib_audio/mp3_shine_esp32/src/mult_noarch_gcc.h diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/mult_sarm_gcc.h b/lib/lib_audio/mp3_shine_esp32/src/mult_sarm_gcc.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/mult_sarm_gcc.h rename to lib/lib_audio/mp3_shine_esp32/src/mult_sarm_gcc.h diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/mult_xtensa_gcc.h b/lib/lib_audio/mp3_shine_esp32/src/mult_xtensa_gcc.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/mult_xtensa_gcc.h rename to lib/lib_audio/mp3_shine_esp32/src/mult_xtensa_gcc.h diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/reservoir.cpp b/lib/lib_audio/mp3_shine_esp32/src/reservoir.cpp similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/reservoir.cpp rename to lib/lib_audio/mp3_shine_esp32/src/reservoir.cpp diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/reservoir.h b/lib/lib_audio/mp3_shine_esp32/src/reservoir.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/reservoir.h rename to lib/lib_audio/mp3_shine_esp32/src/reservoir.h diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/tables.cpp b/lib/lib_audio/mp3_shine_esp32/src/tables.cpp similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/tables.cpp rename to lib/lib_audio/mp3_shine_esp32/src/tables.cpp diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/tables.h b/lib/lib_audio/mp3_shine_esp32/src/tables.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/tables.h rename to lib/lib_audio/mp3_shine_esp32/src/tables.h diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/types.h b/lib/lib_audio/mp3_shine_esp32/src/types.h similarity index 100% rename from lib/libesp32_audio/mp3_shine_esp32/src/types.h rename to lib/lib_audio/mp3_shine_esp32/src/types.h diff --git a/lib/libesp32_div/TTGO_TWatch_Library/LICENSE b/lib/lib_deprecated/TTGO_TWatch_Library/LICENSE similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/LICENSE rename to lib/lib_deprecated/TTGO_TWatch_Library/LICENSE diff --git a/lib/libesp32_div/TTGO_TWatch_Library/README.MD b/lib/lib_deprecated/TTGO_TWatch_Library/README.MD similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/README.MD rename to lib/lib_deprecated/TTGO_TWatch_Library/README.MD diff --git a/lib/libesp32_div/TTGO_TWatch_Library/library.json b/lib/lib_deprecated/TTGO_TWatch_Library/library.json similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/library.json rename to lib/lib_deprecated/TTGO_TWatch_Library/library.json diff --git a/lib/libesp32_div/TTGO_TWatch_Library/library.properties b/lib/lib_deprecated/TTGO_TWatch_Library/library.properties similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/library.properties rename to lib/lib_deprecated/TTGO_TWatch_Library/library.properties diff --git a/lib/libesp32_div/TTGO_TWatch_Library/src/axp20x.cpp b/lib/lib_deprecated/TTGO_TWatch_Library/src/axp20x.cpp similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/src/axp20x.cpp rename to lib/lib_deprecated/TTGO_TWatch_Library/src/axp20x.cpp diff --git a/lib/libesp32_div/TTGO_TWatch_Library/src/axp20x.h b/lib/lib_deprecated/TTGO_TWatch_Library/src/axp20x.h similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/src/axp20x.h rename to lib/lib_deprecated/TTGO_TWatch_Library/src/axp20x.h diff --git a/lib/libesp32_div/TTGO_TWatch_Library/src/bma.cpp b/lib/lib_deprecated/TTGO_TWatch_Library/src/bma.cpp similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/src/bma.cpp rename to lib/lib_deprecated/TTGO_TWatch_Library/src/bma.cpp diff --git a/lib/libesp32_div/TTGO_TWatch_Library/src/bma.h b/lib/lib_deprecated/TTGO_TWatch_Library/src/bma.h similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/src/bma.h rename to lib/lib_deprecated/TTGO_TWatch_Library/src/bma.h diff --git a/lib/libesp32_div/TTGO_TWatch_Library/src/bma4.c b/lib/lib_deprecated/TTGO_TWatch_Library/src/bma4.c similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/src/bma4.c rename to lib/lib_deprecated/TTGO_TWatch_Library/src/bma4.c diff --git a/lib/libesp32_div/TTGO_TWatch_Library/src/bma4.h b/lib/lib_deprecated/TTGO_TWatch_Library/src/bma4.h similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/src/bma4.h rename to lib/lib_deprecated/TTGO_TWatch_Library/src/bma4.h diff --git a/lib/libesp32_div/TTGO_TWatch_Library/src/bma423.c b/lib/lib_deprecated/TTGO_TWatch_Library/src/bma423.c similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/src/bma423.c rename to lib/lib_deprecated/TTGO_TWatch_Library/src/bma423.c diff --git a/lib/libesp32_div/TTGO_TWatch_Library/src/bma423.h b/lib/lib_deprecated/TTGO_TWatch_Library/src/bma423.h similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/src/bma423.h rename to lib/lib_deprecated/TTGO_TWatch_Library/src/bma423.h diff --git a/lib/libesp32_div/TTGO_TWatch_Library/src/bma4_defs.h b/lib/lib_deprecated/TTGO_TWatch_Library/src/bma4_defs.h similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/src/bma4_defs.h rename to lib/lib_deprecated/TTGO_TWatch_Library/src/bma4_defs.h diff --git a/lib/libesp32_div/TTGO_TWatch_Library/src/i2c_bus.cpp b/lib/lib_deprecated/TTGO_TWatch_Library/src/i2c_bus.cpp similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/src/i2c_bus.cpp rename to lib/lib_deprecated/TTGO_TWatch_Library/src/i2c_bus.cpp diff --git a/lib/libesp32_div/TTGO_TWatch_Library/src/i2c_bus.h b/lib/lib_deprecated/TTGO_TWatch_Library/src/i2c_bus.h similarity index 100% rename from lib/libesp32_div/TTGO_TWatch_Library/src/i2c_bus.h rename to lib/lib_deprecated/TTGO_TWatch_Library/src/i2c_bus.h diff --git a/lib/libesp32_audio/es7210/library.json b/lib/lib_deprecated/es7210/library.json similarity index 100% rename from lib/libesp32_audio/es7210/library.json rename to lib/lib_deprecated/es7210/library.json diff --git a/lib/libesp32_audio/es7210/library.properties b/lib/lib_deprecated/es7210/library.properties similarity index 100% rename from lib/libesp32_audio/es7210/library.properties rename to lib/lib_deprecated/es7210/library.properties diff --git a/lib/libesp32_audio/es7210/src/es7210.cpp b/lib/lib_deprecated/es7210/src/es7210.cpp similarity index 100% rename from lib/libesp32_audio/es7210/src/es7210.cpp rename to lib/lib_deprecated/es7210/src/es7210.cpp diff --git a/lib/libesp32_audio/es7210/src/es7210.h b/lib/lib_deprecated/es7210/src/es7210.h similarity index 100% rename from lib/libesp32_audio/es7210/src/es7210.h rename to lib/lib_deprecated/es7210/src/es7210.h diff --git a/lib/libesp32_audio/es7243e/library.json b/lib/lib_deprecated/es7243e/library.json similarity index 100% rename from lib/libesp32_audio/es7243e/library.json rename to lib/lib_deprecated/es7243e/library.json diff --git a/lib/libesp32_audio/es7243e/library.properties b/lib/lib_deprecated/es7243e/library.properties similarity index 100% rename from lib/libesp32_audio/es7243e/library.properties rename to lib/lib_deprecated/es7243e/library.properties diff --git a/lib/libesp32_audio/es7243e/src/es7243e.cpp b/lib/lib_deprecated/es7243e/src/es7243e.cpp similarity index 100% rename from lib/libesp32_audio/es7243e/src/es7243e.cpp rename to lib/lib_deprecated/es7243e/src/es7243e.cpp diff --git a/lib/libesp32_audio/es7243e/src/es7243e.h b/lib/lib_deprecated/es7243e/src/es7243e.h similarity index 100% rename from lib/libesp32_audio/es7243e/src/es7243e.h rename to lib/lib_deprecated/es7243e/src/es7243e.h diff --git a/lib/libesp32_audio/es8156/library.json b/lib/lib_deprecated/es8156/library.json similarity index 100% rename from lib/libesp32_audio/es8156/library.json rename to lib/lib_deprecated/es8156/library.json diff --git a/lib/libesp32_audio/es8156/library.properties b/lib/lib_deprecated/es8156/library.properties similarity index 100% rename from lib/libesp32_audio/es8156/library.properties rename to lib/lib_deprecated/es8156/library.properties diff --git a/lib/libesp32_audio/es8156/src/audio_hal.h b/lib/lib_deprecated/es8156/src/audio_hal.h similarity index 100% rename from lib/libesp32_audio/es8156/src/audio_hal.h rename to lib/lib_deprecated/es8156/src/audio_hal.h diff --git a/lib/libesp32_audio/es8156/src/es8156.cpp b/lib/lib_deprecated/es8156/src/es8156.cpp similarity index 100% rename from lib/libesp32_audio/es8156/src/es8156.cpp rename to lib/lib_deprecated/es8156/src/es8156.cpp diff --git a/lib/libesp32_audio/es8156/src/es8156.h b/lib/lib_deprecated/es8156/src/es8156.h similarity index 100% rename from lib/libesp32_audio/es8156/src/es8156.h rename to lib/lib_deprecated/es8156/src/es8156.h diff --git a/lib/libesp32_audio/es8156/src/esxxx_common.h b/lib/lib_deprecated/es8156/src/esxxx_common.h similarity index 100% rename from lib/libesp32_audio/es8156/src/esxxx_common.h rename to lib/lib_deprecated/es8156/src/esxxx_common.h diff --git a/lib/libesp32_audio/es8311/library.json b/lib/lib_deprecated/es8311/library.json similarity index 100% rename from lib/libesp32_audio/es8311/library.json rename to lib/lib_deprecated/es8311/library.json diff --git a/lib/libesp32_audio/es8311/library.properties b/lib/lib_deprecated/es8311/library.properties similarity index 100% rename from lib/libesp32_audio/es8311/library.properties rename to lib/lib_deprecated/es8311/library.properties diff --git a/lib/libesp32_audio/es8311/src/es8311.cpp b/lib/lib_deprecated/es8311/src/es8311.cpp similarity index 100% rename from lib/libesp32_audio/es8311/src/es8311.cpp rename to lib/lib_deprecated/es8311/src/es8311.cpp diff --git a/lib/libesp32_audio/es8311/src/es8311.h b/lib/lib_deprecated/es8311/src/es8311.h similarity index 100% rename from lib/libesp32_audio/es8311/src/es8311.h rename to lib/lib_deprecated/es8311/src/es8311.h diff --git a/lib/libesp32_audio/wm8960/library.json b/lib/lib_deprecated/wm8960/library.json similarity index 100% rename from lib/libesp32_audio/wm8960/library.json rename to lib/lib_deprecated/wm8960/library.json diff --git a/lib/libesp32_audio/wm8960/library.properties b/lib/lib_deprecated/wm8960/library.properties similarity index 100% rename from lib/libesp32_audio/wm8960/library.properties rename to lib/lib_deprecated/wm8960/library.properties diff --git a/lib/libesp32_audio/wm8960/src/wm8960.cpp b/lib/lib_deprecated/wm8960/src/wm8960.cpp similarity index 100% rename from lib/libesp32_audio/wm8960/src/wm8960.cpp rename to lib/lib_deprecated/wm8960/src/wm8960.cpp diff --git a/lib/libesp32_audio/wm8960/src/wm8960.h b/lib/lib_deprecated/wm8960/src/wm8960.h similarity index 100% rename from lib/libesp32_audio/wm8960/src/wm8960.h rename to lib/lib_deprecated/wm8960/src/wm8960.h diff --git a/lib/lib_display/Adafruit_SH1106-gemu-1.0/Adafruit_SH1106.cpp b/lib/lib_display/Adafruit_SH1106-gemu-1.0/Adafruit_SH1106.cpp deleted file mode 100644 index ecf775c75..000000000 --- a/lib/lib_display/Adafruit_SH1106-gemu-1.0/Adafruit_SH1106.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/********************************************************************* -This is a library for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - -These displays use SPI to communicate, 4 or 5 pins are required to -interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above, and the splash screen below must be included in any redistribution -*********************************************************************/ - -/********************************************************************* -I change the adafruit SSD1306 to SH1106 - -SH1106 driver similar to SSD1306 so, just change the display() method. - -However, SH1106 driver don't provide several functions such as scroll commands. - - -*********************************************************************/ - -//#include -#ifndef __SAM3X8E__ -// #include -#endif -#include -#include -//#include <../../sonoff/settings.h> - -#include "Adafruit_SH1106.h" -#define DISPLAY_INIT_MODE 0 - -// the memory buffer for the LCD - -uint8_t *dbuff; - -Adafruit_SH1106::Adafruit_SH1106(int16_t width, int16_t height) : -Renderer(width,height) { -} - -void Adafruit_SH1106::DisplayOnff(int8_t on) { - if (on) { - SH1106_command(SH1106_DISPLAYON); - } else { - SH1106_command(SH1106_DISPLAYOFF); - } -} - -void Adafruit_SH1106::Updateframe() { - display(); -} - -void Adafruit_SH1106::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { -// ignore update mode - //if (p==DISPLAY_INIT_MODE) { - // allocate screen buffer - setRotation(rot); - invertDisplay(false); - setTextWrap(false); // Allow text to run off edges - cp437(true); - setTextFont(font); - setTextSize(size); - setTextColor(WHITE, BLACK); - setCursor(0,0); - //fillScreen(BLACK); - fillScreen(BLACK); - Updateframe(); - - disp_bpp = -1; - //} -} - -void Adafruit_SH1106::Begin(int16_t p1,int16_t p2,int16_t p3) { - begin(p1,p2,p3); -} - - -boolean Adafruit_SH1106::begin(uint8_t vccstate, uint8_t i2caddr, bool reset) { - _vccstate = vccstate; - _i2caddr = i2caddr; - - framebuffer = (uint8_t *)malloc(WIDTH * ((HEIGHT + 7) / 8)); - if (!framebuffer) return false; - - // I2C Init - Wire.begin(); - - #if defined SH1106_128_32 - // Init sequence for 128x32 OLED module - SH1106_command(SH1106_DISPLAYOFF); // 0xAE - SH1106_command(SH1106_SETDISPLAYCLOCKDIV); // 0xD5 - SH1106_command(0x80); // the suggested ratio 0x80 - SH1106_command(SH1106_SETMULTIPLEX); // 0xA8 - SH1106_command(0x1F); - SH1106_command(SH1106_SETDISPLAYOFFSET); // 0xD3 - SH1106_command(0x0); // no offset - SH1106_command(SH1106_SETSTARTLINE | 0x0); // line #0 - SH1106_command(SH1106_CHARGEPUMP); // 0x8D - if (vccstate == SH1106_EXTERNALVCC) - { SH1106_command(0x10); } - else - { SH1106_command(0x14); } - SH1106_command(SH1106_MEMORYMODE); // 0x20 - SH1106_command(0x00); // 0x0 act like ks0108 - SH1106_command(SH1106_SEGREMAP | 0x1); - SH1106_command(SH1106_COMSCANDEC); - SH1106_command(SH1106_SETCOMPINS); // 0xDA - SH1106_command(0x02); - SH1106_command(SH1106_SETCONTRAST); // 0x81 - SH1106_command(0x8F); - SH1106_command(SH1106_SETPRECHARGE); // 0xd9 - if (vccstate == SH1106_EXTERNALVCC) - { SH1106_command(0x22); } - else - { SH1106_command(0xF1); } - SH1106_command(SH1106_SETVCOMDETECT); // 0xDB - SH1106_command(0x40); - SH1106_command(SH1106_DISPLAYALLON_RESUME); // 0xA4 - SH1106_command(SH1106_NORMALDISPLAY); // 0xA6 - #endif - - #if defined SH1106_128_64 - // Init sequence for 128x64 OLED module - SH1106_command(SH1106_DISPLAYOFF); // 0xAE - SH1106_command(SH1106_SETDISPLAYCLOCKDIV); // 0xD5 - SH1106_command(0x80); // the suggested ratio 0x80 - SH1106_command(SH1106_SETMULTIPLEX); // 0xA8 - SH1106_command(0x3F); - SH1106_command(SH1106_SETDISPLAYOFFSET); // 0xD3 - SH1106_command(0x00); // no offset - - SH1106_command(SH1106_SETSTARTLINE | 0x0); // line #0 0x40 - SH1106_command(SH1106_CHARGEPUMP); // 0x8D - if (vccstate == SH1106_EXTERNALVCC) - { SH1106_command(0x10); } - else - { SH1106_command(0x14); } - SH1106_command(SH1106_MEMORYMODE); // 0x20 - SH1106_command(0x00); // 0x0 act like ks0108 - SH1106_command(SH1106_SEGREMAP | 0x1); - SH1106_command(SH1106_COMSCANDEC); - SH1106_command(SH1106_SETCOMPINS); // 0xDA - SH1106_command(0x12); - SH1106_command(SH1106_SETCONTRAST); // 0x81 - if (vccstate == SH1106_EXTERNALVCC) - { SH1106_command(0x9F); } - else - { SH1106_command(0xCF); } - SH1106_command(SH1106_SETPRECHARGE); // 0xd9 - if (vccstate == SH1106_EXTERNALVCC) - { SH1106_command(0x22); } - else - { SH1106_command(0xF1); } - SH1106_command(SH1106_SETVCOMDETECT); // 0xDB - SH1106_command(0x40); - SH1106_command(SH1106_DISPLAYALLON_RESUME); // 0xA4 - SH1106_command(SH1106_NORMALDISPLAY); // 0xA6 - #endif - - #if defined SH1106_96_16 - // Init sequence for 96x16 OLED module - SH1106_command(SH1106_DISPLAYOFF); // 0xAE - SH1106_command(SH1106_SETDISPLAYCLOCKDIV); // 0xD5 - SH1106_command(0x80); // the suggested ratio 0x80 - SH1106_command(SH1106_SETMULTIPLEX); // 0xA8 - SH1106_command(0x0F); - SH1106_command(SH1106_SETDISPLAYOFFSET); // 0xD3 - SH1106_command(0x00); // no offset - SH1106_command(SH1106_SETSTARTLINE | 0x0); // line #0 - SH1106_command(SH1106_CHARGEPUMP); // 0x8D - if (vccstate == SH1106_EXTERNALVCC) - { SH1106_command(0x10); } - else - { SH1106_command(0x14); } - SH1106_command(SH1106_MEMORYMODE); // 0x20 - SH1106_command(0x00); // 0x0 act like ks0108 - SH1106_command(SH1106_SEGREMAP | 0x1); - SH1106_command(SH1106_COMSCANDEC); - SH1106_command(SH1106_SETCOMPINS); // 0xDA - SH1106_command(0x2); //ada x12 - SH1106_command(SH1106_SETCONTRAST); // 0x81 - if (vccstate == SH1106_EXTERNALVCC) - { SH1106_command(0x10); } - else - { SH1106_command(0xAF); } - SH1106_command(SH1106_SETPRECHARGE); // 0xd9 - if (vccstate == SH1106_EXTERNALVCC) - { SH1106_command(0x22); } - else - { SH1106_command(0xF1); } - SH1106_command(SH1106_SETVCOMDETECT); // 0xDB - SH1106_command(0x40); - SH1106_command(SH1106_DISPLAYALLON_RESUME); // 0xA4 - SH1106_command(SH1106_NORMALDISPLAY); // 0xA6 - #endif - - SH1106_command(SH1106_DISPLAYON);//--turn on oled panel - - - return true; -} - - -void Adafruit_SH1106::invertDisplay(uint8_t i) { - if (i) { - SH1106_command(SH1106_INVERTDISPLAY); - } else { - SH1106_command(SH1106_NORMALDISPLAY); - } -} - -void Adafruit_SH1106::SH1106_command(uint8_t c) { - - // I2C - uint8_t control = 0x00; // Co = 0, D/C = 0 - Wire.beginTransmission(_i2caddr); - WIRE_WRITE(control); - WIRE_WRITE(c); - Wire.endTransmission(); - -} - -// Dim the display -// dim = true: display is dimmed -// dim = false: display is normal -void Adafruit_SH1106::dim(uint8_t dim) { - uint8_t contrast; - - if (dim) { - contrast = 0; // Dimmed display - } else { - if (_vccstate == SH1106_EXTERNALVCC) { - contrast = 0x9F; - } else { - contrast = 0xCF; - } - } - // the range of contrast to too small to be really useful - // it is useful to dim the display - SH1106_command(SH1106_SETCONTRAST); - SH1106_command(contrast); -} - -void Adafruit_SH1106::SH1106_data(uint8_t c) { - // I2C - uint8_t control = 0x40; // Co = 0, D/C = 1 - Wire.beginTransmission(_i2caddr); - WIRE_WRITE(control); - WIRE_WRITE(c); - Wire.endTransmission(); -} - -void Adafruit_SH1106::display(void) { - SH1106_command(SH1106_SETLOWCOLUMN | 0x0); // low col = 0 - SH1106_command(SH1106_SETHIGHCOLUMN | 0x0); // hi col = 0 - SH1106_command(SH1106_SETSTARTLINE | 0x0); // line #0 - // I2C - //height >>= 3; - //width >>= 3; - byte height=64; - byte width=132; - byte m_row = 0; - byte m_col = 2; - - - height >>= 3; - width >>= 3; - //Serial.println(width); - - int p = 0; - - byte i, j, k =0; - - for ( i = 0; i < height; i++) { - - // send a bunch of data in one xmission - SH1106_command(0xB0 + i + m_row);//set page address - SH1106_command(m_col & 0xf);//set lower column address - SH1106_command(0x10 | (m_col >> 4));//set higher column address - - for( j = 0; j < 8; j++){ - Wire.beginTransmission(_i2caddr); - Wire.write(0x40); - for ( k = 0; k < width; k++, p++) { - Wire.write(framebuffer[p]); - } - Wire.endTransmission(); - } - } - -} - -// clear everything -void Adafruit_SH1106::clearDisplay(void) { - memset(framebuffer, 0, (SH1106_LCDWIDTH*SH1106_LCDHEIGHT/8)); -} diff --git a/lib/lib_display/Adafruit_SH1106-gemu-1.0/Adafruit_SH1106.h b/lib/lib_display/Adafruit_SH1106-gemu-1.0/Adafruit_SH1106.h deleted file mode 100644 index 74196d1a3..000000000 --- a/lib/lib_display/Adafruit_SH1106-gemu-1.0/Adafruit_SH1106.h +++ /dev/null @@ -1,154 +0,0 @@ -/********************************************************************* -This is a library for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - -These displays use SPI to communicate, 4 or 5 pins are required to -interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above, and the splash screen must be included in any redistribution -*********************************************************************/ - -/********************************************************************* -I change the adafruit SSD1306 to SH1106 - -SH1106 driver similar to SSD1306 so, just change the display() method. - -However, SH1106 driver don't provide several functions such as scroll commands. - - -*********************************************************************/ - -#if ARDUINO >= 100 - #include "Arduino.h" - #define WIRE_WRITE Wire.write -#else - #include "WProgram.h" - #define WIRE_WRITE Wire.send -#endif - -#include - -#define BLACK 0 -#define WHITE 1 -#define INVERSE 2 - -#define SH1106_I2C_ADDRESS 0x3C // 011110+SA0+RW - 0x3C or 0x3D -// Address for 128x32 is 0x3C -// Address for 128x64 is 0x3D (default) or 0x3C (if SA0 is grounded) - -/*========================================================================= - SH1106 Displays - ----------------------------------------------------------------------- - The driver is used in multiple displays (128x64, 128x32, etc.). - Select the appropriate display below to create an appropriately - sized framebuffer, etc. - - SH1106_128_64 128x64 pixel display - - SH1106_128_32 128x32 pixel display - - SH1106_96_16 - - -----------------------------------------------------------------------*/ - #define SH1106_128_64 -// #define SH1106_128_32 -// #define SH1106_96_16 -/*=========================================================================*/ - -#if defined SH1106_128_64 && defined SH1106_128_32 - #error "Only one SH1106 display can be specified at once in SH1106.h" -#endif -#if !defined SH1106_128_64 && !defined SH1106_128_32 && !defined SH1106_96_16 - #error "At least one SH1106 display must be specified in SH1106.h" -#endif - -#if defined SH1106_128_64 - #define SH1106_LCDWIDTH 128 - #define SH1106_LCDHEIGHT 64 -#endif -#if defined SH1106_128_32 - #define SH1106_LCDWIDTH 128 - #define SH1106_LCDHEIGHT 32 -#endif -#if defined SH1106_96_16 - #define SH1106_LCDWIDTH 96 - #define SH1106_LCDHEIGHT 16 -#endif - -#define SH1106_SETCONTRAST 0x81 -#define SH1106_DISPLAYALLON_RESUME 0xA4 -#define SH1106_DISPLAYALLON 0xA5 -#define SH1106_NORMALDISPLAY 0xA6 -#define SH1106_INVERTDISPLAY 0xA7 -#define SH1106_DISPLAYOFF 0xAE -#define SH1106_DISPLAYON 0xAF - -#define SH1106_SETDISPLAYOFFSET 0xD3 -#define SH1106_SETCOMPINS 0xDA - -#define SH1106_SETVCOMDETECT 0xDB - -#define SH1106_SETDISPLAYCLOCKDIV 0xD5 -#define SH1106_SETPRECHARGE 0xD9 - -#define SH1106_SETMULTIPLEX 0xA8 - -#define SH1106_SETLOWCOLUMN 0x00 -#define SH1106_SETHIGHCOLUMN 0x10 - -#define SH1106_SETSTARTLINE 0x40 - -#define SH1106_MEMORYMODE 0x20 -#define SH1106_COLUMNADDR 0x21 -#define SH1106_PAGEADDR 0x22 - -#define SH1106_COMSCANINC 0xC0 -#define SH1106_COMSCANDEC 0xC8 - -#define SH1106_SEGREMAP 0xA0 - -#define SH1106_CHARGEPUMP 0x8D - -#define SH1106_EXTERNALVCC 0x1 -#define SH1106_SWITCHCAPVCC 0x2 - -// Scrolling #defines -#define SH1106_ACTIVATE_SCROLL 0x2F -#define SH1106_DEACTIVATE_SCROLL 0x2E -#define SH1106_SET_VERTICAL_SCROLL_AREA 0xA3 -#define SH1106_RIGHT_HORIZONTAL_SCROLL 0x26 -#define SH1106_LEFT_HORIZONTAL_SCROLL 0x27 -#define SH1106_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 -#define SH1106_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A - -class Adafruit_SH1106 : public Renderer { - public: - Adafruit_SH1106(int16_t width, int16_t height); - - boolean begin(uint8_t switchvcc = SH1106_SWITCHCAPVCC, uint8_t i2caddr = SH1106_I2C_ADDRESS, bool reset=true); - void SH1106_command(uint8_t c); - void SH1106_data(uint8_t c); - - void clearDisplay(void); - void invertDisplay(uint8_t i); - void display(); - - - void DisplayOnff(int8_t on); - void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font); - void Begin(int16_t p1,int16_t p2,int16_t p3); - void Updateframe(); - void dim(uint8_t contrast); - - private: - int8_t _i2caddr, _vccstate, rst; - -}; diff --git a/lib/lib_display/Adafruit_SH1106-gemu-1.0/LICENSE.txt b/lib/lib_display/Adafruit_SH1106-gemu-1.0/LICENSE.txt deleted file mode 100644 index f6a0f22b8..000000000 --- a/lib/lib_display/Adafruit_SH1106-gemu-1.0/LICENSE.txt +++ /dev/null @@ -1,26 +0,0 @@ -Software License Agreement (BSD License) - -Copyright (c) 2012, Adafruit Industries -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holders nor the -names of its contributors may be used to endorse or promote products -derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/lib_display/Adafruit_SH1106-gemu-1.0/README.md b/lib/lib_display/Adafruit_SH1106-gemu-1.0/README.md deleted file mode 100644 index c457a3cc8..000000000 --- a/lib/lib_display/Adafruit_SH1106-gemu-1.0/README.md +++ /dev/null @@ -1,16 +0,0 @@ -Adafruit_SH1106 -=============== - -Adafruit graphic library for SH1106 driver lcds. - -some small oled lcd use SH1106 driver. - -I change the adafruit SSD1306 to SH1106 - -SH1106 driver similar to SSD1306. thus, just change the display() method. - -However, SH1106 driver don't provide several functions such as scroll commands. - - - Adafruit-GFX-Library - https://github.com/adafruit/Adafruit-GFX-Library diff --git a/lib/lib_display/Adafruit_SH1106-gemu-1.0/examples/sh1106_128x64_i2c/sh1106_128x64_i2c.ino b/lib/lib_display/Adafruit_SH1106-gemu-1.0/examples/sh1106_128x64_i2c/sh1106_128x64_i2c.ino deleted file mode 100644 index 2b2c90368..000000000 --- a/lib/lib_display/Adafruit_SH1106-gemu-1.0/examples/sh1106_128x64_i2c/sh1106_128x64_i2c.ino +++ /dev/null @@ -1,363 +0,0 @@ -/********************************************************************* -This is an example for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - -This example is for a 128x64 size display using I2C to communicate -3 pins are required to interface (2 I2C and one reset) - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above, and the splash screen must be included in any redistribution -*********************************************************************/ - -/********************************************************************* -I change the adafruit SSD1306 to SH1106 - -SH1106 driver don't provide several functions such as scroll commands. - -*********************************************************************/ - -#include -#include -#include -#include - -#define OLED_RESET 4 -Adafruit_SH1106 display(OLED_RESET); - -#define NUMFLAKES 10 -#define XPOS 0 -#define YPOS 1 -#define DELTAY 2 - - -#define LOGO16_GLCD_HEIGHT 16 -#define LOGO16_GLCD_WIDTH 16 -static const unsigned char PROGMEM logo16_glcd_bmp[] = -{ B00000000, B11000000, - B00000001, B11000000, - B00000001, B11000000, - B00000011, B11100000, - B11110011, B11100000, - B11111110, B11111000, - B01111110, B11111111, - B00110011, B10011111, - B00011111, B11111100, - B00001101, B01110000, - B00011011, B10100000, - B00111111, B11100000, - B00111111, B11110000, - B01111100, B11110000, - B01110000, B01110000, - B00000000, B00110000 }; - -#if (SH1106_LCDHEIGHT != 64) -#error("Height incorrect, please fix Adafruit_SH1106.h!"); -#endif - -void setup() { - Serial.begin(9600); - - // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) - display.begin(SH1106_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3D (for the 128x64) - // init done - - // Show image buffer on the display hardware. - // Since the buffer is intialized with an Adafruit splashscreen - // internally, this will display the splashscreen. - display.display(); - delay(2000); - - // Clear the buffer. - display.clearDisplay(); - - // draw a single pixel - display.drawPixel(10, 10, WHITE); - // Show the display buffer on the hardware. - // NOTE: You _must_ call display after making any drawing commands - // to make them visible on the display hardware! - display.display(); - delay(2000); - display.clearDisplay(); - - // draw many lines - testdrawline(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw rectangles - testdrawrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw multiple rectangles - testfillrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw mulitple circles - testdrawcircle(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw a white circle, 10 pixel radius - display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); - display.display(); - delay(2000); - display.clearDisplay(); - - testdrawroundrect(); - delay(2000); - display.clearDisplay(); - - testfillroundrect(); - delay(2000); - display.clearDisplay(); - - testdrawtriangle(); - delay(2000); - display.clearDisplay(); - - testfilltriangle(); - delay(2000); - display.clearDisplay(); - - // draw the first ~12 characters in the font - testdrawchar(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw scrolling text - /* testscrolltext(); - delay(2000); - display.clearDisplay();*/ - - // text display tests - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - display.println("Hello, world!"); - display.setTextColor(BLACK, WHITE); // 'inverted' text - display.println(3.141592); - display.setTextSize(2); - display.setTextColor(WHITE); - display.print("0x"); display.println(0xDEADBEEF, HEX); - display.display(); - delay(2000); - - // miniature bitmap display - display.clearDisplay(); - display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); - display.display(); - - // invert the display - display.invertDisplay(true); - delay(1000); - display.invertDisplay(false); - delay(1000); - - // draw a bitmap icon and 'animate' movement - testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); -} - - -void loop() { - -} - - -void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { - uint8_t icons[NUMFLAKES][3]; - - // initialize - for (uint8_t f=0; f< NUMFLAKES; f++) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - - Serial.print("x: "); - Serial.print(icons[f][XPOS], DEC); - Serial.print(" y: "); - Serial.print(icons[f][YPOS], DEC); - Serial.print(" dy: "); - Serial.println(icons[f][DELTAY], DEC); - } - - while (1) { - // draw each icon - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE); - } - display.display(); - delay(200); - - // then erase it + move it - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK); - // move it - icons[f][YPOS] += icons[f][DELTAY]; - // if its gone, reinit - if (icons[f][YPOS] > display.height()) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - } - } - } -} - - -void testdrawchar(void) { - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - - for (uint8_t i=0; i < 168; i++) { - if (i == '\n') continue; - display.write(i); - if ((i > 0) && (i % 21 == 0)) - display.println(); - } - display.display(); -} - -void testdrawcircle(void) { - for (int16_t i=0; i0; i-=5) { - display.fillTriangle(display.width()/2, display.height()/2-i, - display.width()/2-i, display.height()/2+i, - display.width()/2+i, display.height()/2+i, WHITE); - if (color == WHITE) color = BLACK; - else color = WHITE; - display.display(); - } -} - -void testdrawroundrect(void) { - for (int16_t i=0; i=0; i-=4) { - display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=display.width()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); - display.display(); - } - for (int16_t i=display.height()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=0; i http://www.adafruit.com/category/63_98 - -This example is for a 128x64 size display using SPI to communicate -4 or 5 pins are required to interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above, and the splash screen must be included in any redistribution -*********************************************************************/ - -#include -#include -#include -#include - -// If using software SPI (the default case): -#define OLED_MOSI 9 -#define OLED_CLK 10 -#define OLED_DC 11 -#define OLED_CS 12 -#define OLED_RESET 13 -Adafruit_SH1106 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); - -/* Uncomment this block to use hardware SPI -#define OLED_DC 6 -#define OLED_CS 7 -#define OLED_RESET 8 -Adafruit_SH1106 display(OLED_DC, OLED_RESET, OLED_CS); -*/ - -#define NUMFLAKES 10 -#define XPOS 0 -#define YPOS 1 -#define DELTAY 2 - -#define LOGO16_GLCD_HEIGHT 16 -#define LOGO16_GLCD_WIDTH 16 -static const unsigned char PROGMEM logo16_glcd_bmp[] = -{ B00000000, B11000000, - B00000001, B11000000, - B00000001, B11000000, - B00000011, B11100000, - B11110011, B11100000, - B11111110, B11111000, - B01111110, B11111111, - B00110011, B10011111, - B00011111, B11111100, - B00001101, B01110000, - B00011011, B10100000, - B00111111, B11100000, - B00111111, B11110000, - B01111100, B11110000, - B01110000, B01110000, - B00000000, B00110000 }; - -#if (SH1106_LCDHEIGHT != 64) -#error("Height incorrect, please fix Adafruit_SH1106.h!"); -#endif - -void setup() { - Serial.begin(9600); - - // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) - display.begin(SH1106_SWITCHCAPVCC); - // init done - - // Show image buffer on the display hardware. - // Since the buffer is intialized with an Adafruit splashscreen - // internally, this will display the splashscreen. - display.display(); - delay(2000); - - // Clear the buffer. - display.clearDisplay(); - - // draw a single pixel - display.drawPixel(10, 10, WHITE); - // Show the display buffer on the hardware. - // NOTE: You _must_ call display after making any drawing commands - // to make them visible on the display hardware! - display.display(); - delay(2000); - display.clearDisplay(); - - // draw many lines - testdrawline(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw rectangles - testdrawrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw multiple rectangles - testfillrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw mulitple circles - testdrawcircle(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw a white circle, 10 pixel radius - display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); - display.display(); - delay(2000); - display.clearDisplay(); - - testdrawroundrect(); - delay(2000); - display.clearDisplay(); - - testfillroundrect(); - delay(2000); - display.clearDisplay(); - - testdrawtriangle(); - delay(2000); - display.clearDisplay(); - - testfilltriangle(); - delay(2000); - display.clearDisplay(); - - // draw the first ~12 characters in the font - testdrawchar(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw scrolling text - /*testscrolltext(); - delay(2000); - display.clearDisplay();*/ - - // text display tests - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - display.println("Hello, world!"); - display.setTextColor(BLACK, WHITE); // 'inverted' text - display.println(3.141592); - display.setTextSize(2); - display.setTextColor(WHITE); - display.print("0x"); display.println(0xDEADBEEF, HEX); - display.display(); - delay(2000); - - // miniature bitmap display - display.clearDisplay(); - display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); - display.display(); - - // invert the display - display.invertDisplay(true); - delay(1000); - display.invertDisplay(false); - delay(1000); - - // draw a bitmap icon and 'animate' movement - testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); -} - - -void loop() { - -} - - -void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { - uint8_t icons[NUMFLAKES][3]; - - // initialize - for (uint8_t f=0; f< NUMFLAKES; f++) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - - Serial.print("x: "); - Serial.print(icons[f][XPOS], DEC); - Serial.print(" y: "); - Serial.print(icons[f][YPOS], DEC); - Serial.print(" dy: "); - Serial.println(icons[f][DELTAY], DEC); - } - - while (1) { - // draw each icon - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE); - } - display.display(); - delay(200); - - // then erase it + move it - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK); - // move it - icons[f][YPOS] += icons[f][DELTAY]; - // if its gone, reinit - if (icons[f][YPOS] > display.height()) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - } - } - } -} - - -void testdrawchar(void) { - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - - for (uint8_t i=0; i < 168; i++) { - if (i == '\n') continue; - display.write(i); - if ((i > 0) && (i % 21 == 0)) - display.println(); - } - display.display(); -} - -void testdrawcircle(void) { - for (int16_t i=0; i0; i-=5) { - display.fillTriangle(display.width()/2, display.height()/2-i, - display.width()/2-i, display.height()/2+i, - display.width()/2+i, display.height()/2+i, WHITE); - if (color == WHITE) color = BLACK; - else color = WHITE; - display.display(); - } -} - -void testdrawroundrect(void) { - for (int16_t i=0; i=0; i-=4) { - display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=display.width()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); - display.display(); - } - for (int16_t i=display.height()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=0; i -sentence=SH1106 -paragraph=SH1106 -category=Display -url= -architectures=* diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/.github/ISSUE_TEMPLATE.md b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index f0e26146f..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,46 +0,0 @@ -Thank you for opening an issue on an Adafruit Arduino library repository. To -improve the speed of resolution please review the following guidelines and -common troubleshooting steps below before creating the issue: - -- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use - the forums at http://forums.adafruit.com to ask questions and troubleshoot why - something isn't working as expected. In many cases the problem is a common issue - that you will more quickly receive help from the forum community. GitHub issues - are meant for known defects in the code. If you don't know if there is a defect - in the code then start with troubleshooting on the forum first. - -- **If following a tutorial or guide be sure you didn't miss a step.** Carefully - check all of the steps and commands to run have been followed. Consult the - forum if you're unsure or have questions about steps in a guide/tutorial. - -- **For Arduino projects check these very common issues to ensure they don't apply**: - - - For uploading sketches or communicating with the board make sure you're using - a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes - very hard to tell the difference between a data and charge cable! Try using the - cable with other devices or swapping to another cable to confirm it is not - the problem. - - - **Be sure you are supplying adequate power to the board.** Check the specs of - your board and plug in an external power supply. In many cases just - plugging a board into your computer is not enough to power it and other - peripherals. - - - **Double check all soldering joints and connections.** Flakey connections - cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. - - - **Ensure you are using an official Arduino or Adafruit board.** We can't - guarantee a clone board will have the same functionality and work as expected - with this code and don't support them. - -If you're sure this issue is a defect in the code and checked the steps above -please fill in the following fields to provide enough troubleshooting information. -You may delete the guideline and text above to just leave the following details: - -- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** - -- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO - VERSION HERE** - -- List the steps to reproduce the problem below (if possible attach a sketch or - copy the sketch code in too): **LIST REPRO STEPS BELOW** diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/.github/PULL_REQUEST_TEMPLATE.md b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 7b641eb86..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,26 +0,0 @@ -Thank you for creating a pull request to contribute to Adafruit's GitHub code! -Before you open the request please review the following guidelines and tips to -help it be more easily integrated: - -- **Describe the scope of your change--i.e. what the change does and what parts - of the code were modified.** This will help us understand any risks of integrating - the code. - -- **Describe any known limitations with your change.** For example if the change - doesn't apply to a supported platform of the library please mention it. - -- **Please run any tests or examples that can exercise your modified code.** We - strive to not break users of the code and running tests/examples helps with this - process. - -Thank you again for contributing! We will try to test and integrate the change -as soon as we can, but be aware we have many GitHub repositories to manage and -can't immediately respond to every request. There is no need to bump or check in -on a pull request (it will clutter the discussion of the request). - -Also don't be worried if the request is closed or not integrated--sometimes the -priorities of Adafruit's GitHub code (education, ease of use) might not match the -priorities of the pull request. Don't fret, the open source community thrives on -forks and GitHub makes it easy to keep your changes in a forked repo. - -After reviewing the guidelines above you can delete this text from the pull request. diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/.gitignore b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/.gitignore deleted file mode 100644 index c2a26c038..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Our handy .gitignore for automation ease -Doxyfile* -doxygen_sqlite3.db -html diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/.travis.yml b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/.travis.yml deleted file mode 100644 index 1d9184e52..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -language: c -sudo: false -cache: - directories: - - ~/arduino_ide - - ~/.arduino15/packages/ -git: - depth: false - quiet: true -env: - global: - - ARDUINO_IDE_VERSION="1.8.5" - - PRETTYNAME="Adafruit SSD1306" -# Optional, will default to "$TRAVIS_BUILD_DIR/Doxyfile" -# - DOXYFILE: $TRAVIS_BUILD_DIR/Doxyfile - -before_install: - - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh) - -install: - - arduino --install-library "Adafruit GFX Library" - -script: - - build_main_platforms - -# Generate and deploy documentation -after_success: - - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/library_check.sh) - - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/doxy_gen_and_deploy.sh) diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/Adafruit_SSD1306.cpp b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/Adafruit_SSD1306.cpp deleted file mode 100644 index 2a5928ad3..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/Adafruit_SSD1306.cpp +++ /dev/null @@ -1,1173 +0,0 @@ -/*! - * @file Adafruit_SSD1306.cpp - * - * @mainpage Arduino library for monochrome OLEDs based on SSD1306 drivers. - * - * @section intro_sec Introduction - * - * This is documentation for Adafruit's SSD1306 library for monochrome - * OLED displays: http://www.adafruit.com/category/63_98 - * - * These displays use I2C or SPI to communicate. I2C requires 2 pins - * (SCL+SDA) and optionally a RESET pin. SPI requires 4 pins (MOSI, SCK, - * select, data/command) and optionally a reset pin. Hardware SPI or - * 'bitbang' software SPI are both supported. - * - * Adafruit invests time and resources providing this open source code, - * please support Adafruit and open-source hardware by purchasing - * products from Adafruit! - * - * @section dependencies Dependencies - * - * This library depends on - * Adafruit_GFX being present on your system. Please make sure you have - * installed the latest version before using this library. - * - * @section author Author - * - * Written by Limor Fried/Ladyada for Adafruit Industries, with - * contributions from the open source community. - * - * @section license License - * - * BSD license, all text above, and the splash screen included below, - * must be included in any redistribution. - * - */ - -#ifdef __AVR__ - #include -#elif defined(ESP8266) || defined(ESP32) - #include -#else - #define pgm_read_byte(addr) \ - (*(const unsigned char *)(addr)) ///< PROGMEM workaround for non-AVR -#endif - -#if !defined(__ARM_ARCH) && !defined(ENERGIA) && !defined(ESP8266) && !defined(ESP32) && !defined(__arc__) - #include -#endif - -#include -#include "Adafruit_SSD1306.h" -#include "splash.h" - -// SOME DEFINES AND STATIC VARIABLES USED INTERNALLY ----------------------- - -#if defined(BUFFER_LENGTH) - #define WIRE_MAX BUFFER_LENGTH ///< AVR or similar Wire lib -#elif defined(SERIAL_BUFFER_SIZE) - #define WIRE_MAX (SERIAL_BUFFER_SIZE-1) ///< Newer Wire uses RingBuffer -#else - #define WIRE_MAX 32 ///< Use common Arduino core default -#endif - -#define ssd1306_swap(a, b) \ - (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) ///< No-temp-var swap operation - -#if ARDUINO >= 100 - #define WIRE_WRITE wire->write ///< Wire write function in recent Arduino lib -#else - #define WIRE_WRITE wire->send ///< Wire write function in older Arduino lib -#endif - -#ifdef HAVE_PORTREG - #define SSD1306_SELECT *csPort &= ~csPinMask; ///< Device select - #define SSD1306_DESELECT *csPort |= csPinMask; ///< Device deselect - #define SSD1306_MODE_COMMAND *dcPort &= ~dcPinMask; ///< Command mode - #define SSD1306_MODE_DATA *dcPort |= dcPinMask; ///< Data mode -#else - #define SSD1306_SELECT digitalWrite(csPin, LOW); ///< Device select - #define SSD1306_DESELECT digitalWrite(csPin, HIGH); ///< Device deselect - #define SSD1306_MODE_COMMAND digitalWrite(dcPin, LOW); ///< Command mode - #define SSD1306_MODE_DATA digitalWrite(dcPin, HIGH); ///< Data mode -#endif - -#if (ARDUINO >= 157) && !defined(ARDUINO_STM32_FEATHER) - #define SETWIRECLOCK wire->setClock(wireClk) ///< Set before I2C transfer - #define RESWIRECLOCK wire->setClock(restoreClk) ///< Restore after I2C xfer -#else // setClock() is not present in older Arduino Wire lib (or WICED) - #define SETWIRECLOCK ///< Dummy stand-in define - #define RESWIRECLOCK ///< keeps compiler happy -#endif - -#if defined(SPI_HAS_TRANSACTION) - #define SPI_TRANSACTION_START spi->beginTransaction(spiSettings) ///< Pre-SPI - #define SPI_TRANSACTION_END spi->endTransaction() ///< Post-SPI -#else // SPI transactions likewise not present in older Arduino SPI lib - #define SPI_TRANSACTION_START ///< Dummy stand-in define - #define SPI_TRANSACTION_END ///< keeps compiler happy -#endif - -// The definition of 'transaction' is broadened a bit in the context of -// this library -- referring not just to SPI transactions (if supported -// in the version of the SPI library being used), but also chip select -// (if SPI is being used, whether hardware or soft), and also to the -// beginning and end of I2C transfers (the Wire clock may be sped up before -// issuing data to the display, then restored to the default rate afterward -// so other I2C device types still work). All of these are encapsulated -// in the TRANSACTION_* macros. - -// Check first if Wire, then hardware SPI, then soft SPI: -#define TRANSACTION_START \ - if(wire) { \ - SETWIRECLOCK; \ - } else { \ - if(spi) { \ - SPI_TRANSACTION_START; \ - } \ - SSD1306_SELECT; \ - } ///< Wire, SPI or bitbang transfer setup -#define TRANSACTION_END \ - if(wire) { \ - RESWIRECLOCK; \ - } else { \ - SSD1306_DESELECT; \ - if(spi) { \ - SPI_TRANSACTION_END; \ - } \ - } ///< Wire, SPI or bitbang transfer end - -// CONSTRUCTORS, DESTRUCTOR ------------------------------------------------ - -/*! - @brief Constructor for I2C-interfaced SSD1306 displays. - @param w - Display width in pixels - @param h - Display height in pixels - @param twi - Pointer to an existing TwoWire instance (e.g. &Wire, the - microcontroller's primary I2C bus). - @param rst_pin - Reset pin (using Arduino pin numbering), or -1 if not used - (some displays might be wired to share the microcontroller's - reset pin). - @param clkDuring - Speed (in Hz) for Wire transmissions in SSD1306 library calls. - Defaults to 400000 (400 KHz), a known 'safe' value for most - microcontrollers, and meets the SSD1306 datasheet spec. - Some systems can operate I2C faster (800 KHz for ESP32, 1 MHz - for many other 32-bit MCUs), and some (perhaps not all) - SSD1306's can work with this -- so it's optionally be specified - here and is not a default behavior. (Ignored if using pre-1.5.7 - Arduino software, which operates I2C at a fixed 100 KHz.) - @param clkAfter - Speed (in Hz) for Wire transmissions following SSD1306 library - calls. Defaults to 100000 (100 KHz), the default Arduino Wire - speed. This is done rather than leaving it at the 'during' speed - because other devices on the I2C bus might not be compatible - with the faster rate. (Ignored if using pre-1.5.7 Arduino - software, which operates I2C at a fixed 100 KHz.) - @return Adafruit_SSD1306 object. - @note Call the object's begin() function before use -- buffer - allocation is performed there! -*/ -Adafruit_SSD1306::Adafruit_SSD1306(uint8_t w, uint8_t h, TwoWire *twi, - int8_t rst_pin, uint32_t clkDuring, uint32_t clkAfter) : - Renderer(w, h), spi(NULL), wire(twi ? twi : &Wire), xbuffer(NULL), - mosiPin(-1), clkPin(-1), dcPin(-1), csPin(-1), rstPin(rst_pin), - wireClk(clkDuring), restoreClk(clkAfter) { -} - -/*! - @brief Constructor for SPI SSD1306 displays, using software (bitbang) - SPI. - @param w - Display width in pixels - @param h - Display height in pixels - @param mosi_pin - MOSI (master out, slave in) pin (using Arduino pin numbering). - This transfers serial data from microcontroller to display. - @param sclk_pin - SCLK (serial clock) pin (using Arduino pin numbering). - This clocks each bit from MOSI. - @param dc_pin - Data/command pin (using Arduino pin numbering), selects whether - display is receiving commands (low) or data (high). - @param rst_pin - Reset pin (using Arduino pin numbering), or -1 if not used - (some displays might be wired to share the microcontroller's - reset pin). - @param cs_pin - Chip-select pin (using Arduino pin numbering) for sharing the - bus with other devices. Active low. - @return Adafruit_SSD1306 object. - @note Call the object's begin() function before use -- buffer - allocation is performed there! -*/ -Adafruit_SSD1306::Adafruit_SSD1306(uint8_t w, uint8_t h, - int8_t mosi_pin, int8_t sclk_pin, int8_t dc_pin, int8_t rst_pin, - int8_t cs_pin) : Renderer(w, h), spi(NULL), wire(NULL), xbuffer(NULL), - mosiPin(mosi_pin), clkPin(sclk_pin), dcPin(dc_pin), csPin(cs_pin), - rstPin(rst_pin) { -} - -/*! - @brief Constructor for SPI SSD1306 displays, using native hardware SPI. - @param w - Display width in pixels - @param h - Display height in pixels - @param spi - Pointer to an existing SPIClass instance (e.g. &SPI, the - microcontroller's primary SPI bus). - @param dc_pin - Data/command pin (using Arduino pin numbering), selects whether - display is receiving commands (low) or data (high). - @param rst_pin - Reset pin (using Arduino pin numbering), or -1 if not used - (some displays might be wired to share the microcontroller's - reset pin). - @param cs_pin - Chip-select pin (using Arduino pin numbering) for sharing the - bus with other devices. Active low. - @param bitrate - SPI clock rate for transfers to this display. Default if - unspecified is 8000000UL (8 MHz). - @return Adafruit_SSD1306 object. - @note Call the object's begin() function before use -- buffer - allocation is performed there! -*/ -Adafruit_SSD1306::Adafruit_SSD1306(uint8_t w, uint8_t h, SPIClass *spi, - int8_t dc_pin, int8_t rst_pin, int8_t cs_pin, uint32_t bitrate) : - Renderer(w, h), spi(spi ? spi : &SPI), wire(NULL), xbuffer(NULL), - mosiPin(-1), clkPin(-1), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin) { -#ifdef SPI_HAS_TRANSACTION - spiSettings = SPISettings(bitrate, MSBFIRST, SPI_MODE0); -#endif -} - -/*! - @brief DEPRECATED constructor for SPI SSD1306 displays, using software - (bitbang) SPI. Provided for older code to maintain compatibility - with the current library. Screen size is determined by enabling - one of the SSD1306_* size defines in Adafruit_SSD1306.h. New - code should NOT use this. - @param mosi_pin - MOSI (master out, slave in) pin (using Arduino pin numbering). - This transfers serial data from microcontroller to display. - @param sclk_pin - SCLK (serial clock) pin (using Arduino pin numbering). - This clocks each bit from MOSI. - @param dc_pin - Data/command pin (using Arduino pin numbering), selects whether - display is receiving commands (low) or data (high). - @param rst_pin - Reset pin (using Arduino pin numbering), or -1 if not used - (some displays might be wired to share the microcontroller's - reset pin). - @param cs_pin - Chip-select pin (using Arduino pin numbering) for sharing the - bus with other devices. Active low. - @return Adafruit_SSD1306 object. - @note Call the object's begin() function before use -- buffer - allocation is performed there! -*/ -Adafruit_SSD1306::Adafruit_SSD1306(int8_t mosi_pin, int8_t sclk_pin, - int8_t dc_pin, int8_t rst_pin, int8_t cs_pin) : - Renderer(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT), spi(NULL), wire(NULL), - xbuffer(NULL), mosiPin(mosi_pin), clkPin(sclk_pin), dcPin(dc_pin), - csPin(cs_pin), rstPin(rst_pin) { -} - -/*! - @brief DEPRECATED constructor for SPI SSD1306 displays, using native - hardware SPI. Provided for older code to maintain compatibility - with the current library. Screen size is determined by enabling - one of the SSD1306_* size defines in Adafruit_SSD1306.h. New - code should NOT use this. Only the primary SPI bus is supported, - and bitrate is fixed at 8 MHz. - @param dc_pin - Data/command pin (using Arduino pin numbering), selects whether - display is receiving commands (low) or data (high). - @param rst_pin - Reset pin (using Arduino pin numbering), or -1 if not used - (some displays might be wired to share the microcontroller's - reset pin). - @param cs_pin - Chip-select pin (using Arduino pin numbering) for sharing the - bus with other devices. Active low. - @return Adafruit_SSD1306 object. - @note Call the object's begin() function before use -- buffer - allocation is performed there! -*/ -Adafruit_SSD1306::Adafruit_SSD1306(int8_t dc_pin, int8_t rst_pin, - int8_t cs_pin) : Renderer(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT), - spi(&SPI), wire(NULL), xbuffer(NULL), mosiPin(-1), clkPin(-1), - dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin) { -#ifdef SPI_HAS_TRANSACTION - spiSettings = SPISettings(8000000, MSBFIRST, SPI_MODE0); -#endif -} - -/*! - @brief DEPRECATED constructor for I2C SSD1306 displays. Provided for - older code to maintain compatibility with the current library. - Screen size is determined by enabling one of the SSD1306_* size - defines in Adafruit_SSD1306.h. New code should NOT use this. - Only the primary I2C bus is supported. - @param rst_pin - Reset pin (using Arduino pin numbering), or -1 if not used - (some displays might be wired to share the microcontroller's - reset pin). - @return Adafruit_SSD1306 object. - @note Call the object's begin() function before use -- buffer - allocation is performed there! -*/ -Adafruit_SSD1306::Adafruit_SSD1306(int8_t rst_pin) : - Renderer(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT), spi(NULL), wire(&Wire), - xbuffer(NULL), mosiPin(-1), clkPin(-1), dcPin(-1), csPin(-1), - rstPin(rst_pin) { -} - -/*! - @brief Destructor for Adafruit_SSD1306 object. -*/ -Adafruit_SSD1306::~Adafruit_SSD1306(void) { - if (framebuffer) { - free (framebuffer); - framebuffer = NULL; - } -} - -// LOW-LEVEL UTILS --------------------------------------------------------- - -// Issue single byte out SPI, either soft or hardware as appropriate. -// SPI transaction/selection must be performed in calling function. -inline void Adafruit_SSD1306::SPIwrite(uint8_t d) { - if(spi) { - (void)spi->transfer(d); - } else { - for(uint8_t bit = 0x80; bit; bit >>= 1) { -#ifdef HAVE_PORTREG - if(d & bit) *mosiPort |= mosiPinMask; - else *mosiPort &= ~mosiPinMask; - *clkPort |= clkPinMask; // Clock high - *clkPort &= ~clkPinMask; // Clock low -#else - digitalWrite(mosiPin, d & bit); - digitalWrite(clkPin , HIGH); - digitalWrite(clkPin , LOW); -#endif - } - } -} - -// Issue single command to SSD1306, using I2C or hard/soft SPI as needed. -// Because command calls are often grouped, SPI transaction and selection -// must be started/ended in calling function for efficiency. -// This is a private function, not exposed (see ssd1306_command() instead). -void Adafruit_SSD1306::ssd1306_command1(uint8_t c) { - if(wire) { // I2C - wire->beginTransmission(i2caddr); - WIRE_WRITE((uint8_t)0x00); // Co = 0, D/C = 0 - WIRE_WRITE(c); - wire->endTransmission(); - } else { // SPI (hw or soft) -- transaction started in calling function - SSD1306_MODE_COMMAND - SPIwrite(c); - } -} - -// Issue list of commands to SSD1306, same rules as above re: transactions. -// This is a private function, not exposed. -void Adafruit_SSD1306::ssd1306_commandList(const uint8_t *c, uint8_t n) { - if(wire) { // I2C - wire->beginTransmission(i2caddr); - WIRE_WRITE((uint8_t)0x00); // Co = 0, D/C = 0 - uint8_t bytesOut = 1; - while(n--) { - if(bytesOut >= WIRE_MAX) { - wire->endTransmission(); - wire->beginTransmission(i2caddr); - WIRE_WRITE((uint8_t)0x00); // Co = 0, D/C = 0 - bytesOut = 1; - } - WIRE_WRITE(pgm_read_byte(c++)); - bytesOut++; - } - wire->endTransmission(); - } else { // SPI -- transaction started in calling function - SSD1306_MODE_COMMAND - while(n--) SPIwrite(pgm_read_byte(c++)); - } -} - -// A public version of ssd1306_command1(), for existing user code that -// might rely on that function. This encapsulates the command transfer -// in a transaction start/end, similar to old library's handling of it. -/*! - @brief Issue a single low-level command directly to the SSD1306 - display, bypassing the library. - @param c - Command to issue (0x00 to 0xFF, see datasheet). - @return None (void). -*/ -void Adafruit_SSD1306::ssd1306_command(uint8_t c) { - TRANSACTION_START - ssd1306_command1(c); - TRANSACTION_END -} - -// ALLOCATE & INIT DISPLAY ------------------------------------------------- - -/*! - @brief Allocate RAM for image buffer, initialize peripherals and pins. - @param vcs - VCC selection. Pass SSD1306_SWITCHCAPVCC to generate the display - voltage (step up) from the 3.3V source, or SSD1306_EXTERNALVCC - otherwise. Most situations with Adafruit SSD1306 breakouts will - want SSD1306_SWITCHCAPVCC. - @param addr - I2C address of corresponding SSD1306 display (or pass 0 to use - default of 0x3C for 128x32 display, 0x3D for all others). - SPI displays (hardware or software) do not use addresses, but - this argument is still required (pass 0 or any value really, - it will simply be ignored). Default if unspecified is 0. - @param reset - If true, and if the reset pin passed to the constructor is - valid, a hard reset will be performed before initializing the - display. If using multiple SSD1306 displays on the same bus, and - if they all share the same reset pin, you should only pass true - on the first display being initialized, false on all others, - else the already-initialized displays would be reset. Default if - unspecified is true. - @param periphBegin - If true, and if a hardware peripheral is being used (I2C or SPI, - but not software SPI), call that peripheral's begin() function, - else (false) it has already been done in one's sketch code. - Cases where false might be used include multiple displays or - other devices sharing a common bus, or situations on some - platforms where a nonstandard begin() function is available - (e.g. a TwoWire interface on non-default pins, as can be done - on the ESP8266 and perhaps others). - @return true on successful allocation/init, false otherwise. - Well-behaved code should check the return value before - proceeding. - @note MUST call this function before any drawing or updates! -*/ -boolean Adafruit_SSD1306::begin(uint8_t vcs, uint8_t addr, boolean reset, - boolean periphBegin) { - - framebuffer = (uint8_t *)malloc(WIDTH * ((HEIGHT + 7) / 8)); - if (!framebuffer) return false; - - clearDisplay(); - - /* - if(HEIGHT > 32) { - drawBitmap((WIDTH - splash1_width) / 2, (HEIGHT - splash1_height) / 2, - splash1_data, splash1_width, splash1_height, 1); - } else { - drawBitmap((WIDTH - splash2_width) / 2, (HEIGHT - splash2_height) / 2, - splash2_data, splash2_width, splash2_height, 1); - } -*/ - vccstate = vcs; - - // Setup pin directions - if(wire) { // Using I2C - // If I2C address is unspecified, use default - // (0x3C for 32-pixel-tall displays, 0x3D for all others). - i2caddr = addr ? addr : ((HEIGHT == 32) ? 0x3C : 0x3D); - // TwoWire begin() function might be already performed by the calling - // function if it has unusual circumstances (e.g. TWI variants that - // can accept different SDA/SCL pins, or if two SSD1306 instances - // with different addresses -- only a single begin() is needed). - if(periphBegin) wire->begin(); - } else { // Using one of the SPI modes, either soft or hardware - pinMode(dcPin, OUTPUT); // Set data/command pin as output - pinMode(csPin, OUTPUT); // Same for chip select -#ifdef HAVE_PORTREG - dcPort = (PortReg *)portOutputRegister(digitalPinToPort(dcPin)); - dcPinMask = digitalPinToBitMask(dcPin); - csPort = (PortReg *)portOutputRegister(digitalPinToPort(csPin)); - csPinMask = digitalPinToBitMask(csPin); -#endif - SSD1306_DESELECT - if(spi) { // Hardware SPI - // SPI peripheral begin same as wire check above. - if(periphBegin) spi->begin(); - } else { // Soft SPI - pinMode(mosiPin, OUTPUT); // MOSI and SCLK outputs - pinMode(clkPin , OUTPUT); -#ifdef HAVE_PORTREG - mosiPort = (PortReg *)portOutputRegister(digitalPinToPort(mosiPin)); - mosiPinMask = digitalPinToBitMask(mosiPin); - clkPort = (PortReg *)portOutputRegister(digitalPinToPort(clkPin)); - clkPinMask = digitalPinToBitMask(clkPin); - *clkPort &= ~clkPinMask; // Clock low -#else - digitalWrite(clkPin, LOW); // Clock low -#endif - } - } - - // Reset SSD1306 if requested and reset pin specified in constructor - if(reset && (rstPin >= 0)) { - pinMode( rstPin, OUTPUT); - digitalWrite(rstPin, HIGH); - delay(1); // VDD goes high at start, pause for 1 ms - digitalWrite(rstPin, LOW); // Bring reset low - delay(10); // Wait 10 ms - digitalWrite(rstPin, HIGH); // Bring out of reset - } - - TRANSACTION_START - - // Init sequence - static const uint8_t PROGMEM init1[] = { - SSD1306_DISPLAYOFF, // 0xAE - SSD1306_SETDISPLAYCLOCKDIV, // 0xD5 - 0x80, // the suggested ratio 0x80 - SSD1306_SETMULTIPLEX }; // 0xA8 - ssd1306_commandList(init1, sizeof(init1)); - ssd1306_command1(HEIGHT - 1); - - static const uint8_t PROGMEM init2[] = { - SSD1306_SETDISPLAYOFFSET, // 0xD3 - 0x0, // no offset - SSD1306_SETSTARTLINE | 0x0, // line #0 - SSD1306_CHARGEPUMP }; // 0x8D - ssd1306_commandList(init2, sizeof(init2)); - - ssd1306_command1((vccstate == SSD1306_EXTERNALVCC) ? 0x10 : 0x14); - - static const uint8_t PROGMEM init3[] = { - SSD1306_MEMORYMODE, // 0x20 - 0x00, // 0x0 act like ks0108 - SSD1306_SEGREMAP | 0x1, - SSD1306_COMSCANDEC }; - ssd1306_commandList(init3, sizeof(init3)); - - if((WIDTH == 128) && (HEIGHT == 32)) { - static const uint8_t PROGMEM init4a[] = { - SSD1306_SETCOMPINS, // 0xDA - 0x02, - SSD1306_SETCONTRAST, // 0x81 - 0x8F }; - ssd1306_commandList(init4a, sizeof(init4a)); - } else if((WIDTH == 128) && (HEIGHT == 64)) { - static const uint8_t PROGMEM init4b[] = { - SSD1306_SETCOMPINS, // 0xDA - 0x12, - SSD1306_SETCONTRAST }; // 0x81 - ssd1306_commandList(init4b, sizeof(init4b)); - ssd1306_command1((vccstate == SSD1306_EXTERNALVCC) ? 0x9F : 0xCF); - } else if((WIDTH == 96) && (HEIGHT == 16)) { - static const uint8_t PROGMEM init4c[] = { - SSD1306_SETCOMPINS, // 0xDA - 0x2, // ada x12 - SSD1306_SETCONTRAST }; // 0x81 - ssd1306_commandList(init4c, sizeof(init4c)); - ssd1306_command1((vccstate == SSD1306_EXTERNALVCC) ? 0x10 : 0xAF); - } else if((WIDTH == 64) && (HEIGHT == 48)) { - static const uint8_t PROGMEM init4d[] = { - SSD1306_SETCOMPINS, // 0xDA - 0x12, - SSD1306_SETCONTRAST }; // 0x81 - ssd1306_commandList(init4d, sizeof(init4d)); - ssd1306_command1((vccstate == SSD1306_EXTERNALVCC) ? 0x9F : 0xCF); - } else if((WIDTH == 72) && (HEIGHT == 40)) { - static const uint8_t PROGMEM init4d[] = { - SSD1306_SETCOMPINS, // 0xDA - 0x12, - SSD1306_SETCONTRAST }; // 0x81 - ssd1306_commandList(init4d, sizeof(init4d)); - ssd1306_command1((vccstate == SSD1306_EXTERNALVCC) ? 0x9F : 0xCF); - } else { - // Other screen varieties -- TBD - } - - ssd1306_command1(SSD1306_SETPRECHARGE); // 0xd9 - ssd1306_command1((vccstate == SSD1306_EXTERNALVCC) ? 0x22 : 0xF1); - static const uint8_t PROGMEM init5[] = { - SSD1306_SETVCOMDETECT, // 0xDB - 0x40, - SSD1306_DISPLAYALLON_RESUME, // 0xA4 - SSD1306_NORMALDISPLAY, // 0xA6 - SSD1306_DEACTIVATE_SCROLL, - SSD1306_DISPLAYON }; // Main screen turn on - ssd1306_commandList(init5, sizeof(init5)); - - TRANSACTION_END - - return true; // Success -} - - -void Adafruit_SSD1306::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { -// ignore update mode - //if (p==DISPLAY_INIT_MODE) { - setRotation(rot); - invertDisplay(false); - setTextWrap(false); // Allow text to run off edges - cp437(true); - setTextFont(font); - setTextSize(size); - setTextColor(WHITE,BLACK); - setCursor(0,0); - fillScreen(BLACK); - Updateframe(); - - disp_bpp = -1; - //} -} - -#if 0 - -// DRAWING FUNCTIONS ------------------------------------------------------- - -/*! - @brief Set/clear/invert a single pixel. This is also invoked by the - Adafruit_GFX library in generating many higher-level graphics - primitives. - @param x - Column of display -- 0 at left to (screen width - 1) at right. - @param y - Row of display -- 0 at top to (screen height -1) at bottom. - @param color - Pixel color, one of: BLACK, WHITE or INVERT. - @return None (void). - @note Changes buffer contents only, no immediate effect on display. - Follow up with a call to display(), or with other graphics - commands as needed by one's own application. -*/ -void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) { - - if (!framebuffer) return; - - - if((x >= 0) && (x < width()) && (y >= 0) && (y < height())) { - // Pixel is in-bounds. Rotate coordinates if needed. - switch(getRotation()) { - case 1: - ssd1306_swap(x, y); - x = WIDTH - x - 1; - break; - case 2: - x = WIDTH - x - 1; - y = HEIGHT - y - 1; - break; - case 3: - ssd1306_swap(x, y); - y = HEIGHT - y - 1; - break; - } - switch(color) { - case WHITE: framebuffer[x + (y/8)*WIDTH] |= (1 << (y&7)); break; - case BLACK: framebuffer[x + (y/8)*WIDTH] &= ~(1 << (y&7)); break; - case INVERSE: framebuffer[x + (y/8)*WIDTH] ^= (1 << (y&7)); break; - } - } -} - -/*! - @brief Clear contents of display buffer (set all pixels to off). - @return None (void). - @note Changes buffer contents only, no immediate effect on display. - Follow up with a call to display(), or with other graphics - commands as needed by one's own application. -*/ -void Adafruit_SSD1306::clearDisplay(void) { - if (!framebuffer) return; - memset(framebuffer, 0, WIDTH * ((HEIGHT + 7) / 8)); -} - -/*! - @brief Draw a horizontal line. This is also invoked by the Adafruit_GFX - library in generating many higher-level graphics primitives. - @param x - Leftmost column -- 0 at left to (screen width - 1) at right. - @param y - Row of display -- 0 at top to (screen height -1) at bottom. - @param w - Width of line, in pixels. - @param color - Line color, one of: BLACK, WHITE or INVERT. - @return None (void). - @note Changes buffer contents only, no immediate effect on display. - Follow up with a call to display(), or with other graphics - commands as needed by one's own application. -*/ -void Adafruit_SSD1306::drawFastHLine( - int16_t x, int16_t y, int16_t w, uint16_t color) { - boolean bSwap = false; - switch(rotation) { - case 1: - // 90 degree rotation, swap x & y for rotation, then invert x - bSwap = true; - ssd1306_swap(x, y); - x = WIDTH - x - 1; - break; - case 2: - // 180 degree rotation, invert x and y, then shift y around for height. - x = WIDTH - x - 1; - y = HEIGHT - y - 1; - x -= (w-1); - break; - case 3: - // 270 degree rotation, swap x & y for rotation, - // then invert y and adjust y for w (not to become h) - bSwap = true; - ssd1306_swap(x, y); - y = HEIGHT - y - 1; - y -= (w-1); - break; - } - - if(bSwap) drawFastVLineInternal(x, y, w, color); - else drawFastHLineInternal(x, y, w, color); -} - - - -/*! - @brief Draw a vertical line. This is also invoked by the Adafruit_GFX - library in generating many higher-level graphics primitives. - @param x - Column of display -- 0 at left to (screen width -1) at right. - @param y - Topmost row -- 0 at top to (screen height - 1) at bottom. - @param h - Height of line, in pixels. - @param color - Line color, one of: BLACK, WHITE or INVERT. - @return None (void). - @note Changes buffer contents only, no immediate effect on display. - Follow up with a call to display(), or with other graphics - commands as needed by one's own application. -*/ -void Adafruit_SSD1306::drawFastVLine( - int16_t x, int16_t y, int16_t h, uint16_t color) { - boolean bSwap = false; - switch(rotation) { - case 1: - // 90 degree rotation, swap x & y for rotation, - // then invert x and adjust x for h (now to become w) - bSwap = true; - ssd1306_swap(x, y); - x = WIDTH - x - 1; - x -= (h-1); - break; - case 2: - // 180 degree rotation, invert x and y, then shift y around for height. - x = WIDTH - x - 1; - y = HEIGHT - y - 1; - y -= (h-1); - break; - case 3: - // 270 degree rotation, swap x & y for rotation, then invert y - bSwap = true; - ssd1306_swap(x, y); - y = HEIGHT - y - 1; - break; - } - - if(bSwap) drawFastHLineInternal(x, y, h, color); - else drawFastVLineInternal(x, y, h, color); -} -#endif - -void Adafruit_SSD1306::drawFastHLineInternal ( - int16_t x, int16_t y, int16_t w, uint16_t color) { - if (!framebuffer) return; - if((y >= 0) && (y < HEIGHT)) { // Y coord in bounds? - if(x < 0) { // Clip left - w += x; - x = 0; - } - if((x + w) > WIDTH) { // Clip right - w = (WIDTH - x); - } - if(w > 0) { // Proceed only if width is positive - uint8_t *pBuf = &framebuffer[(y / 8) * WIDTH + x], - mask = 1 << (y & 7); - switch(color) { - case WHITE: while(w--) { *pBuf++ |= mask; }; break; - case BLACK: mask = ~mask; while(w--) { *pBuf++ &= mask; }; break; - case INVERSE: while(w--) { *pBuf++ ^= mask; }; break; - } - } - } -} - -void Adafruit_SSD1306::drawFastVLineInternal( - int16_t x, int16_t __y, int16_t __h, uint16_t color) { -if (!framebuffer) return; - if((x >= 0) && (x < WIDTH)) { // X coord in bounds? - if(__y < 0) { // Clip top - __h += __y; - __y = 0; - } - if((__y + __h) > HEIGHT) { // Clip bottom - __h = (HEIGHT - __y); - } - if(__h > 0) { // Proceed only if height is now positive - // this display doesn't need ints for coordinates, - // use local byte registers for faster juggling - uint8_t y = __y, h = __h; - uint8_t *pBuf = &framebuffer[(y / 8) * WIDTH + x]; - - // do the first partial byte, if necessary - this requires some masking - uint8_t mod = (y & 7); - if(mod) { - // mask off the high n bits we want to set - mod = 8 - mod; - // note - lookup table results in a nearly 10% performance - // improvement in fill* functions - // uint8_t mask = ~(0xFF >> mod); - static const uint8_t PROGMEM premask[8] = - { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; - uint8_t mask = pgm_read_byte(&premask[mod]); - // adjust the mask if we're not going to reach the end of this byte - if(h < mod) mask &= (0XFF >> (mod - h)); - - switch(color) { - case WHITE: *pBuf |= mask; break; - case BLACK: *pBuf &= ~mask; break; - case INVERSE: *pBuf ^= mask; break; - } - pBuf += WIDTH; - } - - if(h >= mod) { // More to go? - h -= mod; - // Write solid bytes while we can - effectively 8 rows at a time - if(h >= 8) { - if(color == INVERSE) { - // separate copy of the code so we don't impact performance of - // black/white write version with an extra comparison per loop - do { - *pBuf ^= 0xFF; // Invert byte - pBuf += WIDTH; // Advance pointer 8 rows - h -= 8; // Subtract 8 rows from height - } while(h >= 8); - } else { - // store a local value to work with - uint8_t val = (color != BLACK) ? 255 : 0; - do { - *pBuf = val; // Set byte - pBuf += WIDTH; // Advance pointer 8 rows - h -= 8; // Subtract 8 rows from height - } while(h >= 8); - } - } - - if(h) { // Do the final partial byte, if necessary - mod = h & 7; - // this time we want to mask the low bits of the byte, - // vs the high bits we did above - // uint8_t mask = (1 << mod) - 1; - // note - lookup table results in a nearly 10% performance - // improvement in fill* functions - static const uint8_t PROGMEM postmask[8] = - { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; - uint8_t mask = pgm_read_byte(&postmask[mod]); - switch(color) { - case WHITE: *pBuf |= mask; break; - case BLACK: *pBuf &= ~mask; break; - case INVERSE: *pBuf ^= mask; break; - } - } - } - } // endif positive height - } // endif x in bounds -} - -/*! - @brief Return color of a single pixel in display buffer. - @param x - Column of display -- 0 at left to (screen width - 1) at right. - @param y - Row of display -- 0 at top to (screen height -1) at bottom. - @return true if pixel is set (usually WHITE, unless display invert mode - is enabled), false if clear (BLACK). - @note Reads from buffer contents; may not reflect current contents of - screen if display() has not been called. -*/ -boolean Adafruit_SSD1306::getPixel(int16_t x, int16_t y) { - if (!framebuffer) return 0; - - if((x >= 0) && (x < width()) && (y >= 0) && (y < height())) { - // Pixel is in-bounds. Rotate coordinates if needed. - switch(getRotation()) { - case 1: - ssd1306_swap(x, y); - x = WIDTH - x - 1; - break; - case 2: - x = WIDTH - x - 1; - y = HEIGHT - y - 1; - break; - case 3: - ssd1306_swap(x, y); - y = HEIGHT - y - 1; - break; - } - return (framebuffer[x + (y / 8) * WIDTH] & (1 << (y & 7))); - } - return false; // Pixel out of bounds -} - -/*! - @brief Get base address of display buffer for direct reading or writing. - @return Pointer to an unsigned 8-bit array, column-major, columns padded - to full byte boundary if needed. -*/ -uint8_t *Adafruit_SSD1306::getBuffer(void) { - return framebuffer; -} - - -// REFRESH DISPLAY --------------------------------------------------------- - -/*! - @brief Push data currently in RAM to SSD1306 display. - @return None (void). - @note Drawing operations are not visible until this function is - called. Call after each graphics command, or after a whole set - of graphics commands, as best needed by one's own application. -*/ -void Adafruit_SSD1306::display(void) { - if (!framebuffer) return; - int16_t col_start = 0; - int16_t col_end = WIDTH - 1; - if ((64 == WIDTH) && (48 == HEIGHT)) { // for 64x48, we need to shift by 32 in both directions - col_start += 32; - col_end += 32; - } else if ((72 == WIDTH) && (40 == HEIGHT)) { // for 72x40, we need to shift by 27 in both directions - col_start += 27; - col_end += 27; - } - - TRANSACTION_START - static const uint8_t PROGMEM dlist1[] = { - SSD1306_PAGEADDR, - 0, // Page start address - 0xFF, // Page end (not really, but works here) - SSD1306_COLUMNADDR }; - ssd1306_commandList(dlist1, sizeof(dlist1)); - ssd1306_command1(col_start); // Column start address - ssd1306_command1(col_end); // Column end address - -#if defined(ESP8266) - // ESP8266 needs a periodic yield() call to avoid watchdog reset. - // With the limited size of SSD1306 displays, and the fast bitrate - // being used (1 MHz or more), I think one yield() immediately before - // a screen write and one immediately after should cover it. But if - // not, if this becomes a problem, yields() might be added in the - // 32-byte transfer condition below. - yield(); -#endif - uint16_t count = WIDTH * ((HEIGHT + 7) / 8); - uint8_t *ptr = framebuffer; - if(wire) { // I2C - wire->beginTransmission(i2caddr); - WIRE_WRITE((uint8_t)0x40); - uint8_t bytesOut = 1; - while(count--) { - if(bytesOut >= WIRE_MAX) { - wire->endTransmission(); - wire->beginTransmission(i2caddr); - WIRE_WRITE((uint8_t)0x40); - bytesOut = 1; - } - WIRE_WRITE(*ptr++); - bytesOut++; - } - wire->endTransmission(); - } else { // SPI - SSD1306_MODE_DATA - while(count--) SPIwrite(*ptr++); - } - TRANSACTION_END -#if defined(ESP8266) - yield(); -#endif -} - -// SCROLLING FUNCTIONS ----------------------------------------------------- - -/*! - @brief Activate a right-handed scroll for all or part of the display. - @param start - First row. - @param stop - Last row. - @return None (void). -*/ -// To scroll the whole display, run: display.startscrollright(0x00, 0x0F) -void Adafruit_SSD1306::startscrollright(uint8_t start, uint8_t stop) { - TRANSACTION_START - static const uint8_t PROGMEM scrollList1a[] = { - SSD1306_RIGHT_HORIZONTAL_SCROLL, - 0X00 }; - ssd1306_commandList(scrollList1a, sizeof(scrollList1a)); - ssd1306_command1(start); - ssd1306_command1(0X00); - ssd1306_command1(stop); - static const uint8_t PROGMEM scrollList1b[] = { - 0X00, - 0XFF, - SSD1306_ACTIVATE_SCROLL }; - ssd1306_commandList(scrollList1b, sizeof(scrollList1b)); - TRANSACTION_END -} - -/*! - @brief Activate a left-handed scroll for all or part of the display. - @param start - First row. - @param stop - Last row. - @return None (void). -*/ -// To scroll the whole display, run: display.startscrollleft(0x00, 0x0F) -void Adafruit_SSD1306::startscrollleft(uint8_t start, uint8_t stop) { - TRANSACTION_START - static const uint8_t PROGMEM scrollList2a[] = { - SSD1306_LEFT_HORIZONTAL_SCROLL, - 0X00 }; - ssd1306_commandList(scrollList2a, sizeof(scrollList2a)); - ssd1306_command1(start); - ssd1306_command1(0X00); - ssd1306_command1(stop); - static const uint8_t PROGMEM scrollList2b[] = { - 0X00, - 0XFF, - SSD1306_ACTIVATE_SCROLL }; - ssd1306_commandList(scrollList2b, sizeof(scrollList2b)); - TRANSACTION_END -} - -/*! - @brief Activate a diagonal scroll for all or part of the display. - @param start - First row. - @param stop - Last row. - @return None (void). -*/ -// display.startscrolldiagright(0x00, 0x0F) -void Adafruit_SSD1306::startscrolldiagright(uint8_t start, uint8_t stop) { - TRANSACTION_START - static const uint8_t PROGMEM scrollList3a[] = { - SSD1306_SET_VERTICAL_SCROLL_AREA, - 0X00 }; - ssd1306_commandList(scrollList3a, sizeof(scrollList3a)); - ssd1306_command1(HEIGHT); - static const uint8_t PROGMEM scrollList3b[] = { - SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL, - 0X00 }; - ssd1306_commandList(scrollList3b, sizeof(scrollList3b)); - ssd1306_command1(start); - ssd1306_command1(0X00); - ssd1306_command1(stop); - static const uint8_t PROGMEM scrollList3c[] = { - 0X01, - SSD1306_ACTIVATE_SCROLL }; - ssd1306_commandList(scrollList3c, sizeof(scrollList3c)); - TRANSACTION_END -} - -/*! - @brief Activate alternate diagonal scroll for all or part of the display. - @param start - First row. - @param stop - Last row. - @return None (void). -*/ -// To scroll the whole display, run: display.startscrolldiagleft(0x00, 0x0F) -void Adafruit_SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop) { - TRANSACTION_START - static const uint8_t PROGMEM scrollList4a[] = { - SSD1306_SET_VERTICAL_SCROLL_AREA, - 0X00 }; - ssd1306_commandList(scrollList4a, sizeof(scrollList4a)); - ssd1306_command1(HEIGHT); - static const uint8_t PROGMEM scrollList4b[] = { - SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL, - 0X00 }; - ssd1306_commandList(scrollList4b, sizeof(scrollList4b)); - ssd1306_command1(start); - ssd1306_command1(0X00); - ssd1306_command1(stop); - static const uint8_t PROGMEM scrollList4c[] = { - 0X01, - SSD1306_ACTIVATE_SCROLL }; - ssd1306_commandList(scrollList4c, sizeof(scrollList4c)); - TRANSACTION_END -} - -/*! - @brief Cease a previously-begun scrolling action. - @return None (void). -*/ -void Adafruit_SSD1306::stopscroll(void) { - TRANSACTION_START - ssd1306_command1(SSD1306_DEACTIVATE_SCROLL); - TRANSACTION_END -} - -// OTHER HARDWARE SETTINGS ------------------------------------------------- - -/*! - @brief Enable or disable display invert mode (white-on-black vs - black-on-white). - @param i - If true, switch to invert mode (black-on-white), else normal - mode (white-on-black). - @return None (void). - @note This has an immediate effect on the display, no need to call the - display() function -- buffer contents are not changed, rather a - different pixel mode of the display hardware is used. When - enabled, drawing BLACK (value 0) pixels will actually draw white, - WHITE (value 1) will draw black. -*/ -void Adafruit_SSD1306::invertDisplay(boolean i) { - TRANSACTION_START - ssd1306_command1(i ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY); - TRANSACTION_END -} - -/*! - @brief Dim the display. - @param dim - true to enable lower brightness mode, false for full brightness. - @return None (void). - @note This has an immediate effect on the display, no need to call the - display() function -- buffer contents are not changed. -*/ -void Adafruit_SSD1306::dim(boolean dim) { - uint8_t contrast; - - if(dim) { - contrast = 0; // Dimmed display - } else { - contrast = (vccstate == SSD1306_EXTERNALVCC) ? 0x9F : 0xCF; - } - // the range of contrast to too small to be really useful - // it is useful to dim the display - TRANSACTION_START - ssd1306_command1(SSD1306_SETCONTRAST); - ssd1306_command1(contrast); - TRANSACTION_END -} - -void Adafruit_SSD1306::DisplayOnff(int8_t on) { - TRANSACTION_START - if(on) { - ssd1306_command1(SSD1306_DISPLAYON); - } else { - ssd1306_command1(SSD1306_DISPLAYOFF); - } - TRANSACTION_END -} - -void Adafruit_SSD1306::Updateframe(void) { - display(); -} diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/Adafruit_SSD1306.h b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/Adafruit_SSD1306.h deleted file mode 100644 index 5be544199..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/Adafruit_SSD1306.h +++ /dev/null @@ -1,189 +0,0 @@ -/*! - * @file Adafruit_SSD1306.h - * - * This is part of for Adafruit's SSD1306 library for monochrome - * OLED displays: http://www.adafruit.com/category/63_98 - * - * These displays use I2C or SPI to communicate. I2C requires 2 pins - * (SCL+SDA) and optionally a RESET pin. SPI requires 4 pins (MOSI, SCK, - * select, data/command) and optionally a reset pin. Hardware SPI or - * 'bitbang' software SPI are both supported. - * - * Adafruit invests time and resources providing this open source code, - * please support Adafruit and open-source hardware by purchasing - * products from Adafruit! - * - * Written by Limor Fried/Ladyada for Adafruit Industries, with - * contributions from the open source community. - * - * BSD license, all text above, and the splash screen header file, - * must be included in any redistribution. - * - */ - -#ifndef _Adafruit_SSD1306_H_ -#define _Adafruit_SSD1306_H_ - -#include - -extern uint8_t *buffer; - -// ONE of the following three lines must be #defined: -//#define SSD1306_128_64 ///< DEPRECTAED: old way to specify 128x64 screen -#define SSD1306_128_32 ///< DEPRECATED: old way to specify 128x32 screen -//#define SSD1306_96_16 ///< DEPRECATED: old way to specify 96x16 screen -// This establishes the screen dimensions in old Adafruit_SSD1306 sketches -// (NEW CODE SHOULD IGNORE THIS, USE THE CONSTRUCTORS THAT ACCEPT WIDTH -// AND HEIGHT ARGUMENTS). - -#if defined(ARDUINO_STM32_FEATHER) - typedef class HardwareSPI SPIClass; -#endif - -#include -#include -#include - -#if defined(__AVR__) - typedef volatile uint8_t PortReg; - typedef uint8_t PortMask; - #define HAVE_PORTREG -#elif defined(__SAM3X8E__) - typedef volatile RwReg PortReg; - typedef uint32_t PortMask; - #define HAVE_PORTREG -#elif defined(__arm__) || defined(ARDUINO_FEATHER52) - typedef volatile uint32_t PortReg; - typedef uint32_t PortMask; - #define HAVE_PORTREG -#endif - -#define BLACK 0 ///< Draw 'off' pixels -#define WHITE 1 ///< Draw 'on' pixels -#define INVERSE 2 ///< Invert pixels - -#define SSD1306_MEMORYMODE 0x20 ///< See datasheet -#define SSD1306_COLUMNADDR 0x21 ///< See datasheet -#define SSD1306_PAGEADDR 0x22 ///< See datasheet -#define SSD1306_SETCONTRAST 0x81 ///< See datasheet -#define SSD1306_CHARGEPUMP 0x8D ///< See datasheet -#define SSD1306_SEGREMAP 0xA0 ///< See datasheet -#define SSD1306_DISPLAYALLON_RESUME 0xA4 ///< See datasheet -#define SSD1306_DISPLAYALLON 0xA5 ///< Not currently used -#define SSD1306_NORMALDISPLAY 0xA6 ///< See datasheet -#define SSD1306_INVERTDISPLAY 0xA7 ///< See datasheet -#define SSD1306_SETMULTIPLEX 0xA8 ///< See datasheet -#define SSD1306_DISPLAYOFF 0xAE ///< See datasheet -#define SSD1306_DISPLAYON 0xAF ///< See datasheet -#define SSD1306_COMSCANINC 0xC0 ///< Not currently used -#define SSD1306_COMSCANDEC 0xC8 ///< See datasheet -#define SSD1306_SETDISPLAYOFFSET 0xD3 ///< See datasheet -#define SSD1306_SETDISPLAYCLOCKDIV 0xD5 ///< See datasheet -#define SSD1306_SETPRECHARGE 0xD9 ///< See datasheet -#define SSD1306_SETCOMPINS 0xDA ///< See datasheet -#define SSD1306_SETVCOMDETECT 0xDB ///< See datasheet - -#define SSD1306_SETLOWCOLUMN 0x00 ///< Not currently used -#define SSD1306_SETHIGHCOLUMN 0x10 ///< Not currently used -#define SSD1306_SETSTARTLINE 0x40 ///< See datasheet - -#define SSD1306_EXTERNALVCC 0x01 ///< External display voltage source -#define SSD1306_SWITCHCAPVCC 0x02 ///< Gen. display voltage from 3.3V - -#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26 ///< Init rt scroll -#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27 ///< Init left scroll -#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 ///< Init diag scroll -#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A ///< Init diag scroll -#define SSD1306_DEACTIVATE_SCROLL 0x2E ///< Stop scroll -#define SSD1306_ACTIVATE_SCROLL 0x2F ///< Start scroll -#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 ///< Set scroll range - -// Deprecated size stuff for backwards compatibility with old sketches -#if defined SSD1306_128_64 - #define SSD1306_LCDWIDTH 128 ///< DEPRECATED: width w/SSD1306_128_64 defined - #define SSD1306_LCDHEIGHT 64 ///< DEPRECATED: height w/SSD1306_128_64 defined -#endif -#if defined SSD1306_128_32 - #define SSD1306_LCDWIDTH 128 ///< DEPRECATED: width w/SSD1306_128_32 defined - #define SSD1306_LCDHEIGHT 32 ///< DEPRECATED: height w/SSD1306_128_32 defined -#endif -#if defined SSD1306_96_16 - #define SSD1306_LCDWIDTH 96 ///< DEPRECATED: width w/SSD1306_96_16 defined - #define SSD1306_LCDHEIGHT 16 ///< DEPRECATED: height w/SSD1306_96_16 defined -#endif - -/*! - @brief Class that stores state and functions for interacting with - SSD1306 OLED displays. -*/ -class Adafruit_SSD1306 : public Renderer { -public: - // NEW CONSTRUCTORS -- recommended for new projects - Adafruit_SSD1306(uint8_t w, uint8_t h, TwoWire *twi=&Wire, int8_t rst_pin=-1, - uint32_t clkDuring=400000UL, uint32_t clkAfter=100000UL); - Adafruit_SSD1306(uint8_t w, uint8_t h, int8_t mosi_pin, int8_t sclk_pin, - int8_t dc_pin, int8_t rst_pin, int8_t cs_pin); - Adafruit_SSD1306(uint8_t w, uint8_t h, SPIClass *spi, - int8_t dc_pin, int8_t rst_pin, int8_t cs_pin, uint32_t bitrate=8000000UL); - - // DEPRECATED CONSTRUCTORS - for back compatibility, avoid in new projects - Adafruit_SSD1306(int8_t mosi_pin, int8_t sclk_pin, int8_t dc_pin, - int8_t rst_pin, int8_t cs_pin); - Adafruit_SSD1306(int8_t dc_pin, int8_t rst_pin, int8_t cs_pin); - Adafruit_SSD1306(int8_t rst_pin = -1); - - ~Adafruit_SSD1306(void); - - boolean begin(uint8_t switchvcc=SSD1306_SWITCHCAPVCC, - uint8_t i2caddr=0, boolean reset=true, - boolean periphBegin=true); - void display(void); - void invertDisplay(boolean i); - void dim(boolean dim); - void DisplayOnff(int8_t on); - void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font); - - #if 0 - void clearDisplay(void); - void drawPixel(int16_t x, int16_t y, uint16_t color); - virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); - virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); - #endif - void startscrollright(uint8_t start, uint8_t stop); - void startscrollleft(uint8_t start, uint8_t stop); - void startscrolldiagright(uint8_t start, uint8_t stop); - void startscrolldiagleft(uint8_t start, uint8_t stop); - void stopscroll(void); - void ssd1306_command(uint8_t c); - boolean getPixel(int16_t x, int16_t y); - uint8_t *getBuffer(void); - void Updateframe(void); - - private: - inline void SPIwrite(uint8_t d) __attribute__((always_inline)); - void drawFastHLineInternal(int16_t x, int16_t y, int16_t w, - uint16_t color); - void drawFastVLineInternal(int16_t x, int16_t y, int16_t h, - uint16_t color); - void ssd1306_command1(uint8_t c); - void ssd1306_commandList(const uint8_t *c, uint8_t n); - - SPIClass *spi; - TwoWire *wire; - uint8_t *xbuffer; - int8_t i2caddr, vccstate, page_end; - int8_t mosiPin , clkPin , dcPin , csPin, rstPin; -#ifdef HAVE_PORTREG - PortReg *mosiPort , *clkPort , *dcPort , *csPort; - PortMask mosiPinMask, clkPinMask, dcPinMask, csPinMask; -#endif -#if defined(SPI_HAS_TRANSACTION) - SPISettings spiSettings; -#endif -#if ARDUINO >= 157 - uint32_t wireClk; // Wire speed for SSD1306 transfers - uint32_t restoreClk; // Wire speed following SSD1306 transfers -#endif -}; - -#endif // _Adafruit_SSD1306_H_ diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/README.md b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/README.md deleted file mode 100644 index f2e01ad4b..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# Adafruit_SSD1306 [![Build Status](https://travis-ci.org/adafruit/Adafruit_SSD1306.svg?branch=master)](https://travis-ci.org/adafruit/Adafruit_SSD1306) - -This is a library for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - -These displays use I2C or SPI to communicate, 2 to 5 pins are required to interface. - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries, with contributions from the open source community. Scrolling code contributed by Michael Gregg. Dynamic buffer allocation based on work by Andrew Canaday. -BSD license, check license.txt for more information. All text above must be included in any redistribution - -Preferred installation method is to use the Arduino IDE Library Manager. To download the source from Github instead, click "Clone or download" above, then "Download ZIP." After uncompressing, rename the resulting folder Adafruit_SSD1306. Check that the Adafruit_SSD1306 folder contains Adafruit_SSD1306.cpp and Adafruit_SSD1306.h. - -You will also have to install the **Adafruit GFX library** which provides graphics primitves such as lines, circles, text, etc. This also can be found in the Arduino Library Manager, or you can get the source from https://github.com/adafruit/Adafruit-GFX-Library - -## Changes - -Version 1.2 (November 2018) introduces some significant changes: - - * Display dimensions are now specified in the constructor...you no longer need to edit the .h file for different screens (though old sketches can continue to work that way). - * SPI transactions are used and SPI bitrate can be specified (both require Arduino 1.6 or later). - * SPI and Wire (I2C) interfaces other than the defaults are supported. - - - -## Compatibility - -MCU |Tested Works|Doesn't Work|Not Tested|Notes -------------|:----------:|:----------:|:--------:|----- -Atmega328 | X | | | -Atmega32u4 | X | | | -Atmega2560 | X | | | -ESP8266 | X | | | Change OLED_RESET to different pin if using default I2C pins D4/D5. -ESP32 | X | | | -ATSAM3X8E | X | | | -ATSAM21D | X | | | -Intel Curie | X | | | -WICED | X | | | No hardware SPI - bitbang only -ATtiny85 | | X | | - - * ATmega328 : Arduino UNO, Adafruit Pro Trinket, Adafruit Metro 328, Adafruit Metro Mini - * ATmega32u4 : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0, Adafruit Flora, Bluefruit Micro - * ATmega2560 : Arduino Mega - * ESP8266 : Adafruit Huzzah - * ATSAM3X8E : Arduino Due - * ATSAM21D : Arduino Zero, M0 Pro, Adafruit Metro Express, Feather M0 - * ATtiny85 : Adafruit Gemma, Arduino Gemma, Adafruit Trinket - - diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/OLED_featherwing/OLED_featherwing.ino b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/OLED_featherwing/OLED_featherwing.ino deleted file mode 100644 index 2d0d24646..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/OLED_featherwing/OLED_featherwing.ino +++ /dev/null @@ -1,79 +0,0 @@ -#include -#include -#include -#include - -Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire); - -// OLED FeatherWing buttons map to different pins depending on board: -#if defined(ESP8266) - #define BUTTON_A 0 - #define BUTTON_B 16 - #define BUTTON_C 2 -#elif defined(ESP32) - #define BUTTON_A 15 - #define BUTTON_B 32 - #define BUTTON_C 14 -#elif defined(ARDUINO_STM32_FEATHER) - #define BUTTON_A PA15 - #define BUTTON_B PC7 - #define BUTTON_C PC5 -#elif defined(TEENSYDUINO) - #define BUTTON_A 4 - #define BUTTON_B 3 - #define BUTTON_C 8 -#elif defined(ARDUINO_FEATHER52832) - #define BUTTON_A 31 - #define BUTTON_B 30 - #define BUTTON_C 27 -#else // 32u4, M0, M4, nrf52840 and 328p - #define BUTTON_A 9 - #define BUTTON_B 6 - #define BUTTON_C 5 -#endif - -void setup() { - Serial.begin(9600); - - Serial.println("OLED FeatherWing test"); - // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally - display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Address 0x3C for 128x32 - - Serial.println("OLED begun"); - - // Show image buffer on the display hardware. - // Since the buffer is intialized with an Adafruit splashscreen - // internally, this will display the splashscreen. - display.display(); - delay(1000); - - // Clear the buffer. - display.clearDisplay(); - display.display(); - - Serial.println("IO test"); - - pinMode(BUTTON_A, INPUT_PULLUP); - pinMode(BUTTON_B, INPUT_PULLUP); - pinMode(BUTTON_C, INPUT_PULLUP); - - // text display tests - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - display.print("Connecting to SSID\n'adafruit':"); - display.print("connected!"); - display.println("IP: 10.0.1.23"); - display.println("Sending val #0"); - display.setCursor(0,0); - display.display(); // actually display all of the above -} - -void loop() { - if(!digitalRead(BUTTON_A)) display.print("A"); - if(!digitalRead(BUTTON_B)) display.print("B"); - if(!digitalRead(BUTTON_C)) display.print("C"); - delay(10); - yield(); - display.display(); -} diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino deleted file mode 100644 index 68bfee354..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino +++ /dev/null @@ -1,410 +0,0 @@ -/************************************************************************** - This is an example for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - - This example is for a 128x32 pixel display using I2C to communicate - 3 pins are required to interface (two I2C and one reset). - - Adafruit invests time and resources providing this open - source code, please support Adafruit and open-source - hardware by purchasing products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries, - with contributions from the open source community. - BSD license, check license.txt for more information - All text above, and the splash screen below must be - included in any redistribution. - **************************************************************************/ - -#include -#include -#include -#include - -#define SCREEN_WIDTH 128 // OLED display width, in pixels -#define SCREEN_HEIGHT 32 // OLED display height, in pixels - -// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) -#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) -Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); - -#define NUMFLAKES 10 // Number of snowflakes in the animation example - -#define LOGO_HEIGHT 16 -#define LOGO_WIDTH 16 -static const unsigned char PROGMEM logo_bmp[] = -{ B00000000, B11000000, - B00000001, B11000000, - B00000001, B11000000, - B00000011, B11100000, - B11110011, B11100000, - B11111110, B11111000, - B01111110, B11111111, - B00110011, B10011111, - B00011111, B11111100, - B00001101, B01110000, - B00011011, B10100000, - B00111111, B11100000, - B00111111, B11110000, - B01111100, B11110000, - B01110000, B01110000, - B00000000, B00110000 }; - -void setup() { - Serial.begin(9600); - - // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally - if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 - Serial.println(F("SSD1306 allocation failed")); - for(;;); // Don't proceed, loop forever - } - - // Show initial display buffer contents on the screen -- - // the library initializes this with an Adafruit splash screen. - display.display(); - delay(2000); // Pause for 2 seconds - - // Clear the buffer - display.clearDisplay(); - - // Draw a single pixel in white - display.drawPixel(10, 10, WHITE); - - // Show the display buffer on the screen. You MUST call display() after - // drawing commands to make them visible on screen! - display.display(); - delay(2000); - // display.display() is NOT necessary after every single drawing command, - // unless that's what you want...rather, you can batch up a bunch of - // drawing operations and then update the screen all at once by calling - // display.display(). These examples demonstrate both approaches... - - testdrawline(); // Draw many lines - - testdrawrect(); // Draw rectangles (outlines) - - testfillrect(); // Draw rectangles (filled) - - testdrawcircle(); // Draw circles (outlines) - - testfillcircle(); // Draw circles (filled) - - testdrawroundrect(); // Draw rounded rectangles (outlines) - - testfillroundrect(); // Draw rounded rectangles (filled) - - testdrawtriangle(); // Draw triangles (outlines) - - testfilltriangle(); // Draw triangles (filled) - - testdrawchar(); // Draw characters of the default font - - testdrawstyles(); // Draw 'stylized' characters - - testscrolltext(); // Draw scrolling text - - testdrawbitmap(); // Draw a small bitmap image - - // Invert and restore display, pausing in-between - display.invertDisplay(true); - delay(1000); - display.invertDisplay(false); - delay(1000); - - testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps -} - -void loop() { -} - -void testdrawline() { - int16_t i; - - display.clearDisplay(); // Clear display buffer - - for(i=0; i=0; i-=4) { - display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); - display.display(); - delay(1); - } - delay(250); - - display.clearDisplay(); - - for(i=display.width()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); - display.display(); - delay(1); - } - for(i=display.height()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); - display.display(); - delay(1); - } - delay(250); - - display.clearDisplay(); - - for(i=0; i0; i-=3) { - // The INVERSE color is used so circles alternate white/black - display.fillCircle(display.width() / 2, display.height() / 2, i, INVERSE); - display.display(); // Update screen with each newly-drawn circle - delay(1); - } - - delay(2000); -} - -void testdrawroundrect(void) { - display.clearDisplay(); - - for(int16_t i=0; i0; i-=5) { - // The INVERSE color is used so triangles alternate white/black - display.fillTriangle( - display.width()/2 , display.height()/2-i, - display.width()/2-i, display.height()/2+i, - display.width()/2+i, display.height()/2+i, INVERSE); - display.display(); - delay(1); - } - - delay(2000); -} - -void testdrawchar(void) { - display.clearDisplay(); - - display.setTextSize(1); // Normal 1:1 pixel scale - display.setTextColor(WHITE); // Draw white text - display.setCursor(0, 0); // Start at top-left corner - display.cp437(true); // Use full 256 char 'Code Page 437' font - - // Not all the characters will fit on the display. This is normal. - // Library will draw what it can and the rest will be clipped. - for(int16_t i=0; i<256; i++) { - if(i == '\n') display.write(' '); - else display.write(i); - } - - display.display(); - delay(2000); -} - -void testdrawstyles(void) { - display.clearDisplay(); - - display.setTextSize(1); // Normal 1:1 pixel scale - display.setTextColor(WHITE); // Draw white text - display.setCursor(0,0); // Start at top-left corner - display.println(F("Hello, world!")); - - display.setTextColor(BLACK, WHITE); // Draw 'inverse' text - display.println(3.141592); - - display.setTextSize(2); // Draw 2X-scale text - display.setTextColor(WHITE); - display.print(F("0x")); display.println(0xDEADBEEF, HEX); - - display.display(); - delay(2000); -} - -void testscrolltext(void) { - display.clearDisplay(); - - display.setTextSize(2); // Draw 2X-scale text - display.setTextColor(WHITE); - display.setCursor(10, 0); - display.println(F("scroll")); - display.display(); // Show initial text - delay(100); - - // Scroll in various directions, pausing in-between: - display.startscrollright(0x00, 0x0F); - delay(2000); - display.stopscroll(); - delay(1000); - display.startscrollleft(0x00, 0x0F); - delay(2000); - display.stopscroll(); - delay(1000); - display.startscrolldiagright(0x00, 0x07); - delay(2000); - display.startscrolldiagleft(0x00, 0x07); - delay(2000); - display.stopscroll(); - delay(1000); -} - -void testdrawbitmap(void) { - display.clearDisplay(); - - display.drawBitmap( - (display.width() - LOGO_WIDTH ) / 2, - (display.height() - LOGO_HEIGHT) / 2, - logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1); - display.display(); - delay(1000); -} - -#define XPOS 0 // Indexes into the 'icons' array in function below -#define YPOS 1 -#define DELTAY 2 - -void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) { - int8_t f, icons[NUMFLAKES][3]; - - // Initialize 'snowflake' positions - for(f=0; f< NUMFLAKES; f++) { - icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width()); - icons[f][YPOS] = -LOGO_HEIGHT; - icons[f][DELTAY] = random(1, 6); - Serial.print(F("x: ")); - Serial.print(icons[f][XPOS], DEC); - Serial.print(F(" y: ")); - Serial.print(icons[f][YPOS], DEC); - Serial.print(F(" dy: ")); - Serial.println(icons[f][DELTAY], DEC); - } - - for(;;) { // Loop forever... - display.clearDisplay(); // Clear the display buffer - - // Draw each snowflake: - for(f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, WHITE); - } - - display.display(); // Show the display buffer on the screen - delay(200); // Pause for 1/10 second - - // Then update coordinates of each flake... - for(f=0; f< NUMFLAKES; f++) { - icons[f][YPOS] += icons[f][DELTAY]; - // If snowflake is off the bottom of the screen... - if (icons[f][YPOS] >= display.height()) { - // Reinitialize to a random position, just off the top - icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width()); - icons[f][YPOS] = -LOGO_HEIGHT; - icons[f][DELTAY] = random(1, 6); - } - } - } -} diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/ssd1306_128x32_spi/ssd1306_128x32_spi.ino b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/ssd1306_128x32_spi/ssd1306_128x32_spi.ino deleted file mode 100644 index b254785f3..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/ssd1306_128x32_spi/ssd1306_128x32_spi.ino +++ /dev/null @@ -1,423 +0,0 @@ -/************************************************************************** - This is an example for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - - This example is for a 128x32 pixel display using SPI to communicate - 4 or 5 pins are required to interface. - - Adafruit invests time and resources providing this open - source code, please support Adafruit and open-source - hardware by purchasing products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries, - with contributions from the open source community. - BSD license, check license.txt for more information - All text above, and the splash screen below must be - included in any redistribution. - **************************************************************************/ - -#include -#include -#include -#include - -#define SCREEN_WIDTH 128 // OLED display width, in pixels -#define SCREEN_HEIGHT 32 // OLED display height, in pixels - -// Declaration for SSD1306 display connected using software SPI (default case): -#define OLED_MOSI 9 -#define OLED_CLK 10 -#define OLED_DC 11 -#define OLED_CS 12 -#define OLED_RESET 13 -Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, - OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); - -/* Comment out above, uncomment this block to use hardware SPI -#define OLED_DC 6 -#define OLED_CS 7 -#define OLED_RESET 8 -Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, - &SPI, OLED_DC, OLED_RESET, OLED_CS); -*/ - -#define NUMFLAKES 10 // Number of snowflakes in the animation example - -#define LOGO_HEIGHT 16 -#define LOGO_WIDTH 16 -static const unsigned char PROGMEM logo_bmp[] = -{ B00000000, B11000000, - B00000001, B11000000, - B00000001, B11000000, - B00000011, B11100000, - B11110011, B11100000, - B11111110, B11111000, - B01111110, B11111111, - B00110011, B10011111, - B00011111, B11111100, - B00001101, B01110000, - B00011011, B10100000, - B00111111, B11100000, - B00111111, B11110000, - B01111100, B11110000, - B01110000, B01110000, - B00000000, B00110000 }; - -void setup() { - Serial.begin(9600); - - // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally - if(!display.begin(SSD1306_SWITCHCAPVCC)) { - Serial.println(F("SSD1306 allocation failed")); - for(;;); // Don't proceed, loop forever - } - - // Show initial display buffer contents on the screen -- - // the library initializes this with an Adafruit splash screen. - display.display(); - delay(2000); // Pause for 2 seconds - - // Clear the buffer - display.clearDisplay(); - - // Draw a single pixel in white - display.drawPixel(10, 10, WHITE); - - // Show the display buffer on the screen. You MUST call display() after - // drawing commands to make them visible on screen! - display.display(); - delay(2000); - // display.display() is NOT necessary after every single drawing command, - // unless that's what you want...rather, you can batch up a bunch of - // drawing operations and then update the screen all at once by calling - // display.display(). These examples demonstrate both approaches... - - testdrawline(); // Draw many lines - - testdrawrect(); // Draw rectangles (outlines) - - testfillrect(); // Draw rectangles (filled) - - testdrawcircle(); // Draw circles (outlines) - - testfillcircle(); // Draw circles (filled) - - testdrawroundrect(); // Draw rounded rectangles (outlines) - - testfillroundrect(); // Draw rounded rectangles (filled) - - testdrawtriangle(); // Draw triangles (outlines) - - testfilltriangle(); // Draw triangles (filled) - - testdrawchar(); // Draw characters of the default font - - testdrawstyles(); // Draw 'stylized' characters - - testscrolltext(); // Draw scrolling text - - testdrawbitmap(); // Draw a small bitmap image - - // Invert and restore display, pausing in-between - display.invertDisplay(true); - delay(1000); - display.invertDisplay(false); - delay(1000); - - testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps -} - -void loop() { -} - -void testdrawline() { - int16_t i; - - display.clearDisplay(); // Clear display buffer - - for(i=0; i=0; i-=4) { - display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); - display.display(); - delay(1); - } - delay(250); - - display.clearDisplay(); - - for(i=display.width()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); - display.display(); - delay(1); - } - for(i=display.height()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); - display.display(); - delay(1); - } - delay(250); - - display.clearDisplay(); - - for(i=0; i0; i-=3) { - // The INVERSE color is used so circles alternate white/black - display.fillCircle(display.width() / 2, display.height() / 2, i, INVERSE); - display.display(); // Update screen with each newly-drawn circle - delay(1); - } - - delay(2000); -} - -void testdrawroundrect(void) { - display.clearDisplay(); - - for(int16_t i=0; i0; i-=5) { - // The INVERSE color is used so triangles alternate white/black - display.fillTriangle( - display.width()/2 , display.height()/2-i, - display.width()/2-i, display.height()/2+i, - display.width()/2+i, display.height()/2+i, INVERSE); - display.display(); - delay(1); - } - - delay(2000); -} - -void testdrawchar(void) { - display.clearDisplay(); - - display.setTextSize(1); // Normal 1:1 pixel scale - display.setTextColor(WHITE); // Draw white text - display.setCursor(0, 0); // Start at top-left corner - display.cp437(true); // Use full 256 char 'Code Page 437' font - - // Not all the characters will fit on the display. This is normal. - // Library will draw what it can and the rest will be clipped. - for(int16_t i=0; i<256; i++) { - if(i == '\n') display.write(' '); - else display.write(i); - } - - display.display(); - delay(2000); -} - -void testdrawstyles(void) { - display.clearDisplay(); - - display.setTextSize(1); // Normal 1:1 pixel scale - display.setTextColor(WHITE); // Draw white text - display.setCursor(0,0); // Start at top-left corner - display.println(F("Hello, world!")); - - display.setTextColor(BLACK, WHITE); // Draw 'inverse' text - display.println(3.141592); - - display.setTextSize(2); // Draw 2X-scale text - display.setTextColor(WHITE); - display.print(F("0x")); display.println(0xDEADBEEF, HEX); - - display.display(); - delay(2000); -} - -void testscrolltext(void) { - display.clearDisplay(); - - display.setTextSize(2); // Draw 2X-scale text - display.setTextColor(WHITE); - display.setCursor(10, 0); - display.println(F("scroll")); - display.display(); // Show initial text - delay(100); - - // Scroll in various directions, pausing in-between: - display.startscrollright(0x00, 0x0F); - delay(2000); - display.stopscroll(); - delay(1000); - display.startscrollleft(0x00, 0x0F); - delay(2000); - display.stopscroll(); - delay(1000); - display.startscrolldiagright(0x00, 0x07); - delay(2000); - display.startscrolldiagleft(0x00, 0x07); - delay(2000); - display.stopscroll(); - delay(1000); -} - -void testdrawbitmap(void) { - display.clearDisplay(); - - display.drawBitmap( - (display.width() - LOGO_WIDTH ) / 2, - (display.height() - LOGO_HEIGHT) / 2, - logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1); - display.display(); - delay(1000); -} - -#define XPOS 0 // Indexes into the 'icons' array in function below -#define YPOS 1 -#define DELTAY 2 - -void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) { - int8_t f, icons[NUMFLAKES][3]; - - // Initialize 'snowflake' positions - for(f=0; f< NUMFLAKES; f++) { - icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width()); - icons[f][YPOS] = -LOGO_HEIGHT; - icons[f][DELTAY] = random(1, 6); - Serial.print(F("x: ")); - Serial.print(icons[f][XPOS], DEC); - Serial.print(F(" y: ")); - Serial.print(icons[f][YPOS], DEC); - Serial.print(F(" dy: ")); - Serial.println(icons[f][DELTAY], DEC); - } - - for(;;) { // Loop forever... - display.clearDisplay(); // Clear the display buffer - - // Draw each snowflake: - for(f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, WHITE); - } - - display.display(); // Show the display buffer on the screen - delay(200); // Pause for 1/10 second - - // Then update coordinates of each flake... - for(f=0; f< NUMFLAKES; f++) { - icons[f][YPOS] += icons[f][DELTAY]; - // If snowflake is off the bottom of the screen... - if (icons[f][YPOS] >= display.height()) { - // Reinitialize to a random position, just off the top - icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width()); - icons[f][YPOS] = -LOGO_HEIGHT; - icons[f][DELTAY] = random(1, 6); - } - } - } -} diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/ssd1306_128x64_i2c/ssd1306_128x64_i2c.ino b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/ssd1306_128x64_i2c/ssd1306_128x64_i2c.ino deleted file mode 100644 index 6d7d5ddd0..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/ssd1306_128x64_i2c/ssd1306_128x64_i2c.ino +++ /dev/null @@ -1,410 +0,0 @@ -/************************************************************************** - This is an example for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - - This example is for a 128x32 pixel display using I2C to communicate - 3 pins are required to interface (two I2C and one reset). - - Adafruit invests time and resources providing this open - source code, please support Adafruit and open-source - hardware by purchasing products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries, - with contributions from the open source community. - BSD license, check license.txt for more information - All text above, and the splash screen below must be - included in any redistribution. - **************************************************************************/ - -#include -#include -#include -#include - -#define SCREEN_WIDTH 128 // OLED display width, in pixels -#define SCREEN_HEIGHT 64 // OLED display height, in pixels - -// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) -#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) -Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); - -#define NUMFLAKES 10 // Number of snowflakes in the animation example - -#define LOGO_HEIGHT 16 -#define LOGO_WIDTH 16 -static const unsigned char PROGMEM logo_bmp[] = -{ B00000000, B11000000, - B00000001, B11000000, - B00000001, B11000000, - B00000011, B11100000, - B11110011, B11100000, - B11111110, B11111000, - B01111110, B11111111, - B00110011, B10011111, - B00011111, B11111100, - B00001101, B01110000, - B00011011, B10100000, - B00111111, B11100000, - B00111111, B11110000, - B01111100, B11110000, - B01110000, B01110000, - B00000000, B00110000 }; - -void setup() { - Serial.begin(9600); - - // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally - if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { // Address 0x3D for 128x64 - Serial.println(F("SSD1306 allocation failed")); - for(;;); // Don't proceed, loop forever - } - - // Show initial display buffer contents on the screen -- - // the library initializes this with an Adafruit splash screen. - display.display(); - delay(2000); // Pause for 2 seconds - - // Clear the buffer - display.clearDisplay(); - - // Draw a single pixel in white - display.drawPixel(10, 10, WHITE); - - // Show the display buffer on the screen. You MUST call display() after - // drawing commands to make them visible on screen! - display.display(); - delay(2000); - // display.display() is NOT necessary after every single drawing command, - // unless that's what you want...rather, you can batch up a bunch of - // drawing operations and then update the screen all at once by calling - // display.display(). These examples demonstrate both approaches... - - testdrawline(); // Draw many lines - - testdrawrect(); // Draw rectangles (outlines) - - testfillrect(); // Draw rectangles (filled) - - testdrawcircle(); // Draw circles (outlines) - - testfillcircle(); // Draw circles (filled) - - testdrawroundrect(); // Draw rounded rectangles (outlines) - - testfillroundrect(); // Draw rounded rectangles (filled) - - testdrawtriangle(); // Draw triangles (outlines) - - testfilltriangle(); // Draw triangles (filled) - - testdrawchar(); // Draw characters of the default font - - testdrawstyles(); // Draw 'stylized' characters - - testscrolltext(); // Draw scrolling text - - testdrawbitmap(); // Draw a small bitmap image - - // Invert and restore display, pausing in-between - display.invertDisplay(true); - delay(1000); - display.invertDisplay(false); - delay(1000); - - testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps -} - -void loop() { -} - -void testdrawline() { - int16_t i; - - display.clearDisplay(); // Clear display buffer - - for(i=0; i=0; i-=4) { - display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); - display.display(); - delay(1); - } - delay(250); - - display.clearDisplay(); - - for(i=display.width()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); - display.display(); - delay(1); - } - for(i=display.height()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); - display.display(); - delay(1); - } - delay(250); - - display.clearDisplay(); - - for(i=0; i0; i-=3) { - // The INVERSE color is used so circles alternate white/black - display.fillCircle(display.width() / 2, display.height() / 2, i, INVERSE); - display.display(); // Update screen with each newly-drawn circle - delay(1); - } - - delay(2000); -} - -void testdrawroundrect(void) { - display.clearDisplay(); - - for(int16_t i=0; i0; i-=5) { - // The INVERSE color is used so triangles alternate white/black - display.fillTriangle( - display.width()/2 , display.height()/2-i, - display.width()/2-i, display.height()/2+i, - display.width()/2+i, display.height()/2+i, INVERSE); - display.display(); - delay(1); - } - - delay(2000); -} - -void testdrawchar(void) { - display.clearDisplay(); - - display.setTextSize(1); // Normal 1:1 pixel scale - display.setTextColor(WHITE); // Draw white text - display.setCursor(0, 0); // Start at top-left corner - display.cp437(true); // Use full 256 char 'Code Page 437' font - - // Not all the characters will fit on the display. This is normal. - // Library will draw what it can and the rest will be clipped. - for(int16_t i=0; i<256; i++) { - if(i == '\n') display.write(' '); - else display.write(i); - } - - display.display(); - delay(2000); -} - -void testdrawstyles(void) { - display.clearDisplay(); - - display.setTextSize(1); // Normal 1:1 pixel scale - display.setTextColor(WHITE); // Draw white text - display.setCursor(0,0); // Start at top-left corner - display.println(F("Hello, world!")); - - display.setTextColor(BLACK, WHITE); // Draw 'inverse' text - display.println(3.141592); - - display.setTextSize(2); // Draw 2X-scale text - display.setTextColor(WHITE); - display.print(F("0x")); display.println(0xDEADBEEF, HEX); - - display.display(); - delay(2000); -} - -void testscrolltext(void) { - display.clearDisplay(); - - display.setTextSize(2); // Draw 2X-scale text - display.setTextColor(WHITE); - display.setCursor(10, 0); - display.println(F("scroll")); - display.display(); // Show initial text - delay(100); - - // Scroll in various directions, pausing in-between: - display.startscrollright(0x00, 0x0F); - delay(2000); - display.stopscroll(); - delay(1000); - display.startscrollleft(0x00, 0x0F); - delay(2000); - display.stopscroll(); - delay(1000); - display.startscrolldiagright(0x00, 0x07); - delay(2000); - display.startscrolldiagleft(0x00, 0x07); - delay(2000); - display.stopscroll(); - delay(1000); -} - -void testdrawbitmap(void) { - display.clearDisplay(); - - display.drawBitmap( - (display.width() - LOGO_WIDTH ) / 2, - (display.height() - LOGO_HEIGHT) / 2, - logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1); - display.display(); - delay(1000); -} - -#define XPOS 0 // Indexes into the 'icons' array in function below -#define YPOS 1 -#define DELTAY 2 - -void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) { - int8_t f, icons[NUMFLAKES][3]; - - // Initialize 'snowflake' positions - for(f=0; f< NUMFLAKES; f++) { - icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width()); - icons[f][YPOS] = -LOGO_HEIGHT; - icons[f][DELTAY] = random(1, 6); - Serial.print(F("x: ")); - Serial.print(icons[f][XPOS], DEC); - Serial.print(F(" y: ")); - Serial.print(icons[f][YPOS], DEC); - Serial.print(F(" dy: ")); - Serial.println(icons[f][DELTAY], DEC); - } - - for(;;) { // Loop forever... - display.clearDisplay(); // Clear the display buffer - - // Draw each snowflake: - for(f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, WHITE); - } - - display.display(); // Show the display buffer on the screen - delay(200); // Pause for 1/10 second - - // Then update coordinates of each flake... - for(f=0; f< NUMFLAKES; f++) { - icons[f][YPOS] += icons[f][DELTAY]; - // If snowflake is off the bottom of the screen... - if (icons[f][YPOS] >= display.height()) { - // Reinitialize to a random position, just off the top - icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width()); - icons[f][YPOS] = -LOGO_HEIGHT; - icons[f][DELTAY] = random(1, 6); - } - } - } -} diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/ssd1306_128x64_spi/ssd1306_128x64_spi.ino b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/ssd1306_128x64_spi/ssd1306_128x64_spi.ino deleted file mode 100644 index dbe300d43..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/examples/ssd1306_128x64_spi/ssd1306_128x64_spi.ino +++ /dev/null @@ -1,424 +0,0 @@ -/************************************************************************** - This is an example for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - - This example is for a 128x64 pixel display using SPI to communicate - 4 or 5 pins are required to interface. - - Adafruit invests time and resources providing this open - source code, please support Adafruit and open-source - hardware by purchasing products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries, - with contributions from the open source community. - BSD license, check license.txt for more information - All text above, and the splash screen below must be - included in any redistribution. - **************************************************************************/ - -#include -#include -#include -#include - -#define SCREEN_WIDTH 128 // OLED display width, in pixels -#define SCREEN_HEIGHT 64 // OLED display height, in pixels - -// Declaration for SSD1306 display connected using software SPI (default case): -#define OLED_MOSI 9 -#define OLED_CLK 10 -#define OLED_DC 11 -#define OLED_CS 12 -#define OLED_RESET 13 -Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, - OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); - -/* Comment out above, uncomment this block to use hardware SPI -#define OLED_DC 6 -#define OLED_CS 7 -#define OLED_RESET 8 -Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, - &SPI, OLED_DC, OLED_RESET, OLED_CS); -*/ - -#define NUMFLAKES 10 // Number of snowflakes in the animation example - -#define LOGO_HEIGHT 16 -#define LOGO_WIDTH 16 -static const unsigned char PROGMEM logo_bmp[] = -{ B00000000, B11000000, - B00000001, B11000000, - B00000001, B11000000, - B00000011, B11100000, - B11110011, B11100000, - B11111110, B11111000, - B01111110, B11111111, - B00110011, B10011111, - B00011111, B11111100, - B00001101, B01110000, - B00011011, B10100000, - B00111111, B11100000, - B00111111, B11110000, - B01111100, B11110000, - B01110000, B01110000, - B00000000, B00110000 }; - -void setup() { - Serial.begin(9600); - - // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally - if(!display.begin(SSD1306_SWITCHCAPVCC)) { - Serial.println(F("SSD1306 allocation failed")); - for(;;); // Don't proceed, loop forever - } - - - // Show initial display buffer contents on the screen -- - // the library initializes this with an Adafruit splash screen. - display.display(); - delay(2000); // Pause for 2 seconds - - // Clear the buffer - display.clearDisplay(); - - // Draw a single pixel in white - display.drawPixel(10, 10, WHITE); - - // Show the display buffer on the screen. You MUST call display() after - // drawing commands to make them visible on screen! - display.display(); - delay(2000); - // display.display() is NOT necessary after every single drawing command, - // unless that's what you want...rather, you can batch up a bunch of - // drawing operations and then update the screen all at once by calling - // display.display(). These examples demonstrate both approaches... - - testdrawline(); // Draw many lines - - testdrawrect(); // Draw rectangles (outlines) - - testfillrect(); // Draw rectangles (filled) - - testdrawcircle(); // Draw circles (outlines) - - testfillcircle(); // Draw circles (filled) - - testdrawroundrect(); // Draw rounded rectangles (outlines) - - testfillroundrect(); // Draw rounded rectangles (filled) - - testdrawtriangle(); // Draw triangles (outlines) - - testfilltriangle(); // Draw triangles (filled) - - testdrawchar(); // Draw characters of the default font - - testdrawstyles(); // Draw 'stylized' characters - - testscrolltext(); // Draw scrolling text - - testdrawbitmap(); // Draw a small bitmap image - - // Invert and restore display, pausing in-between - display.invertDisplay(true); - delay(1000); - display.invertDisplay(false); - delay(1000); - - testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps -} - -void loop() { -} - -void testdrawline() { - int16_t i; - - display.clearDisplay(); // Clear display buffer - - for(i=0; i=0; i-=4) { - display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); - display.display(); - delay(1); - } - delay(250); - - display.clearDisplay(); - - for(i=display.width()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); - display.display(); - delay(1); - } - for(i=display.height()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); - display.display(); - delay(1); - } - delay(250); - - display.clearDisplay(); - - for(i=0; i0; i-=3) { - // The INVERSE color is used so circles alternate white/black - display.fillCircle(display.width() / 2, display.height() / 2, i, INVERSE); - display.display(); // Update screen with each newly-drawn circle - delay(1); - } - - delay(2000); -} - -void testdrawroundrect(void) { - display.clearDisplay(); - - for(int16_t i=0; i0; i-=5) { - // The INVERSE color is used so triangles alternate white/black - display.fillTriangle( - display.width()/2 , display.height()/2-i, - display.width()/2-i, display.height()/2+i, - display.width()/2+i, display.height()/2+i, INVERSE); - display.display(); - delay(1); - } - - delay(2000); -} - -void testdrawchar(void) { - display.clearDisplay(); - - display.setTextSize(1); // Normal 1:1 pixel scale - display.setTextColor(WHITE); // Draw white text - display.setCursor(0, 0); // Start at top-left corner - display.cp437(true); // Use full 256 char 'Code Page 437' font - - // Not all the characters will fit on the display. This is normal. - // Library will draw what it can and the rest will be clipped. - for(int16_t i=0; i<256; i++) { - if(i == '\n') display.write(' '); - else display.write(i); - } - - display.display(); - delay(2000); -} - -void testdrawstyles(void) { - display.clearDisplay(); - - display.setTextSize(1); // Normal 1:1 pixel scale - display.setTextColor(WHITE); // Draw white text - display.setCursor(0,0); // Start at top-left corner - display.println(F("Hello, world!")); - - display.setTextColor(BLACK, WHITE); // Draw 'inverse' text - display.println(3.141592); - - display.setTextSize(2); // Draw 2X-scale text - display.setTextColor(WHITE); - display.print(F("0x")); display.println(0xDEADBEEF, HEX); - - display.display(); - delay(2000); -} - -void testscrolltext(void) { - display.clearDisplay(); - - display.setTextSize(2); // Draw 2X-scale text - display.setTextColor(WHITE); - display.setCursor(10, 0); - display.println(F("scroll")); - display.display(); // Show initial text - delay(100); - - // Scroll in various directions, pausing in-between: - display.startscrollright(0x00, 0x0F); - delay(2000); - display.stopscroll(); - delay(1000); - display.startscrollleft(0x00, 0x0F); - delay(2000); - display.stopscroll(); - delay(1000); - display.startscrolldiagright(0x00, 0x07); - delay(2000); - display.startscrolldiagleft(0x00, 0x07); - delay(2000); - display.stopscroll(); - delay(1000); -} - -void testdrawbitmap(void) { - display.clearDisplay(); - - display.drawBitmap( - (display.width() - LOGO_WIDTH ) / 2, - (display.height() - LOGO_HEIGHT) / 2, - logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1); - display.display(); - delay(1000); -} - -#define XPOS 0 // Indexes into the 'icons' array in function below -#define YPOS 1 -#define DELTAY 2 - -void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) { - int8_t f, icons[NUMFLAKES][3]; - - // Initialize 'snowflake' positions - for(f=0; f< NUMFLAKES; f++) { - icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width()); - icons[f][YPOS] = -LOGO_HEIGHT; - icons[f][DELTAY] = random(1, 6); - Serial.print(F("x: ")); - Serial.print(icons[f][XPOS], DEC); - Serial.print(F(" y: ")); - Serial.print(icons[f][YPOS], DEC); - Serial.print(F(" dy: ")); - Serial.println(icons[f][DELTAY], DEC); - } - - for(;;) { // Loop forever... - display.clearDisplay(); // Clear the display buffer - - // Draw each snowflake: - for(f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, WHITE); - } - - display.display(); // Show the display buffer on the screen - delay(200); // Pause for 1/10 second - - // Then update coordinates of each flake... - for(f=0; f< NUMFLAKES; f++) { - icons[f][YPOS] += icons[f][DELTAY]; - // If snowflake is off the bottom of the screen... - if (icons[f][YPOS] >= display.height()) { - // Reinitialize to a random position, just off the top - icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width()); - icons[f][YPOS] = -LOGO_HEIGHT; - icons[f][DELTAY] = random(1, 6); - } - } - } -} diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/library.properties b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/library.properties deleted file mode 100644 index 61b8efa07..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=Adafruit SSD1306 -version=1.3.0 -author=Adafruit -maintainer=Adafruit -sentence=SSD1306 oled driver library for monochrome 128x64 and 128x32 displays -paragraph=SSD1306 oled driver library for monochrome 128x64 and 128x32 displays -category=Display -url=https://github.com/adafruit/Adafruit_SSD1306 -architectures=* diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/license.txt b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/license.txt deleted file mode 100644 index f6a0f22b8..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/license.txt +++ /dev/null @@ -1,26 +0,0 @@ -Software License Agreement (BSD License) - -Copyright (c) 2012, Adafruit Industries -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holders nor the -names of its contributors may be used to endorse or promote products -derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/splash.h b/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/splash.h deleted file mode 100644 index 487daecb4..000000000 --- a/lib/lib_display/Adafruit_SSD1306-1.3.0-gemu-1.1/splash.h +++ /dev/null @@ -1,108 +0,0 @@ -#define splash1_width 82 -#define splash1_height 64 - -const uint8_t PROGMEM splash1_data[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xF8, 0x7F, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFE, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFB, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xF9, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xF9, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xF1, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFC, - 0x73, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFE, 0x3F, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x1E, 0x0F, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x1F, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xDF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x19, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3C, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7E, 0x7C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFE, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xEF, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xCF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x07, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x07, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF0, 0x03, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, - 0x80, 0x00, 0xFC, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x07, 0x80, - 0x01, 0xFC, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x07, 0x80, 0x01, - 0xFC, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x07, 0x80, 0x01, 0xE0, - 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, - 0x00, 0x00, 0x1E, 0x00, 0x7F, 0xE3, 0xF7, 0x9F, 0xF9, 0xFD, 0xE7, 0x78, - 0x7B, 0xDF, 0xC0, 0xFF, 0xF7, 0xFF, 0xBF, 0xFD, 0xFD, 0xFF, 0x78, 0x7B, - 0xDF, 0xC0, 0xFF, 0xF7, 0xFF, 0xBF, 0xFD, 0xFD, 0xFF, 0x78, 0x7B, 0xDF, - 0xC0, 0xF0, 0xF7, 0x87, 0xBC, 0x3D, 0xE1, 0xFF, 0x78, 0x7B, 0xDE, 0x00, - 0xF0, 0xF7, 0x87, 0xBC, 0x3D, 0xE1, 0xF0, 0x78, 0x7B, 0xDE, 0x00, 0x00, - 0xF7, 0x87, 0x80, 0x3D, 0xE1, 0xE0, 0x78, 0x7B, 0xDE, 0x00, 0x7F, 0xF7, - 0x87, 0x9F, 0xFD, 0xE1, 0xE0, 0x78, 0x7B, 0xDE, 0x00, 0xFF, 0xF7, 0x87, - 0xBF, 0xFD, 0xE1, 0xE0, 0x78, 0x7B, 0xDE, 0x00, 0xF0, 0xF7, 0x87, 0xBC, - 0x3D, 0xE1, 0xE0, 0x78, 0x7B, 0xDE, 0x00, 0xF0, 0xF7, 0x87, 0xBC, 0x3D, - 0xE1, 0xE0, 0x78, 0x7B, 0xDE, 0x00, 0xF0, 0xF7, 0x87, 0xBC, 0x3D, 0xE1, - 0xE0, 0x78, 0x7B, 0xDE, 0x00, 0xFF, 0xF7, 0xFF, 0xBF, 0xFD, 0xE1, 0xE0, - 0x7F, 0xFB, 0xDF, 0xC0, 0xFF, 0xF7, 0xFF, 0xBF, 0xFD, 0xE1, 0xE0, 0x7F, - 0xFB, 0xDF, 0xC0, 0x7C, 0xF3, 0xF3, 0x9F, 0x3D, 0xE1, 0xE0, 0x3E, 0x7B, - 0xCF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0x68, 0xDB, 0x11, 0x1A, 0x31, 0xC0, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFD, 0x2B, 0x5A, 0xFB, 0x6A, 0xEF, 0xC0, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFD, 0x4B, 0x5B, 0x3B, 0x1A, 0x33, 0xC0, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFD, 0x6B, 0x5B, 0xDB, 0x6A, 0xFD, 0xC0 }; - -#define splash2_width 115 -#define splash2_height 32 - -const uint8_t PROGMEM splash2_data[] = { - 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF8, - 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x7E, 0x00, 0x00, 0x01, 0xE0, 0x00, - 0x7F, 0x0F, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0xFE, 0x00, 0x00, - 0x01, 0xE0, 0x00, 0xFF, 0xEF, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, - 0xFE, 0x00, 0x00, 0x01, 0xE0, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x7F, 0xFE, 0x7F, - 0xC0, 0x00, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0x00, - 0x3F, 0xFE, 0x7F, 0xF8, 0x3F, 0xF1, 0xFB, 0xCF, 0xFC, 0xFE, 0xF3, 0xBC, - 0x3D, 0xEF, 0xE0, 0x1F, 0xFE, 0x7F, 0xFF, 0x7F, 0xFB, 0xFF, 0xDF, 0xFE, - 0xFE, 0xFF, 0xBC, 0x3D, 0xEF, 0xE0, 0x1F, 0xC6, 0xFF, 0xFF, 0x7F, 0xFB, - 0xFF, 0xDF, 0xFE, 0xFE, 0xFF, 0xBC, 0x3D, 0xEF, 0xE0, 0x0F, 0xE3, 0xC7, - 0xFE, 0x78, 0x7B, 0xC3, 0xDE, 0x1E, 0xF0, 0xFF, 0xBC, 0x3D, 0xEF, 0x00, - 0x07, 0xFF, 0x87, 0xFC, 0x78, 0x7B, 0xC3, 0xDE, 0x1E, 0xF0, 0xF8, 0x3C, - 0x3D, 0xEF, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x7B, 0xC3, 0xC0, 0x1E, - 0xF0, 0xF0, 0x3C, 0x3D, 0xEF, 0x00, 0x01, 0xF3, 0x7F, 0xE0, 0x3F, 0xFB, - 0xC3, 0xCF, 0xFE, 0xF0, 0xF0, 0x3C, 0x3D, 0xEF, 0x00, 0x03, 0xE3, 0x3F, - 0x80, 0x7F, 0xFB, 0xC3, 0xDF, 0xFE, 0xF0, 0xF0, 0x3C, 0x3D, 0xEF, 0x00, - 0x07, 0xE7, 0x3C, 0x00, 0x78, 0x7B, 0xC3, 0xDE, 0x1E, 0xF0, 0xF0, 0x3C, - 0x3D, 0xEF, 0x00, 0x07, 0xFF, 0xBE, 0x00, 0x78, 0x7B, 0xC3, 0xDE, 0x1E, - 0xF0, 0xF0, 0x3C, 0x3D, 0xEF, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x78, 0x7B, - 0xC3, 0xDE, 0x1E, 0xF0, 0xF0, 0x3C, 0x3D, 0xEF, 0x00, 0x0F, 0xFF, 0xFE, - 0x00, 0x7F, 0xFB, 0xFF, 0xDF, 0xFE, 0xF0, 0xF0, 0x3F, 0xFD, 0xEF, 0xE0, - 0x0F, 0xFF, 0xFF, 0x00, 0x7F, 0xFB, 0xFF, 0xDF, 0xFE, 0xF0, 0xF0, 0x3F, - 0xFD, 0xEF, 0xE0, 0x0F, 0xF9, 0xFF, 0x00, 0x3E, 0x79, 0xF9, 0xCF, 0x9E, - 0xF0, 0xF0, 0x1F, 0x3D, 0xE7, 0xE0, 0x1F, 0xF1, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80, 0xFF, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x1C, 0x00, 0x7F, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0xB4, 0x6D, 0x88, - 0x8D, 0x18, 0xE0, 0x00, 0x00, 0x1F, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, - 0x95, 0xAD, 0x7D, 0xB5, 0x77, 0xE0, 0x00, 0x00, 0x0F, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFE, 0xA5, 0xAD, 0x9D, 0x8D, 0x19, 0xE0, 0x00, 0x00, 0x06, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0xB5, 0xAD, 0xED, 0xB5, 0x7E, 0xE0 }; diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp deleted file mode 100644 index bf1d5cb1d..000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp +++ /dev/null @@ -1,2222 +0,0 @@ -/* - * This class is basically the same as Adafruit_SPITFT. - * The only difference is: it extends Renderer which extends Adafruit_GFX. - * The original Adafruit_SPITFT class directly extends Adafruit_GFX. - */ -/*! - * @file Adafruit_SPITFT_Renderer.cpp - * - * @mainpage Adafruit SPI TFT Displays (and some others) - * - * @section intro_sec Introduction - * - * Part of Adafruit's GFX graphics library. Originally this class was - * written to handle a range of color TFT displays connected via SPI, - * but over time this library and some display-specific subclasses have - * mutated to include some color OLEDs as well as parallel-interfaced - * displays. The name's been kept for the sake of older code. - * - * Adafruit invests time and resources providing this open source code, - * please support Adafruit and open-source hardware by purchasing - * products from Adafruit! - - * @section dependencies Dependencies - * - * This library depends on - * Adafruit_GFX being present on your system. Please make sure you have - * installed the latest version before using this library. - * - * @section author Author - * - * Written by Limor "ladyada" Fried for Adafruit Industries, - * with contributions from the open source community. - * - * @section license License - * - * BSD license, all text here must be included in any redistribution. - */ - -#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all - -#include "Adafruit_SPITFT_Renderer.h" - -#if defined(__AVR__) -#if defined(__AVR_XMEGA__) //only tested with __AVR_ATmega4809__ -#define AVR_WRITESPI(x) for(SPI0_DATA = (x); (!(SPI0_INTFLAGS & _BV(SPI_IF_bp))); ) -#else -#define AVR_WRITESPI(x) for(SPDR = (x); (!(SPSR & _BV(SPIF))); ) -#endif -#endif - -#if defined(PORT_IOBUS) -// On SAMD21, redefine digitalPinToPort() to use the slightly-faster -// PORT_IOBUS rather than PORT (not needed on SAMD51). -#undef digitalPinToPort -#define digitalPinToPort(P) (&(PORT_IOBUS->Group[g_APinDescription[P].ulPort])) -#endif // end PORT_IOBUS - -#if defined(USE_SPI_DMA) - #include - #include "wiring_private.h" // pinPeripheral() function - #include // memalign() function - #define tcNum 2 // Timer/Counter for parallel write strobe PWM - #define wrPeripheral PIO_CCL // Use CCL to invert write strobe - - // DMA transfer-in-progress indicator and callback - static volatile bool dma_busy = false; - static void dma_callback(Adafruit_ZeroDMA *dma) { - dma_busy = false; - } - - #if defined(__SAMD51__) - // Timer/counter info by index # - static const struct { - Tc *tc; // -> Timer/Counter base address - int gclk; // GCLK ID - int evu; // EVSYS user ID - } tcList[] = { - { TC0, TC0_GCLK_ID, EVSYS_ID_USER_TC0_EVU }, - { TC1, TC1_GCLK_ID, EVSYS_ID_USER_TC1_EVU }, - { TC2, TC2_GCLK_ID, EVSYS_ID_USER_TC2_EVU }, - { TC3, TC3_GCLK_ID, EVSYS_ID_USER_TC3_EVU }, - #if defined(TC4) - { TC4, TC4_GCLK_ID, EVSYS_ID_USER_TC4_EVU }, - #endif - #if defined(TC5) - { TC5, TC5_GCLK_ID, EVSYS_ID_USER_TC5_EVU }, - #endif - #if defined(TC6) - { TC6, TC6_GCLK_ID, EVSYS_ID_USER_TC6_EVU }, - #endif - #if defined(TC7) - { TC7, TC7_GCLK_ID, EVSYS_ID_USER_TC7_EVU } - #endif - }; - #define NUM_TIMERS (sizeof tcList / sizeof tcList[0]) ///< # timer/counters - #endif // end __SAMD51__ - -#endif // end USE_SPI_DMA - -// Possible values for Adafruit_SPITFT_Renderer.connection: -#define TFT_HARD_SPI 0 ///< Display interface = hardware SPI -#define TFT_SOFT_SPI 1 ///< Display interface = software SPI -#define TFT_PARALLEL 2 ///< Display interface = 8- or 16-bit parallel - - -// CONSTRUCTORS ------------------------------------------------------------ - -/*! - @brief Adafruit_SPITFT_Renderer constructor for software (bitbang) SPI. - @param w Display width in pixels at default rotation setting (0). - @param h Display height in pixels at default rotation setting (0). - @param cs Arduino pin # for chip-select (-1 if unused, tie CS low). - @param dc Arduino pin # for data/command select (required). - @param mosi Arduino pin # for bitbang SPI MOSI signal (required). - @param sck Arduino pin # for bitbang SPI SCK signal (required). - @param rst Arduino pin # for display reset (optional, display reset - can be tied to MCU reset, default of -1 means unused). - @param miso Arduino pin # for bitbang SPI MISO signal (optional, - -1 default, many displays don't support SPI read). - @return Adafruit_SPITFT_Renderer object. - @note Output pins are not initialized; application typically will - need to call subclass' begin() function, which in turn calls - this library's initSPI() function to initialize pins. -*/ -Adafruit_SPITFT_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, - int8_t cs, int8_t dc, int8_t mosi, int8_t sck, int8_t rst, int8_t miso) : - Renderer(w, h), connection(TFT_SOFT_SPI), _rst(rst), _cs(cs), _dc(dc) { - swspi._sck = sck; - swspi._mosi = mosi; - swspi._miso = miso; -#if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - #if defined(CORE_TEENSY) - #if !defined(KINETISK) - dcPinMask = digitalPinToBitMask(dc); - swspi.sckPinMask = digitalPinToBitMask(sck); - swspi.mosiPinMask = digitalPinToBitMask(mosi); - #endif - dcPortSet = portSetRegister(dc); - dcPortClr = portClearRegister(dc); - swspi.sckPortSet = portSetRegister(sck); - swspi.sckPortClr = portClearRegister(sck); - swspi.mosiPortSet = portSetRegister(mosi); - swspi.mosiPortClr = portClearRegister(mosi); - if(cs >= 0) { - #if !defined(KINETISK) - csPinMask = digitalPinToBitMask(cs); - #endif - csPortSet = portSetRegister(cs); - csPortClr = portClearRegister(cs); - } else { - #if !defined(KINETISK) - csPinMask = 0; - #endif - csPortSet = dcPortSet; - csPortClr = dcPortClr; - } - if(miso >= 0) { - swspi.misoPort = portInputRegister(miso); - #if !defined(KINETISK) - swspi.misoPinMask = digitalPinToBitMask(miso); - #endif - } else { - swspi.misoPort = portInputRegister(dc); - } - #else // !CORE_TEENSY - dcPinMask =digitalPinToBitMask(dc); - swspi.sckPinMask =digitalPinToBitMask(sck); - swspi.mosiPinMask=digitalPinToBitMask(mosi); - dcPortSet =&(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg); - dcPortClr =&(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg); - swspi.sckPortSet =&(PORT->Group[g_APinDescription[sck].ulPort].OUTSET.reg); - swspi.sckPortClr =&(PORT->Group[g_APinDescription[sck].ulPort].OUTCLR.reg); - swspi.mosiPortSet=&(PORT->Group[g_APinDescription[mosi].ulPort].OUTSET.reg); - swspi.mosiPortClr=&(PORT->Group[g_APinDescription[mosi].ulPort].OUTCLR.reg); - if(cs >= 0) { - csPinMask = digitalPinToBitMask(cs); - csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg); - csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg); - } else { - // No chip-select line defined; might be permanently tied to GND. - // Assign a valid GPIO register (though not used for CS), and an - // empty pin bitmask...the nonsense bit-twiddling might be faster - // than checking _cs and possibly branching. - csPortSet = dcPortSet; - csPortClr = dcPortClr; - csPinMask = 0; - } - if(miso >= 0) { - swspi.misoPinMask=digitalPinToBitMask(miso); - swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(miso)); - } else { - swspi.misoPinMask=0; - swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(dc)); - } - #endif // end !CORE_TEENSY - #else // !HAS_PORT_SET_CLR - dcPort =(PORTreg_t)portOutputRegister(digitalPinToPort(dc)); - dcPinMaskSet =digitalPinToBitMask(dc); - swspi.sckPort =(PORTreg_t)portOutputRegister(digitalPinToPort(sck)); - swspi.sckPinMaskSet =digitalPinToBitMask(sck); - swspi.mosiPort =(PORTreg_t)portOutputRegister(digitalPinToPort(mosi)); - swspi.mosiPinMaskSet=digitalPinToBitMask(mosi); - if(cs >= 0) { - csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs)); - csPinMaskSet = digitalPinToBitMask(cs); - } else { - // No chip-select line defined; might be permanently tied to GND. - // Assign a valid GPIO register (though not used for CS), and an - // empty pin bitmask...the nonsense bit-twiddling might be faster - // than checking _cs and possibly branching. - csPort = dcPort; - csPinMaskSet = 0; - } - if(miso >= 0) { - swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(miso)); - swspi.misoPinMask=digitalPinToBitMask(miso); - } else { - swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(dc)); - swspi.misoPinMask=0; - } - csPinMaskClr = ~csPinMaskSet; - dcPinMaskClr = ~dcPinMaskSet; - swspi.sckPinMaskClr = ~swspi.sckPinMaskSet; - swspi.mosiPinMaskClr = ~swspi.mosiPinMaskSet; - #endif // !end HAS_PORT_SET_CLR -#endif // end USE_FAST_PINIO -} - -/*! - @brief Adafruit_SPITFT_Renderer constructor for hardware SPI using the board's - default SPI peripheral. - @param w Display width in pixels at default rotation setting (0). - @param h Display height in pixels at default rotation setting (0). - @param cs Arduino pin # for chip-select (-1 if unused, tie CS low). - @param dc Arduino pin # for data/command select (required). - @param rst Arduino pin # for display reset (optional, display reset - can be tied to MCU reset, default of -1 means unused). - @return Adafruit_SPITFT_Renderer object. - @note Output pins are not initialized; application typically will - need to call subclass' begin() function, which in turn calls - this library's initSPI() function to initialize pins. -*/ -#if defined(ESP8266) // See notes below -Adafruit_SPITFT_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, int8_t cs, - int8_t dc, int8_t rst) : Renderer(w, h), - connection(TFT_HARD_SPI), _rst(rst), _cs(cs), _dc(dc) { - hwspi._spi = &SPI; -} -#else // !ESP8266 -Adafruit_SPITFT_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, int8_t cs, - int8_t dc, int8_t rst) : Adafruit_SPITFT_Renderer(w, h, &SPI, cs, dc, rst) { - // This just invokes the hardware SPI constructor below, - // passing the default SPI device (&SPI). -} -#endif // end !ESP8266 - -#if !defined(ESP8266) -// ESP8266 compiler freaks out at this constructor -- it can't disambiguate -// beteween the SPIClass pointer (argument #3) and a regular integer. -// Solution here it to just not offer this variant on the ESP8266. You can -// use the default hardware SPI peripheral, or you can use software SPI, -// but if there's any library out there that creates a 'virtual' SPIClass -// peripheral and drives it with software bitbanging, that's not supported. -/*! - @brief Adafruit_SPITFT_Renderer constructor for hardware SPI using a specific - SPI peripheral. - @param w Display width in pixels at default rotation (0). - @param h Display height in pixels at default rotation (0). - @param spiClass Pointer to SPIClass type (e.g. &SPI or &SPI1). - @param cs Arduino pin # for chip-select (-1 if unused, tie CS low). - @param dc Arduino pin # for data/command select (required). - @param rst Arduino pin # for display reset (optional, display reset - can be tied to MCU reset, default of -1 means unused). - @return Adafruit_SPITFT_Renderer object. - @note Output pins are not initialized in constructor; application - typically will need to call subclass' begin() function, which - in turn calls this library's initSPI() function to initialize - pins. EXCEPT...if you have built your own SERCOM SPI peripheral - (calling the SPIClass constructor) rather than one of the - built-in SPI devices (e.g. &SPI, &SPI1 and so forth), you will - need to call the begin() function for your object as well as - pinPeripheral() for the MOSI, MISO and SCK pins to configure - GPIO manually. Do this BEFORE calling the display-specific - begin or init function. Unfortunate but unavoidable. -*/ -Adafruit_SPITFT_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, SPIClass *spiClass, - int8_t cs, int8_t dc, int8_t rst) : Renderer(w, h), - connection(TFT_HARD_SPI), _rst(rst), _cs(cs), _dc(dc) { - hwspi._spi = spiClass; -#if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - #if defined(CORE_TEENSY) - #if !defined(KINETISK) - dcPinMask = digitalPinToBitMask(dc); - #endif - dcPortSet = portSetRegister(dc); - dcPortClr = portClearRegister(dc); - if(cs >= 0) { - #if !defined(KINETISK) - csPinMask = digitalPinToBitMask(cs); - #endif - csPortSet = portSetRegister(cs); - csPortClr = portClearRegister(cs); - } else { // see comments below - #if !defined(KINETISK) - csPinMask = 0; - #endif - csPortSet = dcPortSet; - csPortClr = dcPortClr; - } - #else // !CORE_TEENSY - dcPinMask = digitalPinToBitMask(dc); - dcPortSet = &(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg); - dcPortClr = &(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg); - if(cs >= 0) { - csPinMask = digitalPinToBitMask(cs); - csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg); - csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg); - } else { - // No chip-select line defined; might be permanently tied to GND. - // Assign a valid GPIO register (though not used for CS), and an - // empty pin bitmask...the nonsense bit-twiddling might be faster - // than checking _cs and possibly branching. - csPortSet = dcPortSet; - csPortClr = dcPortClr; - csPinMask = 0; - } - #endif // end !CORE_TEENSY - #else // !HAS_PORT_SET_CLR - dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(dc)); - dcPinMaskSet = digitalPinToBitMask(dc); - if(cs >= 0) { - csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs)); - csPinMaskSet = digitalPinToBitMask(cs); - } else { - // No chip-select line defined; might be permanently tied to GND. - // Assign a valid GPIO register (though not used for CS), and an - // empty pin bitmask...the nonsense bit-twiddling might be faster - // than checking _cs and possibly branching. - csPort = dcPort; - csPinMaskSet = 0; - } - csPinMaskClr = ~csPinMaskSet; - dcPinMaskClr = ~dcPinMaskSet; - #endif // end !HAS_PORT_SET_CLR -#endif // end USE_FAST_PINIO -} -#endif // end !ESP8266 - -/*! - @brief Adafruit_SPITFT_Renderer constructor for parallel display connection. - @param w Display width in pixels at default rotation (0). - @param h Display height in pixels at default rotation (0). - @param busWidth If tft16 (enumeration in header file), is a 16-bit - parallel connection, else 8-bit. - 16-bit isn't fully implemented or tested yet so - applications should pass "tft8bitbus_Renderer" for now...needed to - stick a required enum argument in there to - disambiguate this constructor from the soft-SPI case. - Argument is ignored on 8-bit architectures (no 'wide' - support there since PORTs are 8 bits anyway). - @param d0 Arduino pin # for data bit 0 (1+ are extrapolated). - The 8 (or 16) data bits MUST be contiguous and byte- - aligned (or word-aligned for wide interface) within - the same PORT register (might not correspond to - Arduino pin sequence). - @param wr Arduino pin # for write strobe (required). - @param dc Arduino pin # for data/command select (required). - @param cs Arduino pin # for chip-select (optional, -1 if unused, - tie CS low). - @param rst Arduino pin # for display reset (optional, display reset - can be tied to MCU reset, default of -1 means unused). - @param rd Arduino pin # for read strobe (optional, -1 if unused). - @return Adafruit_SPITFT_Renderer object. - @note Output pins are not initialized; application typically will need - to call subclass' begin() function, which in turn calls this - library's initSPI() function to initialize pins. - Yes, the name is a misnomer...this library originally handled - only SPI displays, parallel being a recent addition (but not - wanting to break existing code). -*/ -Adafruit_SPITFT_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, tftBusWidth_Renderer busWidth, - int8_t d0, int8_t wr, int8_t dc, int8_t cs, int8_t rst, int8_t rd) : - Renderer(w, h), connection(TFT_PARALLEL), _rst(rst), _cs(cs), _dc(dc) { - tft8._d0 = d0; - tft8._wr = wr; - tft8._rd = rd; - tft8.wide = (busWidth == tft16bitbus_Renderer); -#if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - #if defined(CORE_TEENSY) - tft8.wrPortSet = portSetRegister(wr); - tft8.wrPortClr = portClearRegister(wr); - #if !defined(KINETISK) - dcPinMask = digitalPinToBitMask(dc); - #endif - dcPortSet = portSetRegister(dc); - dcPortClr = portClearRegister(dc); - if(cs >= 0) { - #if !defined(KINETISK) - csPinMask = digitalPinToBitMask(cs); - #endif - csPortSet = portSetRegister(cs); - csPortClr = portClearRegister(cs); - } else { // see comments below - #if !defined(KINETISK) - csPinMask = 0; - #endif - csPortSet = dcPortSet; - csPortClr = dcPortClr; - } - if(rd >= 0) { // if read-strobe pin specified... - #if defined(KINETISK) - tft8.rdPinMask = 1; - #else // !KINETISK - tft8.rdPinMask = digitalPinToBitMask(rd); - #endif - tft8.rdPortSet = portSetRegister(rd); - tft8.rdPortClr = portClearRegister(rd); - } else { - tft8.rdPinMask = 0; - tft8.rdPortSet = dcPortSet; - tft8.rdPortClr = dcPortClr; - } - // These are all uint8_t* pointers -- elsewhere they're recast - // as necessary if a 'wide' 16-bit interface is in use. - tft8.writePort = portOutputRegister(d0); - tft8.readPort = portInputRegister(d0); - tft8.dirSet = portModeRegister(d0); - tft8.dirClr = portModeRegister(d0); - #else // !CORE_TEENSY - tft8.wrPinMask = digitalPinToBitMask(wr); - tft8.wrPortSet = &(PORT->Group[g_APinDescription[wr].ulPort].OUTSET.reg); - tft8.wrPortClr = &(PORT->Group[g_APinDescription[wr].ulPort].OUTCLR.reg); - dcPinMask = digitalPinToBitMask(dc); - dcPortSet = &(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg); - dcPortClr = &(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg); - if(cs >= 0) { - csPinMask = digitalPinToBitMask(cs); - csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg); - csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg); - } else { - // No chip-select line defined; might be permanently tied to GND. - // Assign a valid GPIO register (though not used for CS), and an - // empty pin bitmask...the nonsense bit-twiddling might be faster - // than checking _cs and possibly branching. - csPortSet = dcPortSet; - csPortClr = dcPortClr; - csPinMask = 0; - } - if(rd >= 0) { // if read-strobe pin specified... - tft8.rdPinMask =digitalPinToBitMask(rd); - tft8.rdPortSet =&(PORT->Group[g_APinDescription[rd].ulPort].OUTSET.reg); - tft8.rdPortClr =&(PORT->Group[g_APinDescription[rd].ulPort].OUTCLR.reg); - } else { - tft8.rdPinMask = 0; - tft8.rdPortSet = dcPortSet; - tft8.rdPortClr = dcPortClr; - } - // Get pointers to PORT write/read/dir bytes within 32-bit PORT - uint8_t dBit = g_APinDescription[d0].ulPin; // d0 bit # in PORT - PortGroup *p = (&(PORT->Group[g_APinDescription[d0].ulPort])); - uint8_t offset = dBit / 8; // d[7:0] byte # within PORT - if(tft8.wide) offset &= ~1; // d[15:8] byte # within PORT - // These are all uint8_t* pointers -- elsewhere they're recast - // as necessary if a 'wide' 16-bit interface is in use. - tft8.writePort = (volatile uint8_t *)&(p->OUT.reg) + offset; - tft8.readPort = (volatile uint8_t *)&(p->IN.reg) + offset; - tft8.dirSet = (volatile uint8_t *)&(p->DIRSET.reg) + offset; - tft8.dirClr = (volatile uint8_t *)&(p->DIRCLR.reg) + offset; - #endif // end !CORE_TEENSY - #else // !HAS_PORT_SET_CLR - tft8.wrPort = (PORTreg_t)portOutputRegister(digitalPinToPort(wr)); - tft8.wrPinMaskSet = digitalPinToBitMask(wr); - dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(dc)); - dcPinMaskSet = digitalPinToBitMask(dc); - if(cs >= 0) { - csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs)); - csPinMaskSet = digitalPinToBitMask(cs); - } else { - // No chip-select line defined; might be permanently tied to GND. - // Assign a valid GPIO register (though not used for CS), and an - // empty pin bitmask...the nonsense bit-twiddling might be faster - // than checking _cs and possibly branching. - csPort = dcPort; - csPinMaskSet = 0; - } - if(rd >= 0) { // if read-strobe pin specified... - tft8.rdPort =(PORTreg_t)portOutputRegister(digitalPinToPort(rd)); - tft8.rdPinMaskSet =digitalPinToBitMask(rd); - } else { - tft8.rdPort = dcPort; - tft8.rdPinMaskSet = 0; - } - csPinMaskClr = ~csPinMaskSet; - dcPinMaskClr = ~dcPinMaskSet; - tft8.wrPinMaskClr = ~tft8.wrPinMaskSet; - tft8.rdPinMaskClr = ~tft8.rdPinMaskSet; - tft8.writePort = (PORTreg_t)portOutputRegister(digitalPinToPort(d0)); - tft8.readPort = (PORTreg_t)portInputRegister(digitalPinToPort(d0)); - tft8.portDir = (PORTreg_t)portModeRegister(digitalPinToPort(d0)); - #endif // end !HAS_PORT_SET_CLR -#endif // end USE_FAST_PINIO -} - -// end constructors ------- - - -// CLASS MEMBER FUNCTIONS -------------------------------------------------- - -// begin() and setAddrWindow() MUST be declared by any subclass. - -/*! - @brief Configure microcontroller pins for TFT interfacing. Typically - called by a subclass' begin() function. - @param freq SPI frequency when using hardware SPI. If default (0) - is passed, will fall back on a device-specific value. - Value is ignored when using software SPI or parallel - connection. - @param spiMode SPI mode when using hardware SPI. MUST be one of the - values SPI_MODE0, SPI_MODE1, SPI_MODE2 or SPI_MODE3 - defined in SPI.h. Do NOT attempt to pass '0' for - SPI_MODE0 and so forth...the values are NOT the same! - Use ONLY the defines! (Pity it's not an enum.) - @note Another anachronistically-named function; this is called even - when the display connection is parallel (not SPI). Also, this - could probably be made private...quite a few class functions - were generously put in the public section. -*/ -void Adafruit_SPITFT_Renderer::initSPI(uint32_t freq, uint8_t spiMode) { - - if(!freq) freq = DEFAULT_SPI_FREQ; // If no freq specified, use default - - // Init basic control pins common to all connection types - if(_cs >= 0) { - pinMode(_cs, OUTPUT); - digitalWrite(_cs, HIGH); // Deselect - } - pinMode(_dc, OUTPUT); - digitalWrite(_dc, HIGH); // Data mode - - if(connection == TFT_HARD_SPI) { - -#if defined(SPI_HAS_TRANSACTION) - hwspi.settings = SPISettings(freq, MSBFIRST, spiMode); -#else - hwspi._freq = freq; // Save freq value for later -#endif - hwspi._mode = spiMode; // Save spiMode value for later - // Call hwspi._spi->begin() ONLY if this is among the 'established' - // SPI interfaces in variant.h. For DIY roll-your-own SERCOM SPIs, - // begin() and pinPeripheral() calls MUST be made in one's calling - // code, BEFORE the screen-specific begin/init function is called. - // Reason for this is that SPI::begin() makes its own calls to - // pinPeripheral() based on g_APinDescription[n].ulPinType, which - // on non-established SPI interface pins will always be PIO_DIGITAL - // or similar, while we need PIO_SERCOM or PIO_SERCOM_ALT...it's - // highly unique between devices and variants for each pin or - // SERCOM so we can't make those calls ourselves here. And the SPI - // device needs to be set up before calling this because it's - // immediately followed with initialization commands. Blargh. - if( -#if !defined(SPI_INTERFACES_COUNT) - 1 -#endif -#if SPI_INTERFACES_COUNT > 0 - (hwspi._spi == &SPI) -#endif -#if SPI_INTERFACES_COUNT > 1 - || (hwspi._spi == &SPI1) -#endif -#if SPI_INTERFACES_COUNT > 2 - || (hwspi._spi == &SPI2) -#endif -#if SPI_INTERFACES_COUNT > 3 - || (hwspi._spi == &SPI3) -#endif -#if SPI_INTERFACES_COUNT > 4 - || (hwspi._spi == &SPI4) -#endif -#if SPI_INTERFACES_COUNT > 5 - || (hwspi._spi == &SPI5) -#endif - ) { - hwspi._spi->begin(); - } - } else if(connection == TFT_SOFT_SPI) { - - pinMode(swspi._mosi, OUTPUT); - digitalWrite(swspi._mosi, LOW); - pinMode(swspi._sck, OUTPUT); - digitalWrite(swspi._sck, LOW); - if(swspi._miso >= 0) { - pinMode(swspi._miso, INPUT); - } - - } else { // TFT_PARALLEL - - // Initialize data pins. We were only passed d0, so scan - // the pin description list looking for the other pins. - // They'll be on the same PORT, and within the next 7 (or 15) bits - // (because we need to write to a contiguous PORT byte or word). -#if defined(__AVR__) - // PORT registers are 8 bits wide, so just need a register match... - for(uint8_t i=0; i= dBit ) && - (g_APinDescription[i].ulPin <= (uint32_t)lastBit)) { - pinMode(i, OUTPUT); - digitalWrite(i, LOW); - } - } - #endif // end !CORE_TEENSY -#endif - pinMode(tft8._wr, OUTPUT); - digitalWrite(tft8._wr, HIGH); - if(tft8._rd >= 0) { - pinMode(tft8._rd, OUTPUT); - digitalWrite(tft8._rd, HIGH); - } - } - - if(_rst >= 0) { - // Toggle _rst low to reset - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - -#if defined(USE_SPI_DMA) - if(((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) && - (dma.allocate() == DMA_STATUS_OK)) { // Allocate channel - // The DMA library needs to alloc at least one valid descriptor, - // so we do that here. It's not used in the usual sense though, - // just before a transfer we copy descriptor[0] to this address. - if(dptr = dma.addDescriptor(NULL, NULL, 42, DMA_BEAT_SIZE_BYTE, - false, false)) { - // Alloc 2 scanlines worth of pixels on display's major axis, - // whichever that is, rounding each up to 2-pixel boundary. - int major = (WIDTH > HEIGHT) ? WIDTH : HEIGHT; - major += (major & 1); // -> next 2-pixel bound, if needed. - maxFillLen = major * 2; // 2 scanlines - // Note to future self: if you decide to make the pixel buffer - // much larger, remember that DMA transfer descriptors can't - // exceed 65,535 bytes (not 65,536), meaning 32,767 pixels max. - // Not that we have that kind of RAM to throw around right now. - if((pixelBuf[0] = - (uint16_t *)malloc(maxFillLen * sizeof(uint16_t)))) { - // Alloc OK. Get pointer to start of second scanline. - pixelBuf[1] = &pixelBuf[0][major]; - // Determine number of DMA descriptors needed to cover - // entire screen when entire 2-line pixelBuf is used - // (round up for fractional last descriptor). - int numDescriptors = (WIDTH * HEIGHT + (maxFillLen - 1)) / - maxFillLen; - // DMA descriptors MUST be 128-bit (16 byte) aligned. - // memalign() is considered obsolete but it's replacements - // (aligned_alloc() or posix_memalign()) are not currently - // available in the version of ARM GCC in use, but this - // is, so here we are. - if((descriptor = (DmacDescriptor *)memalign(16, - numDescriptors * sizeof(DmacDescriptor)))) { - int dmac_id; - volatile uint32_t *data_reg; - - if(connection == TFT_HARD_SPI) { - // THIS IS AN AFFRONT TO NATURE, but I don't know - // any "clean" way to get the sercom number from the - // the SPIClass pointer (e.g. &SPI or &SPI1), which - // is all we have to work with. SPIClass does contain - // a SERCOM pointer but it is a PRIVATE member! - // Doing an UNSPEAKABLY HORRIBLE THING here, directly - // accessing the first 32-bit value in the SPIClass - // structure, knowing that's (currently) where the - // SERCOM pointer lives, but this ENTIRELY DEPENDS on - // that structure not changing nor the compiler - // rearranging things. Oh the humanity! - - if(*(SERCOM **)hwspi._spi == &sercom0) { - dmac_id = SERCOM0_DMAC_ID_TX; - data_reg = &SERCOM0->SPI.DATA.reg; -#if defined SERCOM1 - } else if(*(SERCOM **)hwspi._spi == &sercom1) { - dmac_id = SERCOM1_DMAC_ID_TX; - data_reg = &SERCOM1->SPI.DATA.reg; -#endif -#if defined SERCOM2 - } else if(*(SERCOM **)hwspi._spi == &sercom2) { - dmac_id = SERCOM2_DMAC_ID_TX; - data_reg = &SERCOM2->SPI.DATA.reg; -#endif -#if defined SERCOM3 - } else if(*(SERCOM **)hwspi._spi == &sercom3) { - dmac_id = SERCOM3_DMAC_ID_TX; - data_reg = &SERCOM3->SPI.DATA.reg; -#endif -#if defined SERCOM4 - } else if(*(SERCOM **)hwspi._spi == &sercom4) { - dmac_id = SERCOM4_DMAC_ID_TX; - data_reg = &SERCOM4->SPI.DATA.reg; -#endif -#if defined SERCOM5 - } else if(*(SERCOM **)hwspi._spi == &sercom5) { - dmac_id = SERCOM5_DMAC_ID_TX; - data_reg = &SERCOM5->SPI.DATA.reg; -#endif -#if defined SERCOM6 - } else if(*(SERCOM **)hwspi._spi == &sercom6) { - dmac_id = SERCOM6_DMAC_ID_TX; - data_reg = &SERCOM6->SPI.DATA.reg; -#endif -#if defined SERCOM7 - } else if(*(SERCOM **)hwspi._spi == &sercom7) { - dmac_id = SERCOM7_DMAC_ID_TX; - data_reg = &SERCOM7->SPI.DATA.reg; -#endif - } - dma.setPriority(DMA_PRIORITY_3); - dma.setTrigger(dmac_id); - dma.setAction(DMA_TRIGGER_ACTON_BEAT); - - // Initialize descriptor list. - for(int d=0; dChannel[dmaChannel].CHEVCTRL.bit.EVOE = 1; - DMAC->Channel[dmaChannel].CHEVCTRL.bit.EVOMODE = 0; - - // CONFIGURE TIMER/COUNTER (for write strobe) - - Tc *timer = tcList[tcNum].tc; // -> Timer struct - int id = tcList[tcNum].gclk; // Timer GCLK ID - GCLK_PCHCTRL_Type pchctrl; - - // Set up timer clock source from GCLK - GCLK->PCHCTRL[id].bit.CHEN = 0; // Stop timer - while(GCLK->PCHCTRL[id].bit.CHEN); // Wait for it - pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK0_Val; - pchctrl.bit.CHEN = 1; // Enable - GCLK->PCHCTRL[id].reg = pchctrl.reg; - while(!GCLK->PCHCTRL[id].bit.CHEN); // Wait for it - - // Disable timer/counter before configuring it - timer->COUNT8.CTRLA.bit.ENABLE = 0; - while(timer->COUNT8.SYNCBUSY.bit.STATUS); - - timer->COUNT8.WAVE.bit.WAVEGEN = 2; // NPWM - timer->COUNT8.CTRLA.bit.MODE = 1; // 8-bit - timer->COUNT8.CTRLA.bit.PRESCALER = 0; // 1:1 - while(timer->COUNT8.SYNCBUSY.bit.STATUS); - - timer->COUNT8.CTRLBCLR.bit.DIR = 1; // Count UP - while(timer->COUNT8.SYNCBUSY.bit.CTRLB); - timer->COUNT8.CTRLBSET.bit.ONESHOT = 1; // One-shot - while(timer->COUNT8.SYNCBUSY.bit.CTRLB); - timer->COUNT8.PER.reg = 6; // PWM top - while(timer->COUNT8.SYNCBUSY.bit.PER); - timer->COUNT8.CC[0].reg = 2; // Compare - while(timer->COUNT8.SYNCBUSY.bit.CC0); - // Enable async input events, - // event action = restart. - timer->COUNT8.EVCTRL.bit.TCEI = 1; - timer->COUNT8.EVCTRL.bit.EVACT = 1; - - // Enable timer - timer->COUNT8.CTRLA.reg |= TC_CTRLA_ENABLE; - while(timer->COUNT8.SYNCBUSY.bit.STATUS); - -#if(wrPeripheral == PIO_CCL) - // CONFIGURE CCL (inverts timer/counter output) - - MCLK->APBCMASK.bit.CCL_ = 1; // Enable CCL clock - CCL->CTRL.bit.ENABLE = 0; // Disable to config - CCL->CTRL.bit.SWRST = 1; // Reset CCL registers - CCL->LUTCTRL[tcNum].bit.ENABLE = 0; // Disable LUT - CCL->LUTCTRL[tcNum].bit.FILTSEL = 0; // No filter - CCL->LUTCTRL[tcNum].bit.INSEL0 = 6; // TC input - CCL->LUTCTRL[tcNum].bit.INSEL1 = 0; // MASK - CCL->LUTCTRL[tcNum].bit.INSEL2 = 0; // MASK - CCL->LUTCTRL[tcNum].bit.TRUTH = 1; // Invert in 0 - CCL->LUTCTRL[tcNum].bit.ENABLE = 1; // Enable LUT - CCL->CTRL.bit.ENABLE = 1; // Enable CCL -#endif - - // CONFIGURE EVENT SYSTEM - - // Set up event system clock source from GCLK... - // Disable EVSYS, wait for disable - GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN = 0; - while(GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN); - pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK0_Val; - pchctrl.bit.CHEN = 1; // Re-enable - GCLK->PCHCTRL[EVSYS_GCLK_ID_0].reg = pchctrl.reg; - // Wait for it, then enable EVSYS clock - while(!GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN); - MCLK->APBBMASK.bit.EVSYS_ = 1; - - // Connect Timer EVU to ch 0 - EVSYS->USER[tcList[tcNum].evu].reg = 1; - // Datasheet recommends single write operation; - // reg instead of bit. Also datasheet: PATH bits - // must be zero when using async! - EVSYS_CHANNEL_Type ev; - ev.reg = 0; - ev.bit.PATH = 2; // Asynchronous - ev.bit.EVGEN = 0x22 + dmaChannel; // DMA channel 0+ - EVSYS->Channel[0].CHANNEL.reg = ev.reg; - - // Initialize descriptor list. - for(int d=0; d= 0) SPI_CS_LOW(); -} - -/*! - @brief Call after issuing command(s) or data to display. Performs - chip-deselect (if required) and ends an SPI transaction (if - using hardware SPI and transactions are supported). Required - for all display types; not an SPI-specific function. -*/ -void Adafruit_SPITFT_Renderer::endWrite(void) { - if(_cs >= 0) SPI_CS_HIGH(); - SPI_END_TRANSACTION(); -} - - -// ------------------------------------------------------------------------- -// Lower-level graphics operations. These functions require a chip-select -// and/or SPI transaction around them (via startWrite(), endWrite() above). -// Higher-level graphics primitives might start a single transaction and -// then make multiple calls to these functions (e.g. circle or text -// rendering might make repeated lines or rects) before ending the -// transaction. It's more efficient than starting a transaction every time. - -/*! - @brief Draw a single pixel to the display at requested coordinates. - Not self-contained; should follow a startWrite() call. - @param x Horizontal position (0 = left). - @param y Vertical position (0 = top). - @param color 16-bit pixel color in '565' RGB format. -*/ -void Adafruit_SPITFT_Renderer::writePixel(int16_t x, int16_t y, uint16_t color) { - if((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) { - setAddrWindow(x, y, 1, 1); - SPI_WRITE16(color); - } -} - -/*! - @brief Issue a series of pixels from memory to the display. Not self- - contained; should follow startWrite() and setAddrWindow() calls. - @param colors Pointer to array of 16-bit pixel values in '565' RGB - format. - @param len Number of elements in 'colors' array. - @param block If true (default case if unspecified), function blocks - until DMA transfer is complete. This is simply IGNORED - if DMA is not enabled. If false, the function returns - immediately after the last DMA transfer is started, - and one should use the dmaWait() function before - doing ANY other display-related activities (or even - any SPI-related activities, if using an SPI display - that shares the bus with other devices). - @param bigEndian If using DMA, and if set true, bitmap in memory is in - big-endian order (most significant byte first). By - default this is false, as most microcontrollers seem - to be little-endian and 16-bit pixel values must be - byte-swapped before issuing to the display (which tend - to be big-endian when using SPI or 8-bit parallel). - If an application can optimize around this -- for - example, a bitmap in a uint16_t array having the byte - values already reordered big-endian, this can save - some processing time here, ESPECIALLY if using this - function's non-blocking DMA mode. Not all cases are - covered...this is really here only for SAMD DMA and - much forethought on the application side. -*/ -void Adafruit_SPITFT_Renderer::writePixels(uint16_t *colors, uint32_t len, - bool block, bool bigEndian) { - - if(!len) return; // Avoid 0-byte transfers - -#if defined(ESP32) // ESP32 has a special SPI pixel-writing function... - if(connection == TFT_HARD_SPI) { - hwspi._spi->writePixels(colors, len * 2); - return; - } -#elif defined(USE_SPI_DMA) - if((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) { - int maxSpan = maxFillLen / 2; // One scanline max - uint8_t pixelBufIdx = 0; // Active pixel buffer number - #if defined(__SAMD51__) - if(connection == TFT_PARALLEL) { - // Switch WR pin to PWM or CCL - pinPeripheral(tft8._wr, wrPeripheral); - } - #endif // end __SAMD51__ - if(!bigEndian) { // Normal little-endian situation... - while(len) { - int count = (len < maxSpan) ? len : maxSpan; - - // Because TFT and SAMD endianisms are different, must swap - // bytes from the 'colors' array passed into a DMA working - // buffer. This can take place while the prior DMA transfer - // is in progress, hence the need for two pixelBufs. - for(int i=0; isetDataMode(hwspi._mode); - } else { - pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO - } - #endif // end __SAMD51__ || _SAMD21_ - } - return; - } -#endif // end USE_SPI_DMA - - // All other cases (bitbang SPI or non-DMA hard SPI or parallel), - // use a loop with the normal 16-bit data write function: - while(len--) { - SPI_WRITE16(*colors++); - } -} - -/*! - @brief Wait for the last DMA transfer in a prior non-blocking - writePixels() call to complete. This does nothing if DMA - is not enabled, and is not needed if blocking writePixels() - was used (as is the default case). -*/ -void Adafruit_SPITFT_Renderer::dmaWait(void) { -#if defined(USE_SPI_DMA) - while(dma_busy); - #if defined(__SAMD51__) || defined(_SAMD21_) - if(connection == TFT_HARD_SPI) { - // See SAMD51/21 note in writeColor() - hwspi._spi->setDataMode(hwspi._mode); - } else { - pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO - } - #endif // end __SAMD51__ || _SAMD21_ -#endif -} - -/*! - @brief Issue a series of pixels, all the same color. Not self- - contained; should follow startWrite() and setAddrWindow() calls. - @param color 16-bit pixel color in '565' RGB format. - @param len Number of pixels to draw. -*/ -void Adafruit_SPITFT_Renderer::writeColor(uint16_t color, uint32_t len) { - - if(!len) return; // Avoid 0-byte transfers - - uint8_t hi = color >> 8, lo = color; - -#if defined(ESP32) // ESP32 has a special SPI pixel-writing function... - if(connection == TFT_HARD_SPI) { - #define SPI_MAX_PIXELS_AT_ONCE 32 - #define TMPBUF_LONGWORDS (SPI_MAX_PIXELS_AT_ONCE + 1) / 2 - #define TMPBUF_PIXELS (TMPBUF_LONGWORDS * 2) - static uint32_t temp[TMPBUF_LONGWORDS]; - uint32_t c32 = color * 0x00010001; - uint16_t bufLen = (len < TMPBUF_PIXELS) ? len : TMPBUF_PIXELS, - xferLen, fillLen; - // Fill temp buffer 32 bits at a time - fillLen = (bufLen + 1) / 2; // Round up to next 32-bit boundary - for(uint32_t t=0; t= 16)) { // Don't bother with DMA on short pixel runs - int i, d, numDescriptors; - if(hi == lo) { // If high & low bytes are same... - onePixelBuf = color; - // Can do this with a relatively short descriptor list, - // each transferring a max of 32,767 (not 32,768) pixels. - // This won't run off the end of the allocated descriptor list, - // since we're using much larger chunks per descriptor here. - numDescriptors = (len + 32766) / 32767; - for(d=0; d lastFillLen) { - int fillStart = lastFillLen / 2, - fillEnd = (((len < maxFillLen) ? - len : maxFillLen) + 1) / 2; - for(i=fillStart; isetDataMode(hwspi._mode); - } else { - pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO - } - #endif // end __SAMD51__ - return; - } - #endif // end USE_SPI_DMA -#endif // end !ESP32 - - // All other cases (non-DMA hard SPI, bitbang SPI, parallel)... - - if(connection == TFT_HARD_SPI) { -#if defined(ESP8266) - do { - uint32_t pixelsThisPass = len; - if(pixelsThisPass > 50000) pixelsThisPass = 50000; - len -= pixelsThisPass; - yield(); // Periodic yield() on long fills - while(pixelsThisPass--) { - hwspi._spi->write(hi); - hwspi._spi->write(lo); - } - } while(len); -#else // !ESP8266 - while(len--) { - #if defined(__AVR__) - AVR_WRITESPI(hi); - AVR_WRITESPI(lo); - #elif defined(ESP32) - hwspi._spi->write(hi); - hwspi._spi->write(lo); - #else - hwspi._spi->transfer(hi); - hwspi._spi->transfer(lo); - #endif - } -#endif // end !ESP8266 - } else if(connection == TFT_SOFT_SPI) { -#if defined(ESP8266) - do { - uint32_t pixelsThisPass = len; - if(pixelsThisPass > 20000) pixelsThisPass = 20000; - len -= pixelsThisPass; - yield(); // Periodic yield() on long fills - while(pixelsThisPass--) { - for(uint16_t bit=0, x=color; bit<16; bit++) { - if(x & 0x8000) SPI_MOSI_HIGH(); - else SPI_MOSI_LOW(); - SPI_SCK_HIGH(); - SPI_SCK_LOW(); - x <<= 1; - } - } - } while(len); -#else // !ESP8266 - while(len--) { - #if defined(__AVR__) - for(uint8_t bit=0, x=hi; bit<8; bit++) { - if(x & 0x80) SPI_MOSI_HIGH(); - else SPI_MOSI_LOW(); - SPI_SCK_HIGH(); - SPI_SCK_LOW(); - x <<= 1; - } - for(uint8_t bit=0, x=lo; bit<8; bit++) { - if(x & 0x80) SPI_MOSI_HIGH(); - else SPI_MOSI_LOW(); - SPI_SCK_HIGH(); - SPI_SCK_LOW(); - x <<= 1; - } - #else // !__AVR__ - for(uint16_t bit=0, x=color; bit<16; bit++) { - if(x & 0x8000) SPI_MOSI_HIGH(); - else SPI_MOSI_LOW(); - SPI_SCK_HIGH(); - x <<= 1; - SPI_SCK_LOW(); - } - #endif // end !__AVR__ - } -#endif // end !ESP8266 - } else { // PARALLEL - if(hi == lo) { -#if defined(__AVR__) - len *= 2; - *tft8.writePort = hi; - while(len--) { - TFT_WR_STROBE(); - } -#elif defined(USE_FAST_PINIO) - if(!tft8.wide) { - len *= 2; - *tft8.writePort = hi; - } else { - *(volatile uint16_t *)tft8.writePort = color; - } - while(len--) { - TFT_WR_STROBE(); - } -#endif - } else { - while(len--) { -#if defined(__AVR__) - *tft8.writePort = hi; - TFT_WR_STROBE(); - *tft8.writePort = lo; -#elif defined(USE_FAST_PINIO) - if(!tft8.wide) { - *tft8.writePort = hi; - TFT_WR_STROBE(); - *tft8.writePort = lo; - } else { - *(volatile uint16_t *)tft8.writePort = color; - } -#endif - TFT_WR_STROBE(); - } - } - } -} - -/*! - @brief Draw a filled rectangle to the display. Not self-contained; - should follow startWrite(). Typically used by higher-level - graphics primitives; user code shouldn't need to call this and - is likely to use the self-contained fillRect() instead. - writeFillRect() performs its own edge clipping and rejection; - see writeFillRectPreclipped() for a more 'raw' implementation. - @param x Horizontal position of first corner. - @param y Vertical position of first corner. - @param w Rectangle width in pixels (positive = right of first - corner, negative = left of first corner). - @param h Rectangle height in pixels (positive = below first - corner, negative = above first corner). - @param color 16-bit fill color in '565' RGB format. - @note Written in this deep-nested way because C by definition will - optimize for the 'if' case, not the 'else' -- avoids branches - and rejects clipped rectangles at the least-work possibility. -*/ -void Adafruit_SPITFT_Renderer::writeFillRect(int16_t x, int16_t y, - int16_t w, int16_t h, uint16_t color) { - if(w && h) { // Nonzero width and height? - if(w < 0) { // If negative width... - x += w + 1; // Move X to left edge - w = -w; // Use positive width - } - if(x < _width) { // Not off right - if(h < 0) { // If negative height... - y += h + 1; // Move Y to top edge - h = -h; // Use positive height - } - if(y < _height) { // Not off bottom - int16_t x2 = x + w - 1; - if(x2 >= 0) { // Not off left - int16_t y2 = y + h - 1; - if(y2 >= 0) { // Not off top - // Rectangle partly or fully overlaps screen - if(x < 0) { x = 0; w = x2 + 1; } // Clip left - if(y < 0) { y = 0; h = y2 + 1; } // Clip top - if(x2 >= _width) { w = _width - x; } // Clip right - if(y2 >= _height) { h = _height - y; } // Clip bottom - writeFillRectPreclipped(x, y, w, h, color); - } - } - } - } - } -} - -/*! - @brief Draw a horizontal line on the display. Performs edge clipping - and rejection. Not self-contained; should follow startWrite(). - Typically used by higher-level graphics primitives; user code - shouldn't need to call this and is likely to use the self- - contained drawFastHLine() instead. - @param x Horizontal position of first point. - @param y Vertical position of first point. - @param w Line width in pixels (positive = right of first point, - negative = point of first corner). - @param color 16-bit line color in '565' RGB format. -*/ -void inline Adafruit_SPITFT_Renderer::writeFastHLine(int16_t x, int16_t y, int16_t w, - uint16_t color) { - if((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width - if(w < 0) { // If negative width... - x += w + 1; // Move X to left edge - w = -w; // Use positive width - } - if(x < _width) { // Not off right - int16_t x2 = x + w - 1; - if(x2 >= 0) { // Not off left - // Line partly or fully overlaps screen - if(x < 0) { x = 0; w = x2 + 1; } // Clip left - if(x2 >= _width) { w = _width - x; } // Clip right - writeFillRectPreclipped(x, y, w, 1, color); - } - } - } -} - -/*! - @brief Draw a vertical line on the display. Performs edge clipping and - rejection. Not self-contained; should follow startWrite(). - Typically used by higher-level graphics primitives; user code - shouldn't need to call this and is likely to use the self- - contained drawFastVLine() instead. - @param x Horizontal position of first point. - @param y Vertical position of first point. - @param h Line height in pixels (positive = below first point, - negative = above first point). - @param color 16-bit line color in '565' RGB format. -*/ -void inline Adafruit_SPITFT_Renderer::writeFastVLine(int16_t x, int16_t y, int16_t h, - uint16_t color) { - if((x >= 0) && (x < _width) && h) { // X on screen, nonzero height - if(h < 0) { // If negative height... - y += h + 1; // Move Y to top edge - h = -h; // Use positive height - } - if(y < _height) { // Not off bottom - int16_t y2 = y + h - 1; - if(y2 >= 0) { // Not off top - // Line partly or fully overlaps screen - if(y < 0) { y = 0; h = y2 + 1; } // Clip top - if(y2 >= _height) { h = _height - y; } // Clip bottom - writeFillRectPreclipped(x, y, 1, h, color); - } - } - } -} - -/*! - @brief A lower-level version of writeFillRect(). This version requires - all inputs are in-bounds, that width and height are positive, - and no part extends offscreen. NO EDGE CLIPPING OR REJECTION IS - PERFORMED. If higher-level graphics primitives are written to - handle their own clipping earlier in the drawing process, this - can avoid unnecessary function calls and repeated clipping - operations in the lower-level functions. - @param x Horizontal position of first corner. MUST BE WITHIN - SCREEN BOUNDS. - @param y Vertical position of first corner. MUST BE WITHIN SCREEN - BOUNDS. - @param w Rectangle width in pixels. MUST BE POSITIVE AND NOT - EXTEND OFF SCREEN. - @param h Rectangle height in pixels. MUST BE POSITIVE AND NOT - EXTEND OFF SCREEN. - @param color 16-bit fill color in '565' RGB format. - @note This is a new function, no graphics primitives besides rects - and horizontal/vertical lines are written to best use this yet. -*/ -inline void Adafruit_SPITFT_Renderer::writeFillRectPreclipped(int16_t x, int16_t y, - int16_t w, int16_t h, uint16_t color) { - setAddrWindow(x, y, w, h); - writeColor(color, (uint32_t)w * h); -} - - -// ------------------------------------------------------------------------- -// Ever-so-slightly higher-level graphics operations. Similar to the 'write' -// functions above, but these contain their own chip-select and SPI -// transactions as needed (via startWrite(), endWrite()). They're typically -// used solo -- as graphics primitives in themselves, not invoked by higher- -// level primitives (which should use the functions above for better -// performance). - -/*! - @brief Draw a single pixel to the display at requested coordinates. - Self-contained and provides its own transaction as needed - (see writePixel(x,y,color) for a lower-level variant). - Edge clipping is performed here. - @param x Horizontal position (0 = left). - @param y Vertical position (0 = top). - @param color 16-bit pixel color in '565' RGB format. -*/ -void Adafruit_SPITFT_Renderer::drawPixel(int16_t x, int16_t y, uint16_t color) { - // Clip first... - if((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) { - // THEN set up transaction (if needed) and draw... - startWrite(); - setAddrWindow(x, y, 1, 1); - SPI_WRITE16(color); - endWrite(); - } -} - -/*! - @brief Draw a filled rectangle to the display. Self-contained and - provides its own transaction as needed (see writeFillRect() or - writeFillRectPreclipped() for lower-level variants). Edge - clipping and rejection is performed here. - @param x Horizontal position of first corner. - @param y Vertical position of first corner. - @param w Rectangle width in pixels (positive = right of first - corner, negative = left of first corner). - @param h Rectangle height in pixels (positive = below first - corner, negative = above first corner). - @param color 16-bit fill color in '565' RGB format. - @note This repeats the writeFillRect() function almost in its entirety, - with the addition of a transaction start/end. It's done this way - (rather than starting the transaction and calling writeFillRect() - to handle clipping and so forth) so that the transaction isn't - performed at all if the rectangle is rejected. It's really not - that much code. -*/ -void Adafruit_SPITFT_Renderer::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color) { - if(w && h) { // Nonzero width and height? - if(w < 0) { // If negative width... - x += w + 1; // Move X to left edge - w = -w; // Use positive width - } - if(x < _width) { // Not off right - if(h < 0) { // If negative height... - y += h + 1; // Move Y to top edge - h = -h; // Use positive height - } - if(y < _height) { // Not off bottom - int16_t x2 = x + w - 1; - if(x2 >= 0) { // Not off left - int16_t y2 = y + h - 1; - if(y2 >= 0) { // Not off top - // Rectangle partly or fully overlaps screen - if(x < 0) { x = 0; w = x2 + 1; } // Clip left - if(y < 0) { y = 0; h = y2 + 1; } // Clip top - if(x2 >= _width) { w = _width - x; } // Clip right - if(y2 >= _height) { h = _height - y; } // Clip bottom - startWrite(); - writeFillRectPreclipped(x, y, w, h, color); - endWrite(); - } - } - } - } - } -} - -/*! - @brief Draw a horizontal line on the display. Self-contained and - provides its own transaction as needed (see writeFastHLine() for - a lower-level variant). Edge clipping and rejection is performed - here. - @param x Horizontal position of first point. - @param y Vertical position of first point. - @param w Line width in pixels (positive = right of first point, - negative = point of first corner). - @param color 16-bit line color in '565' RGB format. - @note This repeats the writeFastHLine() function almost in its - entirety, with the addition of a transaction start/end. It's - done this way (rather than starting the transaction and calling - writeFastHLine() to handle clipping and so forth) so that the - transaction isn't performed at all if the line is rejected. -*/ -void Adafruit_SPITFT_Renderer::drawFastHLine(int16_t x, int16_t y, int16_t w, - uint16_t color) { - if((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width - if(w < 0) { // If negative width... - x += w + 1; // Move X to left edge - w = -w; // Use positive width - } - if(x < _width) { // Not off right - int16_t x2 = x + w - 1; - if(x2 >= 0) { // Not off left - // Line partly or fully overlaps screen - if(x < 0) { x = 0; w = x2 + 1; } // Clip left - if(x2 >= _width) { w = _width - x; } // Clip right - startWrite(); - writeFillRectPreclipped(x, y, w, 1, color); - endWrite(); - } - } - } -} - -/*! - @brief Draw a vertical line on the display. Self-contained and provides - its own transaction as needed (see writeFastHLine() for a lower- - level variant). Edge clipping and rejection is performed here. - @param x Horizontal position of first point. - @param y Vertical position of first point. - @param h Line height in pixels (positive = below first point, - negative = above first point). - @param color 16-bit line color in '565' RGB format. - @note This repeats the writeFastVLine() function almost in its - entirety, with the addition of a transaction start/end. It's - done this way (rather than starting the transaction and calling - writeFastVLine() to handle clipping and so forth) so that the - transaction isn't performed at all if the line is rejected. -*/ -void Adafruit_SPITFT_Renderer::drawFastVLine(int16_t x, int16_t y, int16_t h, - uint16_t color) { - if((x >= 0) && (x < _width) && h) { // X on screen, nonzero height - if(h < 0) { // If negative height... - y += h + 1; // Move Y to top edge - h = -h; // Use positive height - } - if(y < _height) { // Not off bottom - int16_t y2 = y + h - 1; - if(y2 >= 0) { // Not off top - // Line partly or fully overlaps screen - if(y < 0) { y = 0; h = y2 + 1; } // Clip top - if(y2 >= _height) { h = _height - y; } // Clip bottom - startWrite(); - writeFillRectPreclipped(x, y, 1, h, color); - endWrite(); - } - } - } -} - -/*! - @brief Essentially writePixel() with a transaction around it. I don't - think this is in use by any of our code anymore (believe it was - for some older BMP-reading examples), but is kept here in case - any user code relies on it. Consider it DEPRECATED. - @param color 16-bit pixel color in '565' RGB format. -*/ -void Adafruit_SPITFT_Renderer::pushColor(uint16_t color) { - startWrite(); - SPI_WRITE16(color); - endWrite(); -} - -/*! - @brief Draw a 16-bit image (565 RGB) at the specified (x,y) position. - For 16-bit display devices; no color reduction performed. - Adapted from https://github.com/PaulStoffregen/ILI9341_t3 - by Marc MERLIN. See examples/pictureEmbed to use this. - 5/6/2017: function name and arguments have changed for - compatibility with current GFX library and to avoid naming - problems in prior implementation. Formerly drawBitmap() with - arguments in different order. Handles its own transaction and - edge clipping/rejection. - @param x Top left corner horizontal coordinate. - @param y Top left corner vertical coordinate. - @param pcolors Pointer to 16-bit array of pixel values. - @param w Width of bitmap in pixels. - @param h Height of bitmap in pixels. -*/ -void Adafruit_SPITFT_Renderer::drawRGBBitmap(int16_t x, int16_t y, - uint16_t *pcolors, int16_t w, int16_t h) { - - int16_t x2, y2; // Lower-right coord - if(( x >= _width ) || // Off-edge right - ( y >= _height) || // " top - ((x2 = (x+w-1)) < 0 ) || // " left - ((y2 = (y+h-1)) < 0) ) return; // " bottom - - int16_t bx1=0, by1=0, // Clipped top-left within bitmap - saveW=w; // Save original bitmap width value - if(x < 0) { // Clip left - w += x; - bx1 = -x; - x = 0; - } - if(y < 0) { // Clip top - h += y; - by1 = -y; - y = 0; - } - if(x2 >= _width ) w = _width - x; // Clip right - if(y2 >= _height) h = _height - y; // Clip bottom - - pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left - startWrite(); - setAddrWindow(x, y, w, h); // Clipped area - while(h--) { // For each (clipped) scanline... - writePixels(pcolors, w); // Push one (clipped) row - pcolors += saveW; // Advance pointer by one full (unclipped) line - } - endWrite(); -} - - -// ------------------------------------------------------------------------- -// Miscellaneous class member functions that don't draw anything. - -/*! - @brief Invert the colors of the display (if supported by hardware). - Self-contained, no transaction setup required. - @param i true = inverted display, false = normal display. -*/ -void Adafruit_SPITFT_Renderer::invertDisplay(bool i) { - startWrite(); - writeCommand(i ? invertOnCommand : invertOffCommand); - endWrite(); -} - -/*! - @brief Given 8-bit red, green and blue values, return a 'packed' - 16-bit color value in '565' RGB format (5 bits red, 6 bits - green, 5 bits blue). This is just a mathematical operation, - no hardware is touched. - @param red 8-bit red brightnesss (0 = off, 255 = max). - @param green 8-bit green brightnesss (0 = off, 255 = max). - @param blue 8-bit blue brightnesss (0 = off, 255 = max). - @return 'Packed' 16-bit color value (565 format). -*/ -uint16_t Adafruit_SPITFT_Renderer::color565(uint8_t red, uint8_t green, uint8_t blue) { - return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3); -} - -/*! - @brief Adafruit_SPITFT_Renderer Send Command handles complete sending of commands and data - @param commandByte The Command Byte - @param dataBytes A pointer to the Data bytes to send - @param numDataBytes The number of bytes we should send - */ -void Adafruit_SPITFT_Renderer::sendCommand(uint8_t commandByte, uint8_t *dataBytes, uint8_t numDataBytes) { - SPI_BEGIN_TRANSACTION(); - if(_cs >= 0) SPI_CS_LOW(); - - SPI_DC_LOW(); // Command mode - spiWrite(commandByte); // Send the command byte - - SPI_DC_HIGH(); - for (int i=0; i= 0) SPI_CS_HIGH(); - SPI_END_TRANSACTION(); -} - -/*! - @brief Adafruit_SPITFT_Renderer Send Command handles complete sending of commands and const data - @param commandByte The Command Byte - @param dataBytes A pointer to the Data bytes to send - @param numDataBytes The number of bytes we should send - */ -void Adafruit_SPITFT_Renderer::sendCommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes) { - SPI_BEGIN_TRANSACTION(); - if(_cs >= 0) SPI_CS_LOW(); - - SPI_DC_LOW(); // Command mode - spiWrite(commandByte); // Send the command byte - - SPI_DC_HIGH(); - for (int i=0; i= 0) SPI_CS_HIGH(); - SPI_END_TRANSACTION(); -} - -/*! - @brief Read 8 bits of data from display configuration memory (not RAM). - This is highly undocumented/supported and should be avoided, - function is only included because some of the examples use it. - @param commandByte - The command register to read data from. - @param index - The byte index into the command to read from. - @return Unsigned 8-bit data read from display register. - */ -/**************************************************************************/ -uint8_t Adafruit_SPITFT_Renderer::readcommand8(uint8_t commandByte, uint8_t index) { - uint8_t result; - startWrite(); - SPI_DC_LOW(); // Command mode - spiWrite(commandByte); - SPI_DC_HIGH(); // Data mode - do { - result = spiRead(); - } while(index--); // Discard bytes up to index'th - endWrite(); - return result; -} - -// ------------------------------------------------------------------------- -// Lowest-level hardware-interfacing functions. Many of these are inline and -// compile to different things based on #defines -- typically just a few -// instructions. Others, not so much, those are not inlined. - -/*! - @brief Start an SPI transaction if using the hardware SPI interface to - the display. If using an earlier version of the Arduino platform - (before the addition of SPI transactions), this instead attempts - to set up the SPI clock and mode. No action is taken if the - connection is not hardware SPI-based. This does NOT include a - chip-select operation -- see startWrite() for a function that - encapsulated both actions. -*/ -inline void Adafruit_SPITFT_Renderer::SPI_BEGIN_TRANSACTION(void) { - if(connection == TFT_HARD_SPI) { -#if defined(SPI_HAS_TRANSACTION) - hwspi._spi->beginTransaction(hwspi.settings); -#else // No transactions, configure SPI manually... - #if defined(__AVR__) || defined(TEENSYDUINO) || defined(ARDUINO_ARCH_STM32F1) - hwspi._spi->setClockDivider(SPI_CLOCK_DIV2); - #elif defined(__arm__) - hwspi._spi->setClockDivider(11); - #elif defined(ESP8266) || defined(ESP32) - hwspi._spi->setFrequency(hwspi._freq); - #elif defined(RASPI) || defined(ARDUINO_ARCH_STM32F1) - hwspi._spi->setClock(hwspi._freq); - #endif - hwspi._spi->setBitOrder(MSBFIRST); - hwspi._spi->setDataMode(hwspi._mode); -#endif // end !SPI_HAS_TRANSACTION - } -} - -/*! - @brief End an SPI transaction if using the hardware SPI interface to - the display. No action is taken if the connection is not - hardware SPI-based or if using an earlier version of the Arduino - platform (before the addition of SPI transactions). This does - NOT include a chip-deselect operation -- see endWrite() for a - function that encapsulated both actions. -*/ -inline void Adafruit_SPITFT_Renderer::SPI_END_TRANSACTION(void) { -#if defined(SPI_HAS_TRANSACTION) - if(connection == TFT_HARD_SPI) { - hwspi._spi->endTransaction(); - } -#endif -} - -/*! - @brief Issue a single 8-bit value to the display. Chip-select, - transaction and data/command selection must have been - previously set -- this ONLY issues the byte. This is another of - those functions in the library with a now-not-accurate name - that's being maintained for compatibility with outside code. - This function is used even if display connection is parallel. - @param b 8-bit value to write. -*/ -void Adafruit_SPITFT_Renderer::spiWrite(uint8_t b) { - if(connection == TFT_HARD_SPI) { -#if defined(__AVR__) - AVR_WRITESPI(b); -#elif defined(ESP8266) || defined(ESP32) - hwspi._spi->write(b); -#else - hwspi._spi->transfer(b); -#endif - } else if(connection == TFT_SOFT_SPI) { - for(uint8_t bit=0; bit<8; bit++) { - if(b & 0x80) SPI_MOSI_HIGH(); - else SPI_MOSI_LOW(); - SPI_SCK_HIGH(); - b <<= 1; - SPI_SCK_LOW(); - } - } else { // TFT_PARALLEL -#if defined(__AVR__) - *tft8.writePort = b; -#elif defined(USE_FAST_PINIO) - if(!tft8.wide) *tft8.writePort = b; - else *(volatile uint16_t *)tft8.writePort = b; -#endif - TFT_WR_STROBE(); - } -} - -/*! - @brief Write a single command byte to the display. Chip-select and - transaction must have been previously set -- this ONLY sets - the device to COMMAND mode, issues the byte and then restores - DATA mode. There is no corresponding explicit writeData() - function -- just use spiWrite(). - @param cmd 8-bit command to write. -*/ -void Adafruit_SPITFT_Renderer::writeCommand(uint8_t cmd) { - SPI_DC_LOW(); - spiWrite(cmd); - SPI_DC_HIGH(); -} - -/*! - @brief Read a single 8-bit value from the display. Chip-select and - transaction must have been previously set -- this ONLY reads - the byte. This is another of those functions in the library - with a now-not-accurate name that's being maintained for - compatibility with outside code. This function is used even if - display connection is parallel. - @return Unsigned 8-bit value read (always zero if USE_FAST_PINIO is - not supported by the MCU architecture). -*/ -uint8_t Adafruit_SPITFT_Renderer::spiRead(void) { - uint8_t b = 0; - uint16_t w = 0; - if(connection == TFT_HARD_SPI) { - return hwspi._spi->transfer((uint8_t)0); - } else if(connection == TFT_SOFT_SPI) { - if(swspi._miso >= 0) { - for(uint8_t i=0; i<8; i++) { - SPI_SCK_HIGH(); - b <<= 1; - if(SPI_MISO_READ()) b++; - SPI_SCK_LOW(); - } - } - return b; - } else { // TFT_PARALLEL - if(tft8._rd >= 0) { -#if defined(USE_FAST_PINIO) - TFT_RD_LOW(); // Read line LOW - #if defined(__AVR__) - *tft8.portDir = 0x00; // Set port to input state - w = *tft8.readPort; // Read value from port - *tft8.portDir = 0xFF; // Restore port to output - #else // !__AVR__ - if(!tft8.wide) { // 8-bit TFT connection - #if defined(HAS_PORT_SET_CLR) - *tft8.dirClr = 0xFF; // Set port to input state - w = *tft8.readPort; // Read value from port - *tft8.dirSet = 0xFF; // Restore port to output - #else // !HAS_PORT_SET_CLR - *tft8.portDir = 0x00; // Set port to input state - w = *tft8.readPort; // Read value from port - *tft8.portDir = 0xFF; // Restore port to output - #endif // end HAS_PORT_SET_CLR - } else { // 16-bit TFT connection - #if defined(HAS_PORT_SET_CLR) - *(volatile uint16_t *)tft8.dirClr = 0xFFFF; // Input state - w = *(volatile uint16_t *)tft8.readPort; // 16-bit read - *(volatile uint16_t *)tft8.dirSet = 0xFFFF; // Output state - #else // !HAS_PORT_SET_CLR - *(volatile uint16_t *)tft8.portDir = 0x0000; // Input state - w = *(volatile uint16_t *)tft8.readPort; // 16-bit read - *(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state - #endif // end !HAS_PORT_SET_CLR - } - TFT_RD_HIGH(); // Read line HIGH - #endif // end !__AVR__ -#else // !USE_FAST_PINIO - w = 0; // Parallel TFT is NOT SUPPORTED without USE_FAST_PINIO -#endif // end !USE_FAST_PINIO - } - return w; - } -} - -/*! - @brief Set the software (bitbang) SPI MOSI line HIGH. -*/ -inline void Adafruit_SPITFT_Renderer::SPI_MOSI_HIGH(void) { -#if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - #if defined(KINETISK) - *swspi.mosiPortSet = 1; - #else // !KINETISK - *swspi.mosiPortSet = swspi.mosiPinMask; - #endif - #else // !HAS_PORT_SET_CLR - *swspi.mosiPort |= swspi.mosiPinMaskSet; - #endif // end !HAS_PORT_SET_CLR -#else // !USE_FAST_PINIO - digitalWrite(swspi._mosi, HIGH); - #if defined(ESP32) - for(volatile uint8_t i=0; i<1; i++); - #endif // end ESP32 -#endif // end !USE_FAST_PINIO -} - -/*! - @brief Set the software (bitbang) SPI MOSI line LOW. -*/ -inline void Adafruit_SPITFT_Renderer::SPI_MOSI_LOW(void) { -#if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - #if defined(KINETISK) - *swspi.mosiPortClr = 1; - #else // !KINETISK - *swspi.mosiPortClr = swspi.mosiPinMask; - #endif - #else // !HAS_PORT_SET_CLR - *swspi.mosiPort &= swspi.mosiPinMaskClr; - #endif // end !HAS_PORT_SET_CLR -#else // !USE_FAST_PINIO - digitalWrite(swspi._mosi, LOW); - #if defined(ESP32) - for(volatile uint8_t i=0; i<1; i++); - #endif // end ESP32 -#endif // end !USE_FAST_PINIO -} - -/*! - @brief Set the software (bitbang) SPI SCK line HIGH. -*/ -inline void Adafruit_SPITFT_Renderer::SPI_SCK_HIGH(void) { -#if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - #if defined(KINETISK) - *swspi.sckPortSet = 1; - #else // !KINETISK - *swspi.sckPortSet = swspi.sckPinMask; - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x - for(volatile uint8_t i=0; i<1; i++); - #endif - #endif - #else // !HAS_PORT_SET_CLR - *swspi.sckPort |= swspi.sckPinMaskSet; - #endif // end !HAS_PORT_SET_CLR -#else // !USE_FAST_PINIO - digitalWrite(swspi._sck, HIGH); - #if defined(ESP32) - for(volatile uint8_t i=0; i<1; i++); - #endif // end ESP32 -#endif // end !USE_FAST_PINIO -} - -/*! - @brief Set the software (bitbang) SPI SCK line LOW. -*/ -inline void Adafruit_SPITFT_Renderer::SPI_SCK_LOW(void) { -#if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - #if defined(KINETISK) - *swspi.sckPortClr = 1; - #else // !KINETISK - *swspi.sckPortClr = swspi.sckPinMask; - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x - for(volatile uint8_t i=0; i<1; i++); - #endif - #endif - #else // !HAS_PORT_SET_CLR - *swspi.sckPort &= swspi.sckPinMaskClr; - #endif // end !HAS_PORT_SET_CLR -#else // !USE_FAST_PINIO - digitalWrite(swspi._sck, LOW); - #if defined(ESP32) - for(volatile uint8_t i=0; i<1; i++); - #endif // end ESP32 -#endif // end !USE_FAST_PINIO -} - -/*! - @brief Read the state of the software (bitbang) SPI MISO line. - @return true if HIGH, false if LOW. -*/ -inline bool Adafruit_SPITFT_Renderer::SPI_MISO_READ(void) { -#if defined(USE_FAST_PINIO) - #if defined(KINETISK) - return *swspi.misoPort; - #else // !KINETISK - return *swspi.misoPort & swspi.misoPinMask; - #endif // end !KINETISK -#else // !USE_FAST_PINIO - return digitalRead(swspi._miso); -#endif // end !USE_FAST_PINIO -} - -/*! - @brief Issue a single 16-bit value to the display. Chip-select, - transaction and data/command selection must have been - previously set -- this ONLY issues the word. Despite the name, - this function is used even if display connection is parallel; - name was maintaned for backward compatibility. Naming is also - not consistent with the 8-bit version, spiWrite(). Sorry about - that. Again, staying compatible with outside code. - @param w 16-bit value to write. -*/ -void Adafruit_SPITFT_Renderer::SPI_WRITE16(uint16_t w) { - if(connection == TFT_HARD_SPI) { -#if defined(__AVR__) - AVR_WRITESPI(w >> 8); - AVR_WRITESPI(w); -#elif defined(ESP8266) || defined(ESP32) - hwspi._spi->write16(w); -#else - hwspi._spi->transfer(w >> 8); - hwspi._spi->transfer(w); -#endif - } else if(connection == TFT_SOFT_SPI) { - for(uint8_t bit=0; bit<16; bit++) { - if(w & 0x8000) SPI_MOSI_HIGH(); - else SPI_MOSI_LOW(); - SPI_SCK_HIGH(); - SPI_SCK_LOW(); - w <<= 1; - } - } else { // TFT_PARALLEL -#if defined(__AVR__) - *tft8.writePort = w >> 8; - TFT_WR_STROBE(); - *tft8.writePort = w; -#elif defined(USE_FAST_PINIO) - if(!tft8.wide) { - *tft8.writePort = w >> 8; - TFT_WR_STROBE(); - *tft8.writePort = w; - } else { - *(volatile uint16_t *)tft8.writePort = w; - } -#endif - TFT_WR_STROBE(); - } -} - -/*! - @brief Issue a single 32-bit value to the display. Chip-select, - transaction and data/command selection must have been - previously set -- this ONLY issues the longword. Despite the - name, this function is used even if display connection is - parallel; name was maintaned for backward compatibility. Naming - is also not consistent with the 8-bit version, spiWrite(). - Sorry about that. Again, staying compatible with outside code. - @param l 32-bit value to write. -*/ -void Adafruit_SPITFT_Renderer::SPI_WRITE32(uint32_t l) { - if(connection == TFT_HARD_SPI) { -#if defined(__AVR__) - AVR_WRITESPI(l >> 24); - AVR_WRITESPI(l >> 16); - AVR_WRITESPI(l >> 8); - AVR_WRITESPI(l ); -#elif defined(ESP8266) || defined(ESP32) - hwspi._spi->write32(l); -#else - hwspi._spi->transfer(l >> 24); - hwspi._spi->transfer(l >> 16); - hwspi._spi->transfer(l >> 8); - hwspi._spi->transfer(l); -#endif - } else if(connection == TFT_SOFT_SPI) { - for(uint8_t bit=0; bit<32; bit++) { - if(l & 0x80000000) SPI_MOSI_HIGH(); - else SPI_MOSI_LOW(); - SPI_SCK_HIGH(); - SPI_SCK_LOW(); - l <<= 1; - } - } else { // TFT_PARALLEL -#if defined(__AVR__) - *tft8.writePort = l >> 24; - TFT_WR_STROBE(); - *tft8.writePort = l >> 16; - TFT_WR_STROBE(); - *tft8.writePort = l >> 8; - TFT_WR_STROBE(); - *tft8.writePort = l; -#elif defined(USE_FAST_PINIO) - if(!tft8.wide) { - *tft8.writePort = l >> 24; - TFT_WR_STROBE(); - *tft8.writePort = l >> 16; - TFT_WR_STROBE(); - *tft8.writePort = l >> 8; - TFT_WR_STROBE(); - *tft8.writePort = l; - } else { - *(volatile uint16_t *)tft8.writePort = l >> 16; - TFT_WR_STROBE(); - *(volatile uint16_t *)tft8.writePort = l; - } -#endif - TFT_WR_STROBE(); - } -} - -/*! - @brief Set the WR line LOW, then HIGH. Used for parallel-connected - interfaces when writing data. -*/ -inline void Adafruit_SPITFT_Renderer::TFT_WR_STROBE(void) { -#if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - #if defined(KINETISK) - *tft8.wrPortClr = 1; - *tft8.wrPortSet = 1; - #else // !KINETISK - *tft8.wrPortClr = tft8.wrPinMask; - *tft8.wrPortSet = tft8.wrPinMask; - #endif // end !KINETISK - #else // !HAS_PORT_SET_CLR - *tft8.wrPort &= tft8.wrPinMaskClr; - *tft8.wrPort |= tft8.wrPinMaskSet; - #endif // end !HAS_PORT_SET_CLR -#else // !USE_FAST_PINIO - digitalWrite(tft8._wr, LOW); - digitalWrite(tft8._wr, HIGH); -#endif // end !USE_FAST_PINIO -} - -/*! - @brief Set the RD line HIGH. Used for parallel-connected interfaces - when reading data. -*/ -inline void Adafruit_SPITFT_Renderer::TFT_RD_HIGH(void) { -#if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - *tft8.rdPortSet = tft8.rdPinMask; - #else // !HAS_PORT_SET_CLR - *tft8.rdPort |= tft8.rdPinMaskSet; - #endif // end !HAS_PORT_SET_CLR -#else // !USE_FAST_PINIO - digitalWrite(tft8._rd, HIGH); -#endif // end !USE_FAST_PINIO -} - -/*! - @brief Set the RD line LOW. Used for parallel-connected interfaces - when reading data. -*/ -inline void Adafruit_SPITFT_Renderer::TFT_RD_LOW(void) { -#if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - *tft8.rdPortClr = tft8.rdPinMask; - #else // !HAS_PORT_SET_CLR - *tft8.rdPort &= tft8.rdPinMaskClr; - #endif // end !HAS_PORT_SET_CLR -#else // !USE_FAST_PINIO - digitalWrite(tft8._rd, LOW); -#endif // end !USE_FAST_PINIO -} - -#endif // end __AVR_ATtiny85__ diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h deleted file mode 100644 index ce8f26d73..000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h +++ /dev/null @@ -1,525 +0,0 @@ -/* - * This class is basically the same as Adafruit_SPITFT. - * The only difference is: it extends Renderer which extends Adafruit_GFX. - * The original Adafruit_SPITFT class directly extends Adafruit_GFX. - */ -/*! - * @file Adafruit_SPITFT_Renderer.h - * - * Part of Adafruit's GFX graphics library. Originally this class was - * written to handle a range of color TFT displays connected via SPI, - * but over time this library and some display-specific subclasses have - * mutated to include some color OLEDs as well as parallel-interfaced - * displays. The name's been kept for the sake of older code. - * - * Adafruit invests time and resources providing this open source code, - * please support Adafruit and open-source hardware by purchasing - * products from Adafruit! - * - * Written by Limor "ladyada" Fried for Adafruit Industries, - * with contributions from the open source community. - * - * BSD license, all text here must be included in any redistribution. - */ - -#ifndef _ADAFRUIT_SPITFT_RENDERER_H_ -#define _ADAFRUIT_SPITFT_RENDERER_H_ - -#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all - -#include -#include "Adafruit_GFX.h" -#include "renderer.h" - -// HARDWARE CONFIG --------------------------------------------------------- - -#if defined(__AVR__) - typedef uint8_t ADAGFX_PORT_t; ///< PORT values are 8-bit - #define USE_FAST_PINIO ///< Use direct PORT register access -#elif defined(ARDUINO_STM32_FEATHER) // WICED - typedef class HardwareSPI SPIClass; ///< SPI is a bit odd on WICED - typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit -#elif defined(__arm__) - #if defined(ARDUINO_ARCH_SAMD) - // Adafruit M0, M4 - typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit - #define USE_FAST_PINIO ///< Use direct PORT register access - #define HAS_PORT_SET_CLR ///< PORTs have set & clear registers - #elif defined(CORE_TEENSY) - // PJRC Teensy 4.x - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x - typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit - // PJRC Teensy 3.x - #else - typedef uint8_t ADAGFX_PORT_t; ///< PORT values are 8-bit - #endif - #define USE_FAST_PINIO ///< Use direct PORT register access - #define HAS_PORT_SET_CLR ///< PORTs have set & clear registers - #else - // Arduino Due? - typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit - // USE_FAST_PINIO not available here (yet)...Due has a totally different - // GPIO register set and will require some changes elsewhere (e.g. in - // constructors especially). - #endif -#else // !ARM - // Probably ESP8266 or ESP32. USE_FAST_PINIO is not available here (yet) - // but don't worry about it too much...the digitalWrite() implementation - // on these platforms is reasonably efficient and already RAM-resident, - // only gotcha then is no parallel connection support for now. - typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit -#endif // end !ARM -typedef volatile ADAGFX_PORT_t* PORTreg_t; ///< PORT register type - -#if defined(__AVR__) - #define DEFAULT_SPI_FREQ 8000000L ///< Hardware SPI default speed -#else - #define DEFAULT_SPI_FREQ 16000000L ///< Hardware SPI default speed -#endif - -#if defined(ADAFRUIT_PYPORTAL) || defined(ADAFRUIT_PYBADGE_M4_EXPRESS) || defined(ADAFRUIT_PYGAMER_M4_EXPRESS) - #define USE_SPI_DMA ///< Auto DMA if using PyPortal -#else - //#define USE_SPI_DMA ///< If set, use DMA if available -#endif -// Another "oops" name -- this now also handles parallel DMA. -// If DMA is enabled, Arduino sketch MUST #include -// Estimated RAM usage: -// 4 bytes/pixel on display major axis + 8 bytes/pixel on minor axis, -// e.g. 320x240 pixels = 320 * 4 + 240 * 8 = 3,200 bytes. - -#if !defined(ARDUINO_ARCH_SAMD) - #undef USE_SPI_DMA ///< DMA currently for SAMD chips only -#endif - -#if defined(USE_SPI_DMA) - #pragma message ("GFX DMA IS ENABLED. HIGHLY EXPERIMENTAL.") - #include -#endif - -// This is kind of a kludge. Needed a way to disambiguate the software SPI -// and parallel constructors via their argument lists. Originally tried a -// bool as the first argument to the parallel constructor (specifying 8-bit -// vs 16-bit interface) but the compiler regards this as equivalent to an -// integer and thus still ambiguous. SO...the parallel constructor requires -// an enumerated type as the first argument: tft8 (for 8-bit parallel) or -// tft16 (for 16-bit)...even though 16-bit isn't fully implemented or tested -// and might never be, still needed that disambiguation from soft SPI. -enum tftBusWidth_Renderer { tft8bitbus_Renderer, tft16bitbus_Renderer }; ///< For first arg to parallel constructor - -// CLASS DEFINITION -------------------------------------------------------- - -/*! - @brief Adafruit_SPITFT is an intermediary class between Adafruit_GFX - and various hardware-specific subclasses for different displays. - It handles certain operations that are common to a range of - displays (address window, area fills, etc.). Originally these were - all color TFT displays interfaced via SPI, but it's since expanded - to include color OLEDs and parallel-interfaced TFTs. THE NAME HAS - BEEN KEPT TO AVOID BREAKING A LOT OF SUBCLASSES AND EXAMPLE CODE. - Many of the class member functions similarly live on with names - that don't necessarily accurately describe what they're doing, - again to avoid breaking a lot of other code. If in doubt, read - the comments. -*/ -class Adafruit_SPITFT_Renderer : public Renderer { - - public: - - // CONSTRUCTORS -------------------------------------------------------- - - // Software SPI constructor: expects width & height (at default rotation - // setting 0), 4 signal pins (cs, dc, mosi, sclk), 2 optional pins - // (reset, miso). cs argument is required but can be -1 if unused -- - // rather than moving it to the optional arguments, it was done this way - // to avoid breaking existing code (-1 option was a later addition). - Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, - int8_t cs, int8_t dc, int8_t mosi, int8_t sck, - int8_t rst = -1, int8_t miso = -1); - - // Hardware SPI constructor using the default SPI port: expects width & - // height (at default rotation setting 0), 2 signal pins (cs, dc), - // optional reset pin. cs is required but can be -1 if unused -- rather - // than moving it to the optional arguments, it was done this way to - // avoid breaking existing code (-1 option was a later addition). - Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, - int8_t cs, int8_t dc, int8_t rst = -1); - -#if !defined(ESP8266) // See notes in .cpp - // Hardware SPI constructor using an arbitrary SPI peripheral: expects - // width & height (rotation 0), SPIClass pointer, 2 signal pins (cs, dc) - // and optional reset pin. cs is required but can be -1 if unused. - Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, SPIClass *spiClass, - int8_t cs, int8_t dc, int8_t rst = -1); -#endif // end !ESP8266 - - // Parallel constructor: expects width & height (rotation 0), flag - // indicating whether 16-bit (true) or 8-bit (false) interface, 3 signal - // pins (d0, wr, dc), 3 optional pins (cs, rst, rd). 16-bit parallel - // isn't even fully implemented but the 'wide' flag was added as a - // required argument to avoid ambiguity with other constructors. - Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, tftBusWidth_Renderer busWidth, - int8_t d0, int8_t wr, int8_t dc, - int8_t cs = -1, int8_t rst = -1, int8_t rd = -1); - - // CLASS MEMBER FUNCTIONS ---------------------------------------------- - - // These first two functions MUST be declared by subclasses: - - /*! - @brief Display-specific initialization function. - @param freq SPI frequency, in hz (or 0 for default or unused). - */ - virtual void begin(uint32_t freq) = 0; - - /*! - @brief Set up the specific display hardware's "address window" - for subsequent pixel-pushing operations. - @param x Leftmost pixel of area to be drawn (MUST be within - display bounds at current rotation setting). - @param y Topmost pixel of area to be drawn (MUST be within - display bounds at current rotation setting). - @param w Width of area to be drawn, in pixels (MUST be >0 and, - added to x, within display bounds at current rotation). - @param h Height of area to be drawn, in pixels (MUST be >0 and, - added to x, within display bounds at current rotation). - */ - virtual void setAddrWindow( - uint16_t x, uint16_t y, uint16_t w, uint16_t h) = 0; - - // Remaining functions do not need to be declared in subclasses - // unless they wish to provide hardware-specific optimizations. - // Brief comments here...documented more thoroughly in .cpp file. - - // Subclass' begin() function invokes this to initialize hardware. - // freq=0 to use default SPI speed. spiMode must be one of the SPI_MODEn - // values defined in SPI.h, which are NOT the same as 0 for SPI_MODE0, - // 1 for SPI_MODE1, etc...use ONLY the SPI_MODEn defines! Only! - // Name is outdated (interface may be parallel) but for compatibility: - void initSPI(uint32_t freq = 0, uint8_t spiMode = SPI_MODE0); - // Chip select and/or hardware SPI transaction start as needed: - void startWrite(void); - // Chip deselect and/or hardware SPI transaction end as needed: - void endWrite(void); - void sendCommand(uint8_t commandByte, uint8_t *dataBytes = NULL, uint8_t numDataBytes = 0); - void sendCommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes); - uint8_t readcommand8(uint8_t commandByte, uint8_t index = 0); - - // These functions require a chip-select and/or SPI transaction - // around them. Higher-level graphics primitives might start a - // single transaction and then make multiple calls to these functions - // (e.g. circle or text rendering might make repeated lines or rects) - // before ending the transaction. It's more efficient than starting a - // transaction every time. - void writePixel(int16_t x, int16_t y, uint16_t color); - void writePixels(uint16_t *colors, uint32_t len, - bool block=true, bool bigEndian=false); - void writeColor(uint16_t color, uint32_t len); - void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color); - void writeFastHLine(int16_t x, int16_t y, int16_t w, - uint16_t color); - void writeFastVLine(int16_t x, int16_t y, int16_t h, - uint16_t color); - // This is a new function, similar to writeFillRect() except that - // all arguments MUST be onscreen, sorted and clipped. If higher-level - // primitives can handle their own sorting/clipping, it avoids repeating - // such operations in the low-level code, making it potentially faster. - // CALLING THIS WITH UNCLIPPED OR NEGATIVE VALUES COULD BE DISASTROUS. - inline void writeFillRectPreclipped(int16_t x, int16_t y, - int16_t w, int16_t h, uint16_t color); - // Another new function, companion to the new non-blocking - // writePixels() variant. - void dmaWait(void); - - - // These functions are similar to the 'write' functions above, but with - // a chip-select and/or SPI transaction built-in. They're typically used - // solo -- that is, as graphics primitives in themselves, not invoked by - // higher-level primitives (which should use the functions above). - void drawPixel(int16_t x, int16_t y, uint16_t color); - void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color); - void drawFastHLine(int16_t x, int16_t y, int16_t w, - uint16_t color); - void drawFastVLine(int16_t x, int16_t y, int16_t h, - uint16_t color); - // A single-pixel push encapsulated in a transaction. I don't think - // this is used anymore (BMP demos might've used it?) but is provided - // for backward compatibility, consider it deprecated: - void pushColor(uint16_t color); - - using Adafruit_GFX::drawRGBBitmap; // Check base class first - void drawRGBBitmap(int16_t x, int16_t y, - uint16_t *pcolors, int16_t w, int16_t h); - - void invertDisplay(bool i); - uint16_t color565(uint8_t r, uint8_t g, uint8_t b); - - // Despite parallel additions, function names kept for compatibility: - void spiWrite(uint8_t b); // Write single byte as DATA - void writeCommand(uint8_t cmd); // Write single byte as COMMAND - uint8_t spiRead(void); // Read single byte of data - - // Most of these low-level functions were formerly macros in - // Adafruit_SPITFT_Macros.h. Some have been made into inline functions - // to avoid macro mishaps. Despite the addition of code for a parallel - // display interface, the names have been kept for backward - // compatibility (some subclasses may be invoking these): - void SPI_WRITE16(uint16_t w); // Not inline - void SPI_WRITE32(uint32_t l); // Not inline - // Old code had both a spiWrite16() function and SPI_WRITE16 macro - // in addition to the SPI_WRITE32 macro. The latter two have been - // made into functions here, and spiWrite16() removed (use SPI_WRITE16() - // instead). It looks like most subclasses had gotten comfortable with - // SPI_WRITE16 and SPI_WRITE32 anyway so those names were kept rather - // than the less-obnoxious camelcase variants, oh well. - - // Placing these functions entirely in the class definition inlines - // them implicitly them while allowing their use in other code: - - /*! - @brief Set the chip-select line HIGH. Does NOT check whether CS pin - is set (>=0), that should be handled in calling function. - Despite function name, this is used even if the display - connection is parallel. - */ - void SPI_CS_HIGH(void) { - #if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - #if defined(KINETISK) - *csPortSet = 1; - #else // !KINETISK - *csPortSet = csPinMask; - #endif // end !KINETISK - #else // !HAS_PORT_SET_CLR - *csPort |= csPinMaskSet; - #endif // end !HAS_PORT_SET_CLR - #else // !USE_FAST_PINIO - digitalWrite(_cs, HIGH); - #endif // end !USE_FAST_PINIO - } - - /*! - @brief Set the chip-select line LOW. Does NOT check whether CS pin - is set (>=0), that should be handled in calling function. - Despite function name, this is used even if the display - connection is parallel. - */ - void SPI_CS_LOW(void) { - #if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - #if defined(KINETISK) - *csPortClr = 1; - #else // !KINETISK - *csPortClr = csPinMask; - #endif // end !KINETISK - #else // !HAS_PORT_SET_CLR - *csPort &= csPinMaskClr; - #endif // end !HAS_PORT_SET_CLR - #else // !USE_FAST_PINIO - digitalWrite(_cs, LOW); - #endif // end !USE_FAST_PINIO - } - - /*! - @brief Set the data/command line HIGH (data mode). - */ - void SPI_DC_HIGH(void) { - #if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - #if defined(KINETISK) - *dcPortSet = 1; - #else // !KINETISK - *dcPortSet = dcPinMask; - #endif // end !KINETISK - #else // !HAS_PORT_SET_CLR - *dcPort |= dcPinMaskSet; - #endif // end !HAS_PORT_SET_CLR - #else // !USE_FAST_PINIO - digitalWrite(_dc, HIGH); - #endif // end !USE_FAST_PINIO - } - - /*! - @brief Set the data/command line LOW (command mode). - */ - void SPI_DC_LOW(void) { - #if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - #if defined(KINETISK) - *dcPortClr = 1; - #else // !KINETISK - *dcPortClr = dcPinMask; - #endif // end !KINETISK - #else // !HAS_PORT_SET_CLR - *dcPort &= dcPinMaskClr; - #endif // end !HAS_PORT_SET_CLR - #else // !USE_FAST_PINIO - digitalWrite(_dc, LOW); - #endif // end !USE_FAST_PINIO - } - - protected: - - // A few more low-level member functions -- some may have previously - // been macros. Shouldn't have a need to access these externally, so - // they've been moved to the protected section. Additionally, they're - // declared inline here and the code is in the .cpp file, since outside - // code doesn't need to see these. - inline void SPI_MOSI_HIGH(void); - inline void SPI_MOSI_LOW(void); - inline void SPI_SCK_HIGH(void); - inline void SPI_SCK_LOW(void); - inline bool SPI_MISO_READ(void); - inline void SPI_BEGIN_TRANSACTION(void); - inline void SPI_END_TRANSACTION(void); - inline void TFT_WR_STROBE(void); // Parallel interface write strobe - inline void TFT_RD_HIGH(void); // Parallel interface read high - inline void TFT_RD_LOW(void); // Parallel interface read low - - // CLASS INSTANCE VARIABLES -------------------------------------------- - - // Here be dragons! There's a big union of three structures here -- - // one each for hardware SPI, software (bitbang) SPI, and parallel - // interfaces. This is to save some memory, since a display's connection - // will be only one of these. The order of some things is a little weird - // in an attempt to get values to align and pack better in RAM. - -#if defined(USE_FAST_PINIO) -#if defined(HAS_PORT_SET_CLR) - PORTreg_t csPortSet; ///< PORT register for chip select SET - PORTreg_t csPortClr; ///< PORT register for chip select CLEAR - PORTreg_t dcPortSet; ///< PORT register for data/command SET - PORTreg_t dcPortClr; ///< PORT register for data/command CLEAR -#else // !HAS_PORT_SET_CLR - PORTreg_t csPort; ///< PORT register for chip select - PORTreg_t dcPort; ///< PORT register for data/command -#endif // end HAS_PORT_SET_CLR -#endif // end USE_FAST_PINIO -#if defined(__cplusplus) && (__cplusplus >= 201100) - union { -#endif - struct { // Values specific to HARDWARE SPI: - SPIClass *_spi; ///< SPI class pointer -#if defined(SPI_HAS_TRANSACTION) - SPISettings settings; ///< SPI transaction settings -#else - uint32_t _freq; ///< SPI bitrate (if no SPI transactions) -#endif - uint32_t _mode; ///< SPI data mode (transactions or no) - } hwspi; ///< Hardware SPI values - struct { // Values specific to SOFTWARE SPI: -#if defined(USE_FAST_PINIO) - PORTreg_t misoPort; ///< PORT (PIN) register for MISO -#if defined(HAS_PORT_SET_CLR) - PORTreg_t mosiPortSet; ///< PORT register for MOSI SET - PORTreg_t mosiPortClr; ///< PORT register for MOSI CLEAR - PORTreg_t sckPortSet; ///< PORT register for SCK SET - PORTreg_t sckPortClr; ///< PORT register for SCK CLEAR - #if !defined(KINETISK) - ADAGFX_PORT_t mosiPinMask; ///< Bitmask for MOSI - ADAGFX_PORT_t sckPinMask; ///< Bitmask for SCK - #endif // end !KINETISK -#else // !HAS_PORT_SET_CLR - PORTreg_t mosiPort; ///< PORT register for MOSI - PORTreg_t sckPort; ///< PORT register for SCK - ADAGFX_PORT_t mosiPinMaskSet; ///< Bitmask for MOSI SET (OR) - ADAGFX_PORT_t mosiPinMaskClr; ///< Bitmask for MOSI CLEAR (AND) - ADAGFX_PORT_t sckPinMaskSet; ///< Bitmask for SCK SET (OR bitmask) - ADAGFX_PORT_t sckPinMaskClr; ///< Bitmask for SCK CLEAR (AND) -#endif // end HAS_PORT_SET_CLR - #if !defined(KINETISK) - ADAGFX_PORT_t misoPinMask; ///< Bitmask for MISO - #endif // end !KINETISK -#endif // end USE_FAST_PINIO - int8_t _mosi; ///< MOSI pin # - int8_t _miso; ///< MISO pin # - int8_t _sck; ///< SCK pin # - } swspi; ///< Software SPI values - struct { // Values specific to 8-bit parallel: -#if defined(USE_FAST_PINIO) - - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x - volatile uint32_t *writePort; ///< PORT register for DATA WRITE - volatile uint32_t *readPort; ///< PORT (PIN) register for DATA READ - #else - volatile uint8_t *writePort; ///< PORT register for DATA WRITE - volatile uint8_t *readPort; ///< PORT (PIN) register for DATA READ - #endif -#if defined(HAS_PORT_SET_CLR) - // Port direction register pointers are always 8-bit regardless of - // PORTreg_t -- even if 32-bit port, we modify a byte-aligned 8 bits. - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x - volatile uint32_t *dirSet; ///< PORT byte data direction SET - volatile uint32_t *dirClr; ///< PORT byte data direction CLEAR - #else - volatile uint8_t *dirSet; ///< PORT byte data direction SET - volatile uint8_t *dirClr; ///< PORT byte data direction CLEAR - #endif - PORTreg_t wrPortSet; ///< PORT register for write strobe SET - PORTreg_t wrPortClr; ///< PORT register for write strobe CLEAR - PORTreg_t rdPortSet; ///< PORT register for read strobe SET - PORTreg_t rdPortClr; ///< PORT register for read strobe CLEAR - #if !defined(KINETISK) - ADAGFX_PORT_t wrPinMask; ///< Bitmask for write strobe - #endif // end !KINETISK - ADAGFX_PORT_t rdPinMask; ///< Bitmask for read strobe -#else // !HAS_PORT_SET_CLR - // Port direction register pointer is always 8-bit regardless of - // PORTreg_t -- even if 32-bit port, we modify a byte-aligned 8 bits. - volatile uint8_t *portDir; ///< PORT direction register - PORTreg_t wrPort; ///< PORT register for write strobe - PORTreg_t rdPort; ///< PORT register for read strobe - ADAGFX_PORT_t wrPinMaskSet; ///< Bitmask for write strobe SET (OR) - ADAGFX_PORT_t wrPinMaskClr; ///< Bitmask for write strobe CLEAR (AND) - ADAGFX_PORT_t rdPinMaskSet; ///< Bitmask for read strobe SET (OR) - ADAGFX_PORT_t rdPinMaskClr; ///< Bitmask for read strobe CLEAR (AND) -#endif // end HAS_PORT_SET_CLR -#endif // end USE_FAST_PINIO - int8_t _d0; ///< Data pin 0 # - int8_t _wr; ///< Write strobe pin # - int8_t _rd; ///< Read strobe pin # (or -1) - bool wide = 0; ///< If true, is 16-bit interface - } tft8; ///< Parallel interface settings -#if defined(__cplusplus) && (__cplusplus >= 201100) - }; ///< Only one interface is active -#endif -#if defined(USE_SPI_DMA) // Used by hardware SPI and tft8 - Adafruit_ZeroDMA dma; ///< DMA instance - DmacDescriptor *dptr = NULL; ///< 1st descriptor - DmacDescriptor *descriptor = NULL; ///< Allocated descriptor list - uint16_t *pixelBuf[2]; ///< Working buffers - uint16_t maxFillLen; ///< Max pixels per DMA xfer - uint16_t lastFillColor = 0; ///< Last color used w/fill - uint32_t lastFillLen = 0; ///< # of pixels w/last fill - uint8_t onePixelBuf; ///< For hi==lo fill -#endif -#if defined(USE_FAST_PINIO) -#if defined(HAS_PORT_SET_CLR) - #if !defined(KINETISK) - ADAGFX_PORT_t csPinMask; ///< Bitmask for chip select - ADAGFX_PORT_t dcPinMask; ///< Bitmask for data/command - #endif // end !KINETISK -#else // !HAS_PORT_SET_CLR - ADAGFX_PORT_t csPinMaskSet; ///< Bitmask for chip select SET (OR) - ADAGFX_PORT_t csPinMaskClr; ///< Bitmask for chip select CLEAR (AND) - ADAGFX_PORT_t dcPinMaskSet; ///< Bitmask for data/command SET (OR) - ADAGFX_PORT_t dcPinMaskClr; ///< Bitmask for data/command CLEAR (AND) -#endif // end HAS_PORT_SET_CLR -#endif // end USE_FAST_PINIO - uint8_t connection; ///< TFT_HARD_SPI, TFT_SOFT_SPI, etc. - int8_t _rst; ///< Reset pin # (or -1) - int8_t _cs; ///< Chip select pin # (or -1) - int8_t _dc; ///< Data/command pin # - - int16_t _xstart = 0; ///< Internal framebuffer X offset - int16_t _ystart = 0; ///< Internal framebuffer Y offset - uint8_t invertOnCommand = 0; ///< Command to enable invert mode - uint8_t invertOffCommand = 0; ///< Command to disable invert mode - - uint32_t _freq = 0; ///< Dummy var to keep subclasses happy -}; - -#endif // end __AVR_ATtiny85__ -#endif // end _ADAFRUIT_SPITFT_H_ diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp deleted file mode 100644 index 799d87a79..000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/*! - * @file Adafruit_SSD1331.cpp - * - * @mainpage Adafruit SSD1331 Arduino Library - * - * @section intro_sec Introduction - * - * This is a library for the 0.96" 16-bit Color OLED with SSD1331 driver chip - * - * Pick one up today in the adafruit shop! - * ------> http://www.adafruit.com/products/684 - * - * These displays use SPI to communicate, 4 or 5 pins are required to - * interface - * Adafruit invests time and resources providing this open source code, - * please support Adafruit and open-source hardware by purchasing - * products from Adafruit! - * - * @section author Author - * - * Written by Limor Fried/Ladyada for Adafruit Industries. - * - * @section license License - * - * BSD license, all text above must be included in any redistribution - */ - -#include "Adafruit_SSD1331.h" -#include "pins_arduino.h" -#include "wiring_private.h" - -/***********************************/ - -/*! - @brief SPI displays set an address window rectangle for blitting pixels - @param x Top left corner x coordinate - @param y Top left corner x coordinate - @param w Width of window - @param h Height of window -*/ -void Adafruit_SSD1331::setAddrWindow(uint16_t x, uint16_t y, uint16_t w, - uint16_t h) { - - uint8_t x1 = x; - uint8_t y1 = y; - if (x1 > 95) - x1 = 95; - if (y1 > 63) - y1 = 63; - - uint8_t x2 = (x + w - 1); - uint8_t y2 = (y + h - 1); - if (x2 > 95) - x2 = 95; - if (y2 > 63) - y2 = 63; - - if (x1 > x2) { - uint8_t t = x2; - x2 = x1; - x1 = t; - } - if (y1 > y2) { - uint8_t t = y2; - y2 = y1; - y1 = t; - } - - sendCommand(0x15); // Column addr set - sendCommand(x1); - sendCommand(x2); - - sendCommand(0x75); // Column addr set - sendCommand(y1); - sendCommand(y2); - - startWrite(); -} - -/**************************************************************************/ -/*! - @brief Initialize SSD1331 chip - Connects to the SSD1331 over SPI and sends initialization procedure commands - @param freq Desired SPI clock frequency -*/ -/**************************************************************************/ -void Adafruit_SSD1331::begin(uint32_t freq) { - initSPI(freq); - - // Initialization Sequence - sendCommand(SSD1331_CMD_DISPLAYOFF); // 0xAE - sendCommand(SSD1331_CMD_SETREMAP); // 0xA0 -#if defined SSD1331_COLORORDER_RGB - sendCommand(0x72); // RGB Color -#else - sendCommand(0x76); // BGR Color -#endif - sendCommand(SSD1331_CMD_STARTLINE); // 0xA1 - sendCommand(0x0); - sendCommand(SSD1331_CMD_DISPLAYOFFSET); // 0xA2 - sendCommand(0x0); - sendCommand(SSD1331_CMD_NORMALDISPLAY); // 0xA4 - sendCommand(SSD1331_CMD_SETMULTIPLEX); // 0xA8 - sendCommand(0x3F); // 0x3F 1/64 duty - sendCommand(SSD1331_CMD_SETMASTER); // 0xAD - sendCommand(0x8E); - sendCommand(SSD1331_CMD_POWERMODE); // 0xB0 - sendCommand(0x0B); - sendCommand(SSD1331_CMD_PRECHARGE); // 0xB1 - sendCommand(0x31); - sendCommand(SSD1331_CMD_CLOCKDIV); // 0xB3 - sendCommand(0xF0); // 7:4 = Oscillator Frequency, 3:0 = CLK Div Ratio - // (A[3:0]+1 = 1..16) - sendCommand(SSD1331_CMD_PRECHARGEA); // 0x8A - sendCommand(0x64); - sendCommand(SSD1331_CMD_PRECHARGEB); // 0x8B - sendCommand(0x78); - sendCommand(SSD1331_CMD_PRECHARGEC); // 0x8C - sendCommand(0x64); - sendCommand(SSD1331_CMD_PRECHARGELEVEL); // 0xBB - sendCommand(0x3A); - sendCommand(SSD1331_CMD_VCOMH); // 0xBE - sendCommand(0x3E); - sendCommand(SSD1331_CMD_MASTERCURRENT); // 0x87 - sendCommand(0x06); - sendCommand(SSD1331_CMD_CONTRASTA); // 0x81 - sendCommand(0x91); - sendCommand(SSD1331_CMD_CONTRASTB); // 0x82 - sendCommand(0x50); - sendCommand(SSD1331_CMD_CONTRASTC); // 0x83 - sendCommand(0x7D); - sendCommand(SSD1331_CMD_DISPLAYON); //--turn on oled panel - _width = TFTWIDTH; - _height = TFTHEIGHT; -} - -/**************************************************************************/ -/*! - @brief Instantiate Adafruit SSD1331 driver with software SPI - @param cs Chip select pin # - @param dc Data/Command pin # - @param mosi SPI MOSI pin # - @param sclk SPI Clock pin # - @param rst Reset pin # (optional, pass -1 if unused) -*/ -/**************************************************************************/ -Adafruit_SSD1331::Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t mosi, - int8_t sclk, int8_t rst) - : Adafruit_SPITFT_Renderer(TFTWIDTH, TFTHEIGHT, cs, dc, mosi, sclk, rst, -1) {} - -/**************************************************************************/ -/*! - @brief Instantiate Adafruit SSD1331 driver with hardware SPI - @param cs Chip select pin # - @param dc Data/Command pin # - @param rst Reset pin # (optional, pass -1 if unused) -*/ -/**************************************************************************/ -Adafruit_SSD1331::Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t rst) - : Adafruit_SPITFT_Renderer(TFTWIDTH, TFTHEIGHT, cs, dc, rst) {} - -/**************************************************************************/ -/*! - @brief Instantiate Adafruit SSD1331 driver with hardware SPI - @param spi Pointer to an existing SPIClass instance (e.g. &SPI, the - microcontroller's primary SPI bus). - @param cs Chip select pin # - @param dc Data/Command pin # - @param rst Reset pin # (optional, pass -1 if unused) -*/ -/**************************************************************************/ -Adafruit_SSD1331::Adafruit_SSD1331(SPIClass *spi, int8_t cs, int8_t dc, - int8_t rst) - : -#if defined(ESP8266) - Adafruit_SPITFT_Renderer(TFTWIDTH, TFTWIDTH, cs, dc, rst) { -#else - Adafruit_SPITFT_Renderer(TFTWIDTH, TFTWIDTH, spi, cs, dc, rst) { -#endif -} - -/**************************************************************************/ -/*! - @brief Change whether display is on or off - @param enable True if you want the display ON, false OFF -*/ -/**************************************************************************/ -void Adafruit_SSD1331::enableDisplay(boolean enable) { - sendCommand(enable ? SSD1331_CMD_DISPLAYON : SSD1331_CMD_DISPLAYOFF); -} diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h deleted file mode 100644 index e427615c3..000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h +++ /dev/null @@ -1,76 +0,0 @@ -/*! - * @file Adafruit_SSD1331.h - */ - -#include "Arduino.h" -#include -// Tasmota change: use custom version of Adafruit_SPITFT which extends Renderer instead of Adafruit_GFX -#include -#include -#include - -/*! - * @brief Select one of these defines to set the pixel color order - */ -#define SSD1331_COLORORDER_RGB -// #define SSD1331_COLORORDER_BGR - -#if defined SSD1331_COLORORDER_RGB && defined SSD1331_COLORORDER_BGR -#error "RGB and BGR can not both be defined for SSD1331_COLORODER." -#endif - -// Timing Delays -#define SSD1331_DELAYS_HWFILL (3) //!< Fill delay -#define SSD1331_DELAYS_HWLINE (1) //!< Line delay - -// SSD1331 Commands -#define SSD1331_CMD_DRAWLINE 0x21 //!< Draw line -#define SSD1331_CMD_DRAWRECT 0x22 //!< Draw rectangle -#define SSD1331_CMD_FILL 0x26 //!< Fill enable/disable -#define SSD1331_CMD_SETCOLUMN 0x15 //!< Set column address -#define SSD1331_CMD_SETROW 0x75 //!< Set row adress -#define SSD1331_CMD_CONTRASTA 0x81 //!< Set contrast for color A -#define SSD1331_CMD_CONTRASTB 0x82 //!< Set contrast for color B -#define SSD1331_CMD_CONTRASTC 0x83 //!< Set contrast for color C -#define SSD1331_CMD_MASTERCURRENT 0x87 //!< Master current control -#define SSD1331_CMD_SETREMAP 0xA0 //!< Set re-map & data format -#define SSD1331_CMD_STARTLINE 0xA1 //!< Set display start line -#define SSD1331_CMD_DISPLAYOFFSET 0xA2 //!< Set display offset -#define SSD1331_CMD_NORMALDISPLAY 0xA4 //!< Set display to normal mode -#define SSD1331_CMD_DISPLAYALLON 0xA5 //!< Set entire display ON -#define SSD1331_CMD_DISPLAYALLOFF 0xA6 //!< Set entire display OFF -#define SSD1331_CMD_INVERTDISPLAY 0xA7 //!< Invert display -#define SSD1331_CMD_SETMULTIPLEX 0xA8 //!< Set multiplex ratio -#define SSD1331_CMD_SETMASTER 0xAD //!< Set master configuration -#define SSD1331_CMD_DISPLAYOFF 0xAE //!< Display OFF (sleep mode) -#define SSD1331_CMD_DISPLAYON 0xAF //!< Normal Brightness Display ON -#define SSD1331_CMD_POWERMODE 0xB0 //!< Power save mode -#define SSD1331_CMD_PRECHARGE 0xB1 //!< Phase 1 and 2 period adjustment -#define SSD1331_CMD_CLOCKDIV \ - 0xB3 //!< Set display clock divide ratio/oscillator frequency -#define SSD1331_CMD_PRECHARGEA 0x8A //!< Set second pre-charge speed for color A -#define SSD1331_CMD_PRECHARGEB 0x8B //!< Set second pre-charge speed for color B -#define SSD1331_CMD_PRECHARGEC 0x8C //!< Set second pre-charge speed for color C -#define SSD1331_CMD_PRECHARGELEVEL 0xBB //!< Set pre-charge voltage -#define SSD1331_CMD_VCOMH 0xBE //!< Set Vcomh voltge - -/// Class to manage hardware interface with SSD1331 chipset -class Adafruit_SSD1331 : public Adafruit_SPITFT_Renderer { -public: - Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t mosi, int8_t sclk, int8_t rst); - Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t rst); - // 3-4 args using hardware SPI (must specify peripheral) (reset optional) - Adafruit_SSD1331(SPIClass *spi, int8_t cs, int8_t dc, int8_t rst = -1); - - // commands - void begin(uint32_t begin = 8000000); - - void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h); - - void enableDisplay(boolean enable); - - static const int16_t TFTWIDTH = 96; ///< The width of the display - static const int16_t TFTHEIGHT = 64; ///< The height of the display - -private: -}; diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/README.md b/lib/lib_display/Adafruit_SSD1331-1.2.0/README.md deleted file mode 100644 index 24c404c59..000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Adafruit SSD1331 Arduino Library [![Build Status](https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino/html/index.html) -This is a library for the 0.96" 16-bit Color OLED with SSD1331 driver chip - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/products/684 - -These displays use SPI to communicate, 4 or 5 pins are required to -interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above must be included in any redistribution - -To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_SSD1131. Check that the Adafruit_SSD1331 folder contains Adafruit_SSD1331.cpp and Adafruit_SSD1331.h - -Place the Adafruit_SSD1331 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. - -You will also have to download the Adafruit GFX Graphics core which does all the circles, text, rectangles, etc. You can get it from -https://github.com/adafruit/Adafruit-GFX-Library -and download/install that library as well diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/library.properties b/lib/lib_display/Adafruit_SSD1331-1.2.0/library.properties deleted file mode 100644 index 931f1aa38..000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/library.properties +++ /dev/null @@ -1,10 +0,0 @@ -name=Adafruit SSD1331 OLED Driver Library for Arduino -version=1.2.0 -author=Adafruit -maintainer=Adafruit -sentence=For 0.96" OLEDs in the Adafruit shop -paragraph=For 0.96" OLEDs in the Adafruit shop -category=Display -url=https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino -architectures=* -depends=Adafruit GFX Library diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/license.txt b/lib/lib_display/Adafruit_SSD1331-1.2.0/license.txt deleted file mode 100644 index f6a0f22b8..000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/license.txt +++ /dev/null @@ -1,26 +0,0 @@ -Software License Agreement (BSD License) - -Copyright (c) 2012, Adafruit Industries -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holders nor the -names of its contributors may be used to endorse or promote products -derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/README.md b/lib/lib_display/Adafruit_SSD1351-gemu-1.0/README.md deleted file mode 100644 index 6414419d0..000000000 --- a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/README.md +++ /dev/null @@ -1,2 +0,0 @@ -### SSD3115 Arduino Library -This library is for support for the 128x128 oled controller over 3 wire SPI. It is based heavily on the [Adafruit_SSD1351](https://github.com/adafruit/Adafruit-SSD1351-library) library and is designed to work with the [Adafruit_GFX library](https://github.com/adafruit/Adafruit-GFX-Library). diff --git a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/SSD1351.cpp b/lib/lib_display/Adafruit_SSD1351-gemu-1.0/SSD1351.cpp deleted file mode 100644 index 274b030b2..000000000 --- a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/SSD1351.cpp +++ /dev/null @@ -1,588 +0,0 @@ -/*************************************************** - This is our library for the Adafruit SSD1351 Breakout and Shield - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ -#include -#include "SSD1351.h" -#include -#include - - -const uint16_t ssd1351_colors[]={SSD1351_BLACK,SSD1351_WHITE,SSD1351_RED,SSD1351_GREEN,SSD1351_BLUE,SSD1351_CYAN,SSD1351_MAGENTA,\ - SSD1351_YELLOW,SSD1351_NAVY,SSD1351_DARKGREEN,SSD1351_DARKCYAN,SSD1351_MAROON,SSD1351_PURPLE,SSD1351_OLIVE,\ -SSD1351_LIGHTGREY,SSD1351_DARKGREY,SSD1351_ORANGE,SSD1351_GREENYELLOW,SSD1351_PINK}; - -// Constructor when using software SPI. All output pins are configurable. -SSD1351::SSD1351(int8_t cs,int8_t mosi,int8_t sclk, int8_t dc) : Renderer(SSD1351_WIDTH, SSD1351_HEIGHT) { - _cs = cs; - _mosi = mosi; - _sclk = sclk; - _hwspi = 0; - _dc = dc; -} - -#ifndef ESP32 - -#include "spi_register.h" - -/* CPU Clock = 80 Mhz -max clock of display is 4.545 Mhz (220ns sclk cycle) -so cpu/18 => 4.44 Mhz should be ok -HSPI CLK 5 GPIO14 -HSPI /CS 8 GPIO15 -HSPI MOSI 7 GPIO13 -*/ - -uint8_t ssd131_start; - -uint32_t ssd1351_clock; -uint32_t ssd1351_usr; -uint32_t ssd1351_usr1; -uint32_t ssd1351_usr2; -uint32_t ssd1351_spi1c; -uint32_t ssd1351_spi1p; -//uint32_t ssd1351_gpmux; -uint32_t ssd1351_mtdo; - - -uint32_t ssd1351_clock_prev; -uint32_t ssd1351_usr_prev; -uint32_t ssd1351_usr1_prev; -uint32_t ssd1351_usr2_prev; -uint32_t ssd1351_spi1c_prev; -uint32_t ssd1351_spi1p_prev; -//uint32_t ssd1351_gpmux_prev; -uint32_t ssd1351_mtdo_prev; - -// code from espressif SDK -/****************************************************************************** - * FunctionName : spi_lcd_mode_init - * Description : SPI master initial function for driving LCD 3 wire spi -*******************************************************************************/ -void SSD1351::spi_lcd_mode_init(void) { - uint32 regvalue; - - if (_dc >= 0) { - spis = SPISettings(40000000, MSBFIRST, SPI_MODE0); - } else { - ssd1351_clock_prev=SPI1CLK; - ssd1351_usr_prev=SPI1U; - ssd1351_usr1_prev=SPI1U1; - ssd1351_usr2_prev=SPI1U2; - ssd1351_spi1c_prev=SPI1C; - ssd1351_spi1p_prev=SPI1P; - //ssd1351_gpmux_prev=GPMUX; - ssd1351_mtdo_prev=READ_PERI_REG(PERIPHS_IO_MUX_MTDO_U); - - SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE; - SPI1U1=0; - SPI1C = 0; - - //bit9 of PERIPHS_IO_MUX should be cleared when HSPI clock doesn't equal CPU clock - //bit8 of PERIPHS_IO_MUX should be cleared when SPI clock doesn't equal CPU clock - - WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9 - //PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure miso to spi mode - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure mosi to spi mode - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure sclk to spi mode - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure cs to spi mode - -// the current implementation leaves about 1 us between transfers ???? -// due to lack of documentation i could not find the reason -// skipping this would double the speed !!! - - //SET_PERI_REG_MASK(SPI_USER(1), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND); - - SET_PERI_REG_MASK(SPI_USER(1), SPI_USR_COMMAND); - - CLEAR_PERI_REG_MASK(SPI_USER(1), SPI_FLASH_MODE); - // SPI clock=CPU clock/8 => 10 Mhz - /* - WRITE_PERI_REG(SPI_CLOCK(1), - ((1&SPI_CLKDIV_PRE)<= 0) { - SPI.beginTransaction(spis); - } else { - while(READ_PERI_REG(SPI_CMD(1))&SPI_USR); - SPI1CLK=ssd1351_clock; - SPI1U=ssd1351_usr; - SPI1U1=ssd1351_usr1; - SPI1U2=ssd1351_usr2; - SPI1C=ssd1351_spi1c; - SPI1P=ssd1351_spi1p; - //GPMUX=ssd1351_gpmux; - WRITE_PERI_REG(PERIPHS_IO_MUX_MTDO_U,ssd1351_mtdo); - } - ssd131_start = 1; -} - -void SSD1351::stop(void) { - if (!ssd131_start) return; - - if (_dc >= 0) { - SPI.endTransaction(); - } else { - //while(SPI1CMD & SPIBUSY) {} - while(READ_PERI_REG(SPI_CMD(1))&SPI_USR); - SPI1CLK=ssd1351_clock_prev; - SPI1U=ssd1351_usr_prev; - SPI1U1=ssd1351_usr1_prev; - SPI1U2=ssd1351_usr2_prev; - SPI1C=ssd1351_spi1c_prev; - SPI1P=ssd1351_spi1p_prev; - //GPMUX=ssd1351_gpmux_prev; - WRITE_PERI_REG(PERIPHS_IO_MUX_MTDO_U,ssd1351_mtdo_prev); - } - ssd131_start = 0; -} - -// dc = 0 -void SSD1351::writecommand(uint8_t c) { - if (_hwspi) { - uint32_t regvalue; - uint8_t bytetemp; - start(); -//#define SPI_USR_COMMAND_BITLEN 0x0000000F -//#define SPI_USR_COMMAND_BITLEN_S 28 - if (_dc >= 0) { - digitalWrite(_dc, LOW); - SPI.transfer(c); - } else { - bytetemp = (c >> 1) & 0x7f; - regvalue= ((8&SPI_USR_COMMAND_BITLEN)<= 0) { - digitalWrite(_dc, HIGH); - SPI.transfer(d); - } else { - bytetemp = (d >> 1) | 0x80; - regvalue= ((8&SPI_USR_COMMAND_BITLEN)<= 0) { - digitalWrite(_dc, dc); - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(d&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - } else { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(dc) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(d&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - } - WRITE_PERI_REG( PIN_OUT_SET, 1 << _cs); -} - -#else -// ESP32 section -uint8_t ssd131_start; - -void SSD1351::writedata(uint8_t d) { - fastSPIwrite(d, 1); -} - -void SSD1351::writecommand(uint8_t c) { - fastSPIwrite(c, 0); -} - -#include "soc/spi_reg.h" -#include "soc/spi_struct.h" -#include "esp32-hal-spi.h" -#include "esp32-hal.h" -#include "soc/spi_struct.h" - -// diconnect from spi -void SSD1351::start(void) { - if (ssd131_start) return; - SPI.beginTransaction(spis); - ssd131_start = 1; -} - -// reconnect to spi -void SSD1351::stop(void) { - if (!ssd131_start) return; - SPI.endTransaction(); - ssd131_start = 0; -} - -// since ardunio transferBits ia completely disfunctional -// we use our own hardware driver for 9 bit spi -void SSD1351::fastSPIwrite(uint8_t d, uint8_t dc) { - - digitalWrite( _cs, LOW); - if (_dc >= 0) { - digitalWrite(_dc, dc); - SPI.transfer(d); - } else { - uint32_t regvalue = d >> 1; - if (dc) regvalue |= 0x80; - else regvalue &= 0x7f; - if (d & 1) regvalue |= 0x8000; - - REG_SET_BIT(SPI_USER_REG(3), SPI_USR_MOSI); - REG_WRITE(SPI_MOSI_DLEN_REG(3), 9 - 1); - uint32_t *dp=(uint32_t*)SPI_W0_REG(3); - *dp = regvalue; - REG_SET_BIT(SPI_CMD_REG(3), SPI_USR); - while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR)); - } - digitalWrite( _cs, HIGH); -} - -#endif - - -static const uint8_t PROGMEM initList[] = { - SSD1351_CMD_COMMANDLOCK, 1, // Set command lock, 1 arg - 0x12, - SSD1351_CMD_COMMANDLOCK, 1, // Set command lock, 1 arg - 0xB1, - SSD1351_CMD_DISPLAYOFF, 0, // Display off, no args - SSD1351_CMD_CLOCKDIV, 1, - 0xF1, // 7:4 = Oscillator Freq, 3:0 = CLK Div Ratio (A[3:0]+1 = 1..16) - SSD1351_CMD_MUXRATIO, 1, - 127, - SSD1351_CMD_DISPLAYOFFSET, 1, - 0x0, - SSD1351_CMD_SETGPIO, 1, - 0x00, - SSD1351_CMD_FUNCTIONSELECT, 1, - 0x01, // internal (diode drop) - SSD1351_CMD_PRECHARGE, 1, - 0x32, - SSD1351_CMD_VCOMH, 1, - 0x05, - SSD1351_CMD_STARTLINE, 1, - 0x00, - SSD1351_CMD_NORMALDISPLAY, 0, - SSD1351_CMD_CONTRASTABC, 3, - 0xC8, 0x80, 0xC8, - SSD1351_CMD_CONTRASTMASTER, 1, - 0x0F, - SSD1351_CMD_SETVSL, 3, - 0xA0, 0xB5, 0x55, - SSD1351_CMD_PRECHARGE2, 1, - 0x01, - SSD1351_CMD_HORIZSCROLL, 1, - 0x00, - SSD1351_CMD_STOPSCROLL, 0, - SSD1351_CMD_DISPLAYON, 0, // Main screen turn on - 0 }; // END OF COMMAND LIST - - -void SSD1351::begin(void) { - pinMode(_cs, OUTPUT); - digitalWrite(_cs,HIGH); - pinMode(_sclk, OUTPUT); - digitalWrite(_sclk, LOW); - pinMode(_mosi, OUTPUT); - digitalWrite(_mosi, LOW); - - if (_dc >= 0) { - pinMode(_dc, OUTPUT); - digitalWrite(_dc, LOW); - } - - -#ifndef ESP32 - if ((_sclk == 14) && (_mosi == 13) && (_cs == 15)) { - // we use hardware spi - _hwspi = 1; - SPI.begin(); - spi_lcd_mode_init(); - } else { - // we must use software spi - _hwspi = 0; - } -#else - _hwspi = 1; - SPI.begin(_sclk, -1, _mosi, -1); - spis = SPISettings(4500000, MSBFIRST, SPI_MODE3); -#endif - - const uint8_t *addr = (const uint8_t *)initList; - uint8_t cmd, x, numArgs; - - while ((cmd = pgm_read_byte(addr++)) > 0) { // '0' command ends list - x = pgm_read_byte(addr++); - numArgs = x & 0x7F; - if (cmd != 0xFF) { // '255' is ignored - sendcommand(cmd, addr, numArgs); - } - addr += numArgs; - } - delay(100); - setRotation(0); - stop(); -} - - -void SSD1351::sendcommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes) { - writecommand(commandByte); - for (int i=0; i=sizeof(ssd1351_colors)/2) index=0; - return ssd1351_colors[index]; -} - -void SSD1351::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { - setRotation(rot); - invertDisplay(false); - setTextWrap(false); // Allow text to run off edges - cp437(true); - setTextFont(font&3); - setTextSize(size&7); - setTextColor(SSD1351_WHITE,SSD1351_BLACK); - setCursor(0,0); - fillScreen(SSD1351_BLACK); - stop(); -} - -void SSD1351::DisplayOnff(int8_t on) { - if (on) { - writecommand(SSD1351_CMD_DISPLAYON); //Display on - } else { - writecommand(SSD1351_CMD_DISPLAYOFF); - } - stop(); -} - -// dimmer 0-100 -void SSD1351::dim(uint8_t contrast) { - writecommand(SSD1351_CMD_CONTRASTMASTER); - if (contrast>15) contrast=15; - writedata(contrast); - stop(); -} - -#define ssd1351_swap(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) ///< No-temp-var swap operation - - -void SSD1351::setAddrWindow_i(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h) { - uint16_t x2 = x1 + w - 1, - y2 = y1 + h - 1; - if (rotation&1) { // Vertical address increment mode - ssd1351_swap(x1,y1); - ssd1351_swap(x2,y2); - } - writecommand(SSD1351_CMD_SETCOLUMN); // X range - writedata(x1); - writedata(x2); - writecommand(SSD1351_CMD_SETROW); // Y range - writedata(y1); - writedata(y2); - writecommand(SSD1351_CMD_WRITERAM); // Begin write -} - -void SSD1351::write16BitColor(uint16_t color){ - writedata(color>>8); - writedata(color&0xff); -} - -#define MADCTL_MY 0x80 -#define MADCTL_MX 0x40 -#define MADCTL_MV 0x20 -#define MADCTL_ML 0x10 -#define MADCTL_RGB 0x00 -#define MADCTL_BGR 0x08 -#define MADCTL_MH 0x04 - -void SSD1351::setRotation(uint8_t r) { - // madctl bits: - // 6,7 Color depth (01 = 64K) - // 5 Odd/even split COM (0: disable, 1: enable) - // 4 Scan direction (0: top-down, 1: bottom-up) - // 3 Reserved - // 2 Color remap (0: A->B->C, 1: C->B->A) - // 1 Column remap (0: 0-127, 1: 127-0) - // 0 Address increment (0: horizontal, 1: vertical) - uint8_t madctl = 0b01100100; // 64K, enable split, CBA - - rotation = r & 3; // Clip input to valid range - - switch(rotation) { - case 0: - madctl |= 0b00010000; // Scan bottom-up - _width = SSD1351_WIDTH; - _height = SSD1351_HEIGHT; - break; - case 1: - madctl |= 0b00010011; // Scan bottom-up, column remap 127-0, vertical - _width = SSD1351_HEIGHT; - _height = SSD1351_WIDTH; - break; - case 2: - madctl |= 0b00000010; // Column remap 127-0 - _width = SSD1351_WIDTH; - _height = SSD1351_HEIGHT; - break; - case 3: - madctl |= 0b00000001; // Vertical - _width = SSD1351_HEIGHT; - _height = SSD1351_WIDTH; - break; - } - - sendcommand(SSD1351_CMD_SETREMAP, &madctl, 1); - uint8_t startline = (rotation < 2) ? SSD1351_HEIGHT : 0; - sendcommand(SSD1351_CMD_STARTLINE, &startline, 1); - stop(); -} - -void SSD1351::invertDisplay(boolean i) { - writecommand(i ? SSD1351_CMD_INVERTDISPLAY : SSD1351_CMD_NORMALDISPLAY); - stop(); -} - -void SSD1351::drawPixel(int16_t x, int16_t y, uint16_t color) { - if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; - setAddrWindow_i(x,y,1,1); - write16BitColor(color); - stop(); -} - -void SSD1351::setAddrWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { - // uint16_t x2 = x1 + w - 1, - // y2 = y1 + h - 1; - uint8_t flag=0; - - if (!x1 && !y1 && !x2 && !y2) { - x1=0; - y1=0; - x2=_width; - y2=_height; - flag=1; - } - - if (x2>_width) x2=_width; - if (y2>_height) y2=_height; - - x2--; - y2--; - if (rotation&1) { // Vertical address increment mode - ssd1351_swap(x1,y1); - ssd1351_swap(x2,y2); - } - //Serial.printf("x1:%d x2:%d y1:%d y2:%d\n",x1,x2,y1,y2); - writecommand(SSD1351_CMD_SETCOLUMN); // X range - writedata(x1); - writedata(x2); - writecommand(SSD1351_CMD_SETROW); // Y range - writedata(y1); - writedata(y2); - writecommand(SSD1351_CMD_WRITERAM); // Begin write - if (flag) stop(); -} - -void SSD1351::pushColors(uint16_t *data, uint16_t len, boolean first) { - for (uint16_t b=0; b= _width) || (y >= _height)) return; - if ((y+h-1) >= _height) h = _height-y; - - setAddrWindow_i(x,y,1,h); - while (h--) { - write16BitColor(color); - } - stop(); -} - -void SSD1351::drawFastHLine(int16_t x,int16_t y,int16_t w,uint16_t color) { - // Rudimentary clipping - if ((x >= _width) || (y >= _height)) return; - if ((x+w-1) >= _width) w = _width-x; - - setAddrWindow_i(x,y,w,1); - while (w--) { - write16BitColor(color); - } - stop(); -} diff --git a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/SSD1351.h b/lib/lib_display/Adafruit_SSD1351-gemu-1.0/SSD1351.h deleted file mode 100644 index ad81fc240..000000000 --- a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/SSD1351.h +++ /dev/null @@ -1,130 +0,0 @@ -/*************************************************** - This is our library for the Adafruit SSD1351 Breakout and Shield - ----> http://www.adafruit.com/products/1651 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 3 pins are required to - interface - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - -#ifndef _SSD1351_ -#define _SSD1351_ - -#if ARDUINO >= 100 - #include "Arduino.h" - #include "Print.h" -#else - #include "WProgram.h" -#endif - -#include -#include - - - -#define SSD1351_WIDTH 128 -#define SSD1351_HEIGHT 128 - - -// Color definitions -#define SSD1351_BLACK 0x0000 /* 0, 0, 0 */ -#define SSD1351_NAVY 0x000F /* 0, 0, 128 */ -#define SSD1351_DARKGREEN 0x03E0 /* 0, 128, 0 */ -#define SSD1351_DARKCYAN 0x03EF /* 0, 128, 128 */ -#define SSD1351_MAROON 0x7800 /* 128, 0, 0 */ -#define SSD1351_PURPLE 0x780F /* 128, 0, 128 */ -#define SSD1351_OLIVE 0x7BE0 /* 128, 128, 0 */ -#define SSD1351_LIGHTGREY 0xC618 /* 192, 192, 192 */ -#define SSD1351_DARKGREY 0x7BEF /* 128, 128, 128 */ -#define SSD1351_BLUE 0x001F /* 0, 0, 255 */ -#define SSD1351_GREEN 0x07E0 /* 0, 255, 0 */ -#define SSD1351_CYAN 0x07FF /* 0, 255, 255 */ -#define SSD1351_RED 0xF800 /* 255, 0, 0 */ -#define SSD1351_MAGENTA 0xF81F /* 255, 0, 255 */ -#define SSD1351_YELLOW 0xFFE0 /* 255, 255, 0 */ -#define SSD1351_WHITE 0xFFFF /* 255, 255, 255 */ -#define SSD1351_ORANGE 0xFD20 /* 255, 165, 0 */ -#define SSD1351_GREENYELLOW 0xAFE5 /* 173, 255, 47 */ -#define SSD1351_PINK 0xF81F - -#define SSD1351_CMD_SETCOLUMN 0x15 -#define SSD1351_CMD_SETROW 0x75 -#define SSD1351_CMD_WRITERAM 0x5C -#define SSD1351_CMD_READRAM 0x5D -#define SSD1351_CMD_SETREMAP 0xA0 -#define SSD1351_CMD_STARTLINE 0xA1 -#define SSD1351_CMD_DISPLAYOFFSET 0xA2 -#define SSD1351_CMD_DISPLAYALLOFF 0xA4 -#define SSD1351_CMD_DISPLAYALLON 0xA5 -#define SSD1351_CMD_NORMALDISPLAY 0xA6 -#define SSD1351_CMD_INVERTDISPLAY 0xA7 -#define SSD1351_CMD_FUNCTIONSELECT 0xAB -#define SSD1351_CMD_DISPLAYOFF 0xAE -#define SSD1351_CMD_DISPLAYON 0xAF -#define SSD1351_CMD_PRECHARGE 0xB1 -#define SSD1351_CMD_DISPLAYENHANCE 0xB2 -#define SSD1351_CMD_CLOCKDIV 0xB3 -#define SSD1351_CMD_SETVSL 0xB4 -#define SSD1351_CMD_SETGPIO 0xB5 -#define SSD1351_CMD_PRECHARGE2 0xB6 -#define SSD1351_CMD_SETGRAY 0xB8 -#define SSD1351_CMD_USELUT 0xB9 -#define SSD1351_CMD_PRECHARGELEVEL 0xBB -#define SSD1351_CMD_VCOMH 0xBE -#define SSD1351_CMD_CONTRASTABC 0xC1 -#define SSD1351_CMD_CONTRASTMASTER 0xC7 -#define SSD1351_CMD_MUXRATIO 0xCA -#define SSD1351_CMD_COMMANDLOCK 0xFD -#define SSD1351_CMD_HORIZSCROLL 0x96 -#define SSD1351_CMD_STOPSCROLL 0x9E -#define SSD1351_CMD_STARTSCROLL 0x9F - - -#define PIN_OUT_SET 0x60000304 -#define PIN_OUT_CLEAR 0x60000308 - -class SSD1351 : public Renderer { - - public: - - SSD1351(int8_t cs,int8_t mosi,int8_t sclk, int8_t dc); - - void begin(void); - void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font); - void setAddrWindow_i(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); - void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); - void pushColors(uint16_t *data, uint16_t len, boolean first); - void drawPixel(int16_t x, int16_t y, uint16_t color); - void write16BitColor(uint16_t color); - void setRotation(uint8_t r); - void invertDisplay(boolean i); - uint16_t GetColorFromIndex(uint8_t index); - void DisplayOnff(int8_t on); - void writecommand(uint8_t c); - void writedata(uint8_t d); - void commandList(uint8_t *addr); - void hw_spi_init(); - void sendcommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes); - void sendcommand(uint8_t commandByte,uint8_t *dataBytes, uint8_t numDataBytes); - void drawFastVLine(int16_t x,int16_t y,int16_t h,uint16_t color); - void drawFastHLine(int16_t x,int16_t y,int16_t w,uint16_t color); - void spi_lcd_mode_init(void); - void dim(uint8_t contrast); - - private: - uint8_t tabcolor; - SPISettings spis; - void fastSPIwrite(uint8_t d,uint8_t dc); - void start(void); - void stop(void); - int8_t _cs, _mosi, _sclk, _hwspi, _dc; - -}; - -#endif diff --git a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/Tiger.c b/lib/lib_display/Adafruit_SSD1351-gemu-1.0/Tiger.c deleted file mode 100644 index 83e0ba9bf..000000000 --- a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/Tiger.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -// picture with 51 x 34 pixels -// table size 3468 bytes -#if 0 -const uint16_t picture[] = { -0x0000,0x0841,0x0841,0x0840,0x0841,0x0841,0x1041,0x1041,0x1041,0x1041,0x1041,0x1880,0x1041,0x1041,0x1040,0x1041,0x1881,0x1880,0x1880,0x1880,0x2081,0x2081,0x2080,0x20c1,0x3942,0x3942,0x3101,0x2080,0x2881,0x2880,0x2881,0x2881,0x2881,0x2880,0x2881,0x30c1,0x30c1,0x1840,0x2881,0x30c1,0x3901,0x3941,0x3901,0x3101,0x3101,0x3101,0x3101,0x3101,0x4182,0x4182,0x0000, -0x0000,0x0841,0x0841,0x0841,0x1881,0x1881,0x1881,0x1881,0x1881,0x1881,0x2081,0x28c1,0x2081,0x2080,0x2081,0x2081,0x28c1,0x28c1,0x2901,0x3101,0x3101,0x3101,0x3101,0x3942,0x5a04,0x6244,0x6244,0x51c2,0x4101,0x4101,0x4101,0x4101,0x3901,0x4101,0x4101,0x5181,0x4941,0x59c2,0x4141,0x30c1,0x4941,0x4982,0x38c1,0x5182,0x4141,0x4101,0x4941,0x5182,0x5182,0x6a43,0x0000, -0x0000,0x1041,0x0841,0x1041,0x1881,0x20c1,0x2081,0x20c1,0x2081,0x28c1,0x20c1,0x2901,0x2081,0x2081,0x20c1,0x28c1,0x28c1,0x3101,0x3101,0x3101,0x3101,0x3941,0x3942,0x4183,0x5a45,0x6244,0x6a85,0x6a84,0x5a03,0x4141,0x4101,0x4101,0x4101,0x4101,0x4101,0x4101,0x4101,0x4941,0x4141,0x59c2,0x2880,0x38c1,0x4941,0x4941,0x4141,0x4941,0x5181,0x5182,0x6203,0x6203,0x0000, -0x0000,0x20c1,0x1041,0x1881,0x2901,0x3142,0x20c1,0x28c1,0x2901,0x2901,0x2901,0x2901,0x2901,0x2901,0x3101,0x3101,0x3141,0x3942,0x4182,0x4182,0x49c3,0x49c3,0x5204,0x5a45,0x5a45,0x5a45,0x6245,0x6245,0x5a45,0x5a04,0x51c2,0x4141,0x4101,0x4101,0x4101,0x6244,0x8388,0x5a04,0x4101,0x4101,0x4901,0x5182,0x30c1,0x4982,0x4982,0x5182,0x4941,0x4941,0x5181,0x4141,0x0000, -0x0000,0x1881,0x1041,0x1881,0x2101,0x2902,0x28c1,0x2901,0x2901,0x2901,0x2901,0x28c1,0x20c1,0x20c1,0x28c1,0x28c1,0x28c1,0x3942,0x4182,0x4141,0x4182,0x4982,0x4982,0x51c3,0x51c3,0x51c3,0x51c3,0x51c3,0x51c3,0x51c3,0x5a04,0x51c3,0x4982,0x4141,0x9c09,0xd612,0xbd50,0xa48c,0x4100,0x4101,0x4101,0x4101,0x59c2,0x4981,0x3901,0x3901,0x3901,0x4941,0x4101,0x5182,0x0000, -0x0000,0x1881,0x1041,0x1881,0x2902,0x2902,0x2902,0x3142,0x3102,0x3102,0x2901,0x28c1,0x28c1,0x28c1,0x28c1,0x28c1,0x3942,0x51c3,0x6a84,0x3941,0x4182,0x4982,0x4982,0x5a03,0x5a03,0x6244,0x5a04,0x51c3,0x51c3,0x5a03,0x5a44,0x5204,0x3942,0x9bc8,0xcd8f,0xc590,0xc5d1,0xcdd2,0x4100,0x4101,0x4101,0x4101,0x4941,0x4941,0x5182,0x3101,0x4941,0x4941,0x4941,0x4941,0x0000, -0x0000,0x1881,0x1041,0x1881,0x3142,0x3142,0x3102,0x3142,0x3142,0x3102,0x3101,0x28c1,0x28c1,0x28c1,0x28c1,0x5204,0x8bc9,0xbd4f,0xcdd1,0xcdd0,0x6244,0x4982,0x51c2,0x5a45,0xac4a,0x9387,0x4982,0x8b87,0x9387,0x8346,0x6a86,0x5204,0xac89,0xaccc,0xc54f,0xb4ce,0x9c4b,0xc5d1,0x4100,0x4901,0x4101,0x4941,0x4941,0x4101,0x4142,0x6203,0x4941,0x2081,0x38c1,0x5182,0x0000, -0x0000,0x1881,0x1041,0x2081,0x3143,0x3142,0x3142,0x3983,0x3943,0x3102,0x3101,0x28c1,0x28c1,0x28c1,0x2901,0x8b89,0x9c0b,0x9c0a,0xd612,0xac8c,0xd5d1,0x9bc8,0xbc8a,0x9bc7,0xa3c7,0x9bc7,0x9b86,0x9bc7,0x8347,0x93c8,0xac8b,0xc50c,0xcd4b,0xb48a,0xde12,0xde94,0xaccd,0x6ac6,0x4101,0x4101,0x4941,0x4901,0x4101,0x4941,0x4101,0x38c1,0x3901,0x4141,0x2081,0x3901,0x0000, -0x0000,0x1881,0x1041,0x20c1,0x3984,0x3143,0x3943,0x41c4,0x3983,0x3142,0x3101,0x3101,0x3101,0x3101,0x3101,0x9c0a,0x7ac5,0x6203,0xa48c,0xc54f,0xa44b,0xbd0c,0xac08,0x8306,0xc54c,0x72c5,0x7b06,0x6a85,0xddcd,0xcd4c,0x93c7,0xcd0b,0x9386,0xdd8c,0xe60f,0xac8b,0x8389,0x6244,0x6203,0x5181,0x4101,0x4101,0x4901,0x4901,0x4101,0x3901,0x3081,0x38c1,0x59c2,0x4141,0x0000, -0x0000,0x2081,0x1841,0x28c1,0x41c4,0x3142,0x3983,0x49c5,0x4184,0x3102,0x3101,0x3101,0x3101,0x3101,0x3101,0x8348,0xa44b,0x6203,0x6204,0xb50e,0xbd0d,0xe60f,0xe650,0xee90,0x8346,0xb48b,0xb48b,0x7b07,0x72c6,0xd54c,0xbd0b,0xf758,0xffd9,0xb489,0xac07,0xe60e,0xee92,0x5204,0x51c3,0x5181,0x4941,0x4941,0x4101,0x4101,0x4941,0x4101,0x4101,0x3081,0x30c1,0x6a43,0x0000, -0x0000,0x1881,0x1841,0x28c1,0x41c4,0x3983,0x3983,0x41c4,0x3983,0x3102,0x3101,0x3101,0x3101,0x3101,0x3101,0x3941,0x6245,0x7285,0x9c4b,0xa44b,0xee90,0xdd8c,0x8b05,0xde10,0x940b,0xd58e,0xddcd,0xcd0b,0xdd8c,0x8b47,0x9b87,0xbd90,0xd654,0xffda,0xb48b,0xa3c7,0x9c08,0x6285,0x49c3,0x4983,0x4942,0x4941,0x5181,0x4101,0x4101,0x4941,0x4101,0x38c1,0x30c1,0x4141,0x0000, -0x0000,0x1881,0x1881,0x28c1,0x41c4,0x3983,0x41c4,0x4183,0x3942,0x3101,0x3101,0x3101,0x3101,0x3901,0x3901,0x3901,0x4142,0x8bc9,0x6286,0x8b87,0xbc89,0x9345,0xc50b,0xffd9,0xce13,0xe716,0xcd4b,0x7ac5,0xc4ca,0x7284,0x9bc8,0xcdd0,0xde53,0xbd91,0xce13,0xbd0d,0xe60f,0xb4cc,0x6ac6,0x51c4,0x49c3,0x4982,0x5182,0x5181,0x4941,0x4101,0x4101,0x4101,0x4101,0x4101,0x0000, -0x0000,0x1881,0x1881,0x2901,0x41c4,0x3983,0x41c4,0x4183,0x3942,0x3101,0x3101,0x3901,0x3901,0x3101,0x3101,0x6244,0x8b05,0xa409,0xd58d,0xb448,0x82c4,0xbcca,0xee93,0xf757,0xb50f,0xbd4f,0x9c4b,0xb489,0x8b46,0xcd0a,0x7ac4,0x9bc8,0xff98,0xb50f,0xacce,0x940a,0xb4cc,0xac8b,0xeed4,0x51c4,0x49c3,0x49c3,0x4983,0x51c3,0x4941,0x4101,0x4101,0x3901,0x4101,0x38c1,0x0000, -0x0000,0x2081,0x2081,0x2901,0x4184,0x3983,0x4183,0x3942,0x3142,0x3101,0x3101,0x3101,0x3941,0x3101,0x7ac5,0x7ac5,0x6a43,0x6a43,0x6a43,0xbcca,0xe5cd,0x4182,0x9c4b,0x4183,0x8bca,0xa44c,0xb4cd,0xb447,0xb448,0xccc9,0xccca,0xc4c9,0xee94,0x6245,0x838a,0x8b46,0xd5cf,0xde52,0xef15,0x51c3,0x49c3,0x49c3,0x49c3,0x5a45,0x4982,0x4941,0x5141,0x4941,0x3901,0x4101,0x0000, -0x0000,0x2081,0x2080,0x3102,0x3983,0x4184,0x3942,0x3142,0x3942,0x3942,0x3901,0x3941,0x3942,0x7ac5,0x7ac4,0x82c4,0x59c2,0xa3c8,0x5a45,0xd5cd,0xe60f,0xbccb,0x9c09,0xc54e,0x8389,0x93c8,0x9b87,0x69c2,0x8ac4,0xbc89,0xcd0a,0xbc88,0x8bca,0x8b86,0xbd92,0x8305,0xddcf,0xb50e,0xacce,0x5a45,0x51c3,0x49c3,0x49c3,0x5a46,0x4982,0x4982,0x4941,0x4101,0x30c1,0x30c1,0x0000, -0x0000,0x2081,0x2081,0x3142,0x49c4,0x4a05,0x4184,0x4183,0x4183,0x49c3,0x4183,0x7ac6,0x9bc8,0x9b86,0xa386,0x6a44,0x3901,0xb48b,0x4182,0xd54c,0x3101,0xc4ca,0x6244,0x8348,0x61c2,0x6202,0x5a04,0x7a84,0x69c2,0xac07,0xcd0a,0xb448,0x7307,0xf79a,0x7284,0xbc89,0xaccd,0x940b,0x6245,0x51c3,0x51c3,0x49c3,0x49c3,0x6246,0x4982,0x4982,0x4982,0x4141,0x3081,0x2881,0x0000, -0x0000,0x28c1,0x28c1,0x4184,0x5206,0x4a05,0x49c4,0x49c4,0x49c4,0x5205,0x9b87,0x7b06,0x9386,0xa3c6,0x51c2,0x61c2,0x5981,0xe652,0x5204,0xa449,0x3901,0xa3c7,0xac07,0x9305,0x8348,0xb4ce,0x28c1,0x61c2,0x7243,0x9b45,0xcd0a,0xbc89,0x8b05,0xcd8e,0xcd4b,0x8347,0xffd9,0xd654,0x6a87,0x6286,0x6286,0x5a46,0x5a46,0x6287,0x5a45,0x5204,0x5204,0x5204,0x4182,0x2081,0x0000, -0x0000,0x28c1,0x28c1,0x3983,0x41c4,0x41c4,0x4184,0x4184,0x7285,0x82c5,0xa387,0x49c3,0xa3c7,0x9b86,0x4182,0x6a02,0x61c2,0x8b88,0x4142,0x72c5,0x6a84,0xa3c7,0x4982,0x3101,0xa3c6,0xbc8a,0x51c3,0x4941,0x7202,0xac07,0xbc89,0xcd0a,0xccca,0x9b87,0xcd0b,0x8b89,0x7b8a,0xa48e,0x5204,0x5204,0x49c4,0x49c3,0x49c3,0x49c4,0x49c3,0x4983,0x4183,0x4182,0x4182,0x3982,0x0000, -0x0000,0x2081,0x28c1,0x3983,0x41c4,0x4184,0x4184,0x5a03,0x9b86,0x9b86,0x7ac5,0x6244,0x9346,0x9b46,0x4141,0x6a02,0x69c2,0x8305,0x7285,0x3941,0xa449,0xac08,0xcd0c,0x9b86,0x7ac5,0xac08,0x9388,0x6202,0x7a83,0xac09,0xa408,0xcd0b,0xc50b,0xa3c6,0xbcca,0xff99,0x940c,0xaccf,0x49c3,0x49c3,0x49c3,0x4183,0x4183,0x4183,0x4183,0x4182,0x3942,0x3942,0x3942,0x4183,0x0000, -0x0000,0x2081,0x28c1,0x3943,0x41c4,0x4184,0x4183,0x9386,0x9b87,0xa408,0x9346,0x6a44,0x8b05,0x8284,0x5982,0x7a43,0x5181,0x7a43,0x9c09,0x72c6,0xbd0c,0x5a03,0x93c8,0x6a45,0x8b05,0x9b86,0x7a84,0x7243,0x7243,0x9b86,0xb489,0xbccb,0xbccb,0xb447,0xbc8a,0x6ac7,0xce13,0xc5d2,0x49c3,0x49c3,0x4983,0x4183,0x4183,0x4182,0x4182,0x4182,0x3942,0x3942,0x3942,0x4183,0x0000, -0x0000,0x2080,0x28c1,0x3942,0x3984,0x7b06,0x7285,0x7ac5,0x9b87,0x9b86,0x9345,0x6203,0x8284,0x7a83,0x5982,0x7202,0x7203,0x7243,0x9387,0x7b07,0x8b88,0x8347,0x2080,0xb4cb,0xbccc,0x5a03,0x6a03,0x8b04,0x61c2,0x8b05,0xb48b,0xbccb,0xcd4c,0xac09,0xcd0b,0xc590,0x9c8d,0x7b89,0x4983,0x4983,0x4983,0x4183,0x4182,0x4182,0x4182,0x4182,0x3942,0x3942,0x3941,0x4183,0x0000, -0x0000,0x2081,0x28c1,0x3942,0x8b46,0x8b05,0x8b05,0x3101,0x9b86,0x9345,0x8ac4,0x82c4,0x7a43,0x7a83,0x6a02,0x8283,0x8283,0x61c2,0x9b86,0x8b88,0x5204,0xb48b,0x51c3,0xac8a,0x3942,0x6a03,0x7243,0x9345,0x7284,0x8305,0xbccc,0xc54d,0xcd8d,0xc58e,0xcd4c,0xac8c,0xcdd2,0x7307,0x4183,0x4983,0x4982,0x4182,0x4182,0x4182,0x4182,0x3982,0x3942,0x3942,0x3101,0x4183,0x0000, -0x0000,0x2081,0x5a03,0x59c2,0x4141,0x8283,0x82c4,0x4982,0x8b05,0x8b05,0x8284,0x82c4,0x8283,0x8283,0x7a43,0x8283,0x7a02,0x8ac3,0x9346,0x7285,0x93c9,0x5a44,0xa44a,0xb4cb,0x9388,0x7284,0x7a84,0x7243,0x4182,0x7ac5,0xa44a,0x9c4b,0xcd4e,0xbd0e,0xb4cb,0xde53,0xa4ce,0x7308,0x8bca,0x49c3,0x4182,0x4182,0x4182,0x4182,0x4142,0x3942,0x3942,0x3942,0x3101,0x4183,0x0000, -0x0000,0x7243,0x7a43,0x8283,0x3101,0x59c2,0x7a83,0x7a83,0x4141,0x9345,0x8b05,0x7202,0x7203,0x7a43,0x7a43,0x69c2,0x61c2,0x7a02,0x82c4,0x9387,0xa44b,0x3101,0x4182,0x6a86,0x8b88,0xbd4e,0x6244,0x4981,0xac8b,0x4142,0x6203,0xb3c8,0x8307,0xffd9,0xac8b,0x8389,0xa48d,0xa4cd,0x8bca,0x7b49,0x49c3,0x4182,0x4182,0x3982,0x4182,0x3942,0x3942,0x3141,0x3101,0x4183,0x0000, -0x0000,0x6a02,0x7a43,0x7a83,0x8283,0x3901,0x7243,0x7a43,0x7a43,0x4982,0x8283,0x7a43,0x7243,0x5981,0x7202,0x7202,0x69c2,0x5981,0x7a42,0x9bc7,0x51c3,0x93c8,0xa449,0x93c9,0x7b48,0x8347,0x4142,0x6a84,0x8346,0xbccc,0x8b88,0x5182,0xde53,0xcdd1,0xd613,0x8bca,0xb50f,0x8bca,0x8bca,0x8389,0x6286,0x5204,0x4a04,0x49c3,0x4183,0x4183,0x4183,0x4182,0x3982,0x4a04,0x0000, -0x0000,0x8283,0x61c2,0x59c2,0x7202,0x8283,0x4941,0x7a83,0x7243,0x7243,0x7a83,0x7a43,0x7a43,0x7242,0x6182,0x6181,0x7202,0x61c2,0x5981,0x7a43,0x6a43,0x8347,0x8346,0xb48b,0xb4cb,0x9c09,0x5a04,0x7b07,0x93c9,0x9c0a,0x9c0a,0x5a44,0xb4cd,0xa44d,0x8389,0xb50e,0xa44c,0x8b89,0x8b89,0x93ca,0x8388,0x8348,0x8348,0x7b48,0x7b07,0x7307,0x7307,0x72c7,0x6ac7,0x7307,0x0000, -0x0000,0x8ac4,0x8283,0x7a83,0x61c2,0x7a43,0x7a43,0x4942,0x8ac4,0x6a02,0x4982,0x7a83,0x7202,0x7243,0x7a43,0x6a02,0x5941,0x69c2,0x5981,0x5981,0x9386,0x8b46,0x7284,0x5a03,0x51c3,0x8b88,0x6244,0x4183,0x4142,0x7b07,0x3941,0x5a44,0x3982,0x7b07,0x9c0b,0x8348,0x8bc9,0x8b89,0x8388,0x8388,0x8348,0x8348,0x8348,0x8348,0x7b47,0x7b07,0x7b07,0x7307,0x72c6,0x72c7,0x0000, -0x0000,0x8ac4,0x8b04,0x82c3,0x82c4,0x82c4,0x8283,0x82c4,0x4982,0x8ac4,0x6a02,0x5182,0x7243,0x7202,0x7202,0x7202,0x6182,0x5141,0x6182,0x69c2,0x4941,0x7284,0x8b46,0x9bc8,0x8b46,0x93c8,0x49c3,0x3101,0x5a03,0x8306,0x72c7,0xb50e,0xacce,0xb50e,0x8348,0x8348,0x8b89,0x8348,0x8348,0x8348,0x8348,0x8348,0x8347,0x7b07,0x7b07,0x7b07,0x7307,0x72c7,0x72c6,0x72c6,0x0000, -0x0000,0x8b04,0x8ac4,0x9305,0x8ac4,0x8ac4,0x9304,0x8ac4,0x8b04,0x59c2,0x6a03,0x7a43,0x6a03,0x6a02,0x7203,0x69c2,0x69c2,0x6182,0x5141,0x5941,0x69c2,0x5141,0x6203,0x7243,0x7ac5,0x7ac5,0x8346,0xa44a,0xb50d,0xbd0e,0xcd8f,0xd613,0xbd50,0x8bca,0x72c7,0x72c6,0x72c6,0x72c6,0x72c6,0x72c6,0x7307,0x7b07,0x7b07,0x7b07,0x7b07,0x7307,0x72c6,0x72c6,0x72c6,0x72c6,0x0000, -0x0000,0x9345,0x9304,0x9345,0x9345,0x9345,0x9305,0x9345,0x9305,0x8ac4,0x7283,0x5182,0x6202,0x7243,0x6a02,0x69c2,0x61c2,0x5981,0x5982,0x5141,0x4101,0x5101,0x5982,0x5141,0x5141,0x61c2,0x8284,0x9386,0xa44a,0xde53,0xad0f,0xef16,0xe6d6,0x6245,0x4982,0x4982,0x4982,0x4982,0x49c2,0x49c2,0x49c3,0x49c3,0x51c3,0x51c3,0x51c3,0x5203,0x5203,0x5203,0x5203,0x5203,0x0000, -0x0000,0x7a84,0x51c2,0x9b86,0x9b85,0x9304,0x8b04,0x8b04,0x8b04,0x9345,0x7a83,0x7a83,0x7a84,0x30c0,0x7243,0x61c2,0x6182,0x5981,0x5981,0x5141,0x5141,0x38c1,0x2881,0x38c1,0x5181,0x6a02,0x8b04,0xa407,0xcd4c,0xde52,0xef16,0xef57,0xd695,0x6285,0x5a04,0x51c3,0x49c3,0x4982,0x4182,0x3942,0x3941,0x3101,0x3101,0x28c1,0x28c1,0x20c1,0x2081,0x2081,0x2081,0x2081,0x0000, -0x0000,0xa407,0x9b86,0x3901,0x9b86,0xa386,0x9345,0x82c4,0x8b04,0x82c4,0x9304,0x7243,0x59c2,0x7243,0x28c1,0x69c2,0x5981,0x5981,0x4941,0x4901,0x4901,0x5141,0x5141,0x5141,0x4101,0x4941,0x5182,0x5182,0x4182,0xcd8f,0xef16,0xef57,0xa4cf,0x7b07,0x7b07,0x7b07,0x7ac6,0x72c6,0x72c6,0x6a85,0x6a85,0x6245,0x6244,0x5a04,0x5203,0x49c3,0x4182,0x3942,0x3941,0x3101,0x0000, -0x0000,0xac48,0xa407,0xac08,0x30c1,0x8b45,0xa3c7,0x9345,0x8b04,0x8ac4,0x82c4,0x82c4,0x7a83,0x6202,0x6a02,0x30c1,0x59c2,0x61c2,0x5141,0x4901,0x4101,0x4101,0x4101,0x4901,0x5141,0x6182,0x7202,0x8ac4,0xa407,0xac8a,0xa48d,0xef57,0xb550,0x7b06,0x7306,0x72c6,0x72c6,0x72c6,0x72c6,0x72c6,0x72c6,0x72c6,0x72c6,0x72c6,0x72c6,0x6ac6,0x6ac6,0x6a85,0x6a85,0x6a85,0x0000, -0x0000,0x0000,0x1081,0x1081,0x1081,0x0000,0x1041,0x1041,0x0841,0x0840,0x0841,0x0840,0x0841,0x0000,0x0840,0x0840,0x0000,0x0800,0x0840,0x0800,0x0000,0x0000,0x0000,0x0000,0x0000,0x0800,0x0840,0x0840,0x1041,0x1082,0x1082,0x18c3,0x1081,0x0841,0x0841,0x0841,0x0841,0x0841,0x0840,0x0840,0x0841,0x0841,0x0840,0x0841,0x0840,0x0841,0x0840,0x0840,0x0840,0x0840,0x0000, -0x0000 -}; -#endif diff --git a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/Tiger.rgb b/lib/lib_display/Adafruit_SSD1351-gemu-1.0/Tiger.rgb deleted file mode 100644 index e3c49ce82..000000000 Binary files a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/Tiger.rgb and /dev/null differ diff --git a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/keywords.txt b/lib/lib_display/Adafruit_SSD1351-gemu-1.0/keywords.txt deleted file mode 100644 index cfc1e2023..000000000 --- a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/keywords.txt +++ /dev/null @@ -1,30 +0,0 @@ -####################################### -# Syntax Coloring Map -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -SSD3115 KEYWORD1 - - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - -setRotation KEYWORD2 -setAddrWindow KEYWORD2 -pushColor KEYWORD2 -drawPixel KEYWORD2 -drawFastVLine KEYWORD2 -drawFastHLine KEYWORD2 -fillRect KEYWORD2 -setRotation KEYWORD2 -setRotation KEYWORD2 -height KEYWORD2 -width KEYWORD2 -invertDisplay KEYWORD2 -drawImage KEYWORD2 -setScrollArea KEYWORD2 -scroll KEYWORD2 diff --git a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/library.properties b/lib/lib_display/Adafruit_SSD1351-gemu-1.0/library.properties deleted file mode 100644 index e405f69b6..000000000 --- a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=SSD3115 -version=1.0 -author=Limor Fried/Ladyada -maintainer=Limor Fried/Ladyada -sentence=Library for SSD3115 displays -paragraph=Library for SSD3115 displays -category=Display -url=https://github.com/adafruit/Adafruit-SSD1351-library -architectures=* diff --git a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/spi_register.h b/lib/lib_display/Adafruit_SSD1351-gemu-1.0/spi_register.h deleted file mode 100644 index 340559ae1..000000000 --- a/lib/lib_display/Adafruit_SSD1351-gemu-1.0/spi_register.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2010 - 2011 Espressif System - * - */ - -#ifndef SPI_REGISTER_H_INCLUDED -#define SPI_REGISTER_H_INCLUDED - -#define REG_SPI_BASE(i) (0x60000200-i*0x100) -#define SPI_CMD(i) (REG_SPI_BASE(i) + 0x0) -#define SPI_USR (BIT(18)) - -#define SPI_ADDR(i) (REG_SPI_BASE(i) + 0x4) - -#define SPI_CTRL(i) (REG_SPI_BASE(i) + 0x8) -#define SPI_WR_BIT_ORDER (BIT(26)) -#define SPI_RD_BIT_ORDER (BIT(25)) -#define SPI_QIO_MODE (BIT(24)) -#define SPI_DIO_MODE (BIT(23)) -#define SPI_QOUT_MODE (BIT(20)) -#define SPI_DOUT_MODE (BIT(14)) -#define SPI_FASTRD_MODE (BIT(13)) - - - -#define SPI_RD_STATUS(i) (REG_SPI_BASE(i) + 0x10) - -#define SPI_CTRL2(i) (REG_SPI_BASE(i) + 0x14) - -#define SPI_CS_DELAY_NUM 0x0000000F -#define SPI_CS_DELAY_NUM_S 28 -#define SPI_CS_DELAY_MODE 0x00000003 -#define SPI_CS_DELAY_MODE_S 26 -#define SPI_MOSI_DELAY_NUM 0x00000007 -#define SPI_MOSI_DELAY_NUM_S 23 -#define SPI_MOSI_DELAY_MODE 0x00000003 -#define SPI_MOSI_DELAY_MODE_S 21 -#define SPI_MISO_DELAY_NUM 0x00000007 -#define SPI_MISO_DELAY_NUM_S 18 -#define SPI_MISO_DELAY_MODE 0x00000003 -#define SPI_MISO_DELAY_MODE_S 16 -#define SPI_CK_OUT_HIGH_MODE 0x0000000F -#define SPI_CK_OUT_HIGH_MODE_S 12 -#define SPI_CK_OUT_LOW_MODE 0x0000000F -#define SPI_CK_OUT_LOW_MODE_S 8 - -#define SPI_CLOCK(i) (REG_SPI_BASE(i) + 0x18) -#define SPI_CLK_EQU_SYSCLK (BIT(31)) -#define SPI_CLKDIV_PRE 0x00001FFF -#define SPI_CLKDIV_PRE_S 18 -#define SPI_CLKCNT_N 0x0000003F -#define SPI_CLKCNT_N_S 12 -#define SPI_CLKCNT_H 0x0000003F -#define SPI_CLKCNT_H_S 6 -#define SPI_CLKCNT_L 0x0000003F -#define SPI_CLKCNT_L_S 0 - -#define SPI_USER(i) (REG_SPI_BASE(i) + 0x1C) -#define SPI_USR_COMMAND (BIT(31)) -#define SPI_USR_ADDR (BIT(30)) -#define SPI_USR_DUMMY (BIT(29)) -#define SPI_USR_MISO (BIT(28)) -#define SPI_USR_MOSI (BIT(27)) - -#define SPI_USR_MOSI_HIGHPART (BIT(25)) -#define SPI_USR_MISO_HIGHPART (BIT(24)) - - -#define SPI_SIO (BIT(16)) -#define SPI_FWRITE_QIO (BIT(15)) -#define SPI_FWRITE_DIO (BIT(14)) -#define SPI_FWRITE_QUAD (BIT(13)) -#define SPI_FWRITE_DUAL (BIT(12)) -#define SPI_WR_BYTE_ORDER (BIT(11)) -#define SPI_RD_BYTE_ORDER (BIT(10)) -#define SPI_CK_OUT_EDGE (BIT(7)) -#define SPI_CK_I_EDGE (BIT(6)) -#define SPI_CS_SETUP (BIT(5)) -#define SPI_CS_HOLD (BIT(4)) -#define SPI_FLASH_MODE (BIT(2)) -#define SPI_DOUTDIN (BIT(0)) - -#define SPI_USER1(i) (REG_SPI_BASE(i) + 0x20) -#define SPI_USR_ADDR_BITLEN 0x0000003F -#define SPI_USR_ADDR_BITLEN_S 26 -#define SPI_USR_MOSI_BITLEN 0x000001FF -#define SPI_USR_MOSI_BITLEN_S 17 -#define SPI_USR_MISO_BITLEN 0x000001FF -#define SPI_USR_MISO_BITLEN_S 8 - -#define SPI_USR_DUMMY_CYCLELEN 0x000000FF -#define SPI_USR_DUMMY_CYCLELEN_S 0 - -#define SPI_USER2(i) (REG_SPI_BASE(i) + 0x24) -#define SPI_USR_COMMAND_BITLEN 0x0000000F -#define SPI_USR_COMMAND_BITLEN_S 28 -#define SPI_USR_COMMAND_VALUE 0x0000FFFF -#define SPI_USR_COMMAND_VALUE_S 0 - -#define SPI_WR_STATUS(i) (REG_SPI_BASE(i) + 0x28) -#define SPI_PIN(i) (REG_SPI_BASE(i) + 0x2C) -#define SPI_CS2_DIS (BIT(2)) -#define SPI_CS1_DIS (BIT(1)) -#define SPI_CS0_DIS (BIT(0)) -#define SPI_IDLE_EDGE (BIT(29)) - -#define SPI_SLAVE(i) (REG_SPI_BASE(i) + 0x30) -#define SPI_SYNC_RESET (BIT(31)) -#define SPI_SLAVE_MODE (BIT(30)) -#define SPI_SLV_WR_RD_BUF_EN (BIT(29)) -#define SPI_SLV_WR_RD_STA_EN (BIT(28)) -#define SPI_SLV_CMD_DEFINE (BIT(27)) -#define SPI_TRANS_CNT 0x0000000F -#define SPI_TRANS_CNT_S 23 -#define SPI_TRANS_DONE_EN (BIT(9)) -#define SPI_SLV_WR_STA_DONE_EN (BIT(8)) -#define SPI_SLV_RD_STA_DONE_EN (BIT(7)) -#define SPI_SLV_WR_BUF_DONE_EN (BIT(6)) -#define SPI_SLV_RD_BUF_DONE_EN (BIT(5)) - - - -#define SLV_SPI_INT_EN 0x0000001f -#define SLV_SPI_INT_EN_S 5 - -#define SPI_TRANS_DONE (BIT(4)) -#define SPI_SLV_WR_STA_DONE (BIT(3)) -#define SPI_SLV_RD_STA_DONE (BIT(2)) -#define SPI_SLV_WR_BUF_DONE (BIT(1)) -#define SPI_SLV_RD_BUF_DONE (BIT(0)) - -#define SPI_SLAVE1(i) (REG_SPI_BASE(i) + 0x34) -#define SPI_SLV_STATUS_BITLEN 0x0000001F -#define SPI_SLV_STATUS_BITLEN_S 27 -#define SPI_SLV_BUF_BITLEN 0x000001FF -#define SPI_SLV_BUF_BITLEN_S 16 -#define SPI_SLV_RD_ADDR_BITLEN 0x0000003F -#define SPI_SLV_RD_ADDR_BITLEN_S 10 -#define SPI_SLV_WR_ADDR_BITLEN 0x0000003F -#define SPI_SLV_WR_ADDR_BITLEN_S 4 - -#define SPI_SLV_WRSTA_DUMMY_EN (BIT(3)) -#define SPI_SLV_RDSTA_DUMMY_EN (BIT(2)) -#define SPI_SLV_WRBUF_DUMMY_EN (BIT(1)) -#define SPI_SLV_RDBUF_DUMMY_EN (BIT(0)) - - - -#define SPI_SLAVE2(i) (REG_SPI_BASE(i) + 0x38) -#define SPI_SLV_WRBUF_DUMMY_CYCLELEN 0X000000FF -#define SPI_SLV_WRBUF_DUMMY_CYCLELEN_S 24 -#define SPI_SLV_RDBUF_DUMMY_CYCLELEN 0X000000FF -#define SPI_SLV_RDBUF_DUMMY_CYCLELEN_S 16 -#define SPI_SLV_WRSTR_DUMMY_CYCLELEN 0X000000FF -#define SPI_SLV_WRSTR_DUMMY_CYCLELEN_S 8 -#define SPI_SLV_RDSTR_DUMMY_CYCLELEN 0x000000FF -#define SPI_SLV_RDSTR_DUMMY_CYCLELEN_S 0 - -#define SPI_SLAVE3(i) (REG_SPI_BASE(i) + 0x3C) -#define SPI_SLV_WRSTA_CMD_VALUE 0x000000FF -#define SPI_SLV_WRSTA_CMD_VALUE_S 24 -#define SPI_SLV_RDSTA_CMD_VALUE 0x000000FF -#define SPI_SLV_RDSTA_CMD_VALUE_S 16 -#define SPI_SLV_WRBUF_CMD_VALUE 0x000000FF -#define SPI_SLV_WRBUF_CMD_VALUE_S 8 -#define SPI_SLV_RDBUF_CMD_VALUE 0x000000FF -#define SPI_SLV_RDBUF_CMD_VALUE_S 0 - -#define SPI_W0(i) (REG_SPI_BASE(i) +0x40) -#define SPI_W1(i) (REG_SPI_BASE(i) +0x44) -#define SPI_W2(i) (REG_SPI_BASE(i) +0x48) -#define SPI_W3(i) (REG_SPI_BASE(i) +0x4C) -#define SPI_W4(i) (REG_SPI_BASE(i) +0x50) -#define SPI_W5(i) (REG_SPI_BASE(i) +0x54) -#define SPI_W6(i) (REG_SPI_BASE(i) +0x58) -#define SPI_W7(i) (REG_SPI_BASE(i) +0x5C) -#define SPI_W8(i) (REG_SPI_BASE(i) +0x60) -#define SPI_W9(i) (REG_SPI_BASE(i) +0x64) -#define SPI_W10(i) (REG_SPI_BASE(i) +0x68) -#define SPI_W11(i) (REG_SPI_BASE(i) +0x6C) -#define SPI_W12(i) (REG_SPI_BASE(i) +0x70) -#define SPI_W13(i) (REG_SPI_BASE(i) +0x74) -#define SPI_W14(i) (REG_SPI_BASE(i) +0x78) -#define SPI_W15(i) (REG_SPI_BASE(i) +0x7C) - -#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC) -#define SPI_INT_HOLD_ENA 0x00000003 -#define SPI_INT_HOLD_ENA_S 0 -#endif // SPI_REGISTER_H_INCLUDED diff --git a/lib/lib_display/Arduino_ST7789-gemu-1.0/Arduino_ST7789.cpp b/lib/lib_display/Arduino_ST7789-gemu-1.0/Arduino_ST7789.cpp deleted file mode 100644 index b51339b32..000000000 --- a/lib/lib_display/Arduino_ST7789-gemu-1.0/Arduino_ST7789.cpp +++ /dev/null @@ -1,634 +0,0 @@ -/*************************************************** - This is a library for the ST7789 IPS SPI display. - - Originally written by Limor Fried/Ladyada for - Adafruit Industries. - - Modified by Ananev Ilia - ****************************************************/ - -#include "Arduino_ST7789.h" -#include -#include "pins_arduino.h" -#include "wiring_private.h" -#include - -const uint16_t ST7789_colors[]={ST7789_BLACK,ST7789_WHITE,ST7789_RED,ST7789_GREEN,ST7789_BLUE,ST7789_CYAN,ST7789_MAGENTA,\ - ST7789_YELLOW,ST7789_NAVY,ST7789_DARKGREEN,ST7789_DARKCYAN,ST7789_MAROON,ST7789_PURPLE,ST7789_OLIVE,\ -ST7789_LIGHTGREY,ST7789_DARKGREY,ST7789_ORANGE,ST7789_GREENYELLOW,ST7789_PINK}; - -#ifdef ESP32 -#include "esp8266toEsp32.h" -#define ST7789_DIMMER -#endif - - - -uint16_t Arduino_ST7789::GetColorFromIndex(uint8_t index) { - if (index>=sizeof(ST7789_colors)/2) index=0; - return ST7789_colors[index]; -} - -static const uint8_t PROGMEM - init_cmd[] = { // Initialization commands for 7789 screens - 10, // 9 commands in list: - ST7789_SWRESET, ST_CMD_DELAY, // 1: Software reset, no args, w/delay - 150, // 150 ms delay - ST7789_SLPOUT , ST_CMD_DELAY, // 2: Out of sleep mode, no args, w/delay - 255, // 255 = 500 ms delay - ST7789_COLMOD , 1+ST_CMD_DELAY, // 3: Set color mode, 1 arg + delay: - 0x55, // 16-bit color - 10, // 10 ms delay - ST7789_MADCTL , 1, // 4: Memory access ctrl (directions), 1 arg: - 0x00, // Row addr/col addr, bottom to top refresh - ST7789_INVON , ST_CMD_DELAY, // 7: Inversion ON - 10, - ST7789_NORON , ST_CMD_DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7789_DISPON , ST_CMD_DELAY, // 9: Main screen turn on, no args, w/delay - 255 }; // 255 = 500 ms delay - -inline uint16_t swapcolor(uint16_t x) { - return (x << 11) | (x & 0x07E0) | (x >> 11); -} - -#if defined (SPI_HAS_TRANSACTION) - static SPISettings ST7789_SPISettings; -#elif defined (__AVR__) || defined(CORE_TEENSY) - static uint8_t SPCRbackup; - static uint8_t mySPCR; -#endif - - -#if defined (SPI_HAS_TRANSACTION) -#define SPI_BEGIN_TRANSACTION() if (_hwSPI) SPI.beginTransaction(ST7789_SPISettings) -#define SPI_END_TRANSACTION() if (_hwSPI) SPI.endTransaction() -#else -#define SPI_BEGIN_TRANSACTION() (void) -#define SPI_END_TRANSACTION() (void) -#endif - -// Constructor when using software SPI. All output pins are configurable. -Arduino_ST7789::Arduino_ST7789(int8_t dc, int8_t rst, int8_t sid, int8_t sclk, int8_t cs, int8_t bp) - : Renderer(_width, _height) -{ - _cs = cs; - _dc = dc; - _sid = sid; - _sclk = sclk; - _rst = rst; - _hwSPI = false; - _bp = bp; - if(dc == -1) _SPI9bit = true; - else _SPI9bit = false; -} - -// Constructor when using hardware SPI. Faster, but must use SPI pins -// specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.) -Arduino_ST7789::Arduino_ST7789(int8_t dc, int8_t rst, int8_t cs, int8_t bp) - : Renderer(_width, _height) { - _cs = cs; - _dc = dc; - _rst = rst; - _hwSPI = true; - _SPI9bit = false; - _sid = _sclk = -1; - _bp = bp; -} - - -void Arduino_ST7789::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { - setRotation(rot); - if (_width==320 || _height==320) { - invertDisplay(false); - } else { - invertDisplay(true); - } - //setTextWrap(false); // Allow text to run off edges - //cp437(true); - setTextFont(font&3); - setTextSize(size&7); - setTextColor(ST7789_WHITE,ST7789_BLACK); - setCursor(0,0); - fillScreen(ST7789_BLACK); -} - -inline void Arduino_ST7789::spiwrite(uint8_t c) -{ - - //Serial.println(c, HEX); - - if (_hwSPI) - { -#if defined (SPI_HAS_TRANSACTION) - SPI.transfer(c); -#elif defined (__AVR__) || defined(CORE_TEENSY) - SPCRbackup = SPCR; - SPCR = mySPCR; - SPI.transfer(c); - SPCR = SPCRbackup; -#elif defined (__arm__) - SPI.setClockDivider(21); //4MHz - SPI.setDataMode(SPI_MODE2); - SPI.transfer(c); -#endif - } - else - { - if(_SPI9bit) - { - //9s bit send first -#if defined(USE_FAST_IO) - *clkport &= ~clkpinmask; - if(_DCbit) *dataport |= datapinmask; - else *dataport &= ~datapinmask; - *clkport |= clkpinmask; -#else - digitalWrite(_sclk, LOW); - if(_DCbit) digitalWrite(_sid, HIGH); - else digitalWrite(_sid, LOW); - digitalWrite(_sclk, HIGH); -#endif - - - // Fast SPI bitbang swiped from LPD8806 library - for(uint8_t bit = 0x80; bit; bit >>= 1) { -#if defined(USE_FAST_IO) - *clkport &= ~clkpinmask; - if(c & bit) *dataport |= datapinmask; - else *dataport &= ~datapinmask; - *clkport |= clkpinmask; -#else - digitalWrite(_sclk, LOW); - if(c & bit) digitalWrite(_sid, HIGH); - else digitalWrite(_sid, LOW); - digitalWrite(_sclk, HIGH); -#endif - - } - } - else - { - // Fast SPI bitbang swiped from LPD8806 library - for(uint8_t bit = 0x80; bit; bit >>= 1) { -#if defined(USE_FAST_IO) - *clkport &= ~clkpinmask; - if(c & bit) *dataport |= datapinmask; - else *dataport &= ~datapinmask; - *clkport |= clkpinmask; -#else - digitalWrite(_sclk, LOW); - if(c & bit) digitalWrite(_sid, HIGH); - else digitalWrite(_sid, LOW); - digitalWrite(_sclk, HIGH); -#endif - } - } - } -} - -void Arduino_ST7789::writecommand(uint8_t c) { - - DC_LOW(); - CS_LOW(); - SPI_BEGIN_TRANSACTION(); - - spiwrite(c); - - CS_HIGH(); - SPI_END_TRANSACTION(); -} - -void Arduino_ST7789::writedata(uint8_t c) { - SPI_BEGIN_TRANSACTION(); - DC_HIGH(); - CS_LOW(); - - spiwrite(c); - - CS_HIGH(); - SPI_END_TRANSACTION(); -} - - - -// Companion code to the above tables. Reads and issues -// a series of LCD commands stored in PROGMEM byte array. -void Arduino_ST7789::displayInit(const uint8_t *addr) { - - uint8_t numCommands, numArgs; - uint16_t ms; - //<----------------------------------------------------------------------------------------- - DC_HIGH(); - if (!_hwSPI) { -#if defined(USE_FAST_IO) - *clkport |= clkpinmask; -#else - digitalWrite(_sclk, HIGH); -#endif - } - //<----------------------------------------------------------------------------------------- - - numCommands = pgm_read_byte(addr++); // Number of commands to follow - while (numCommands--) { // For each command... - writecommand(pgm_read_byte(addr++)); // Read, issue command - numArgs = pgm_read_byte(addr++); // Number of args to follow - ms = numArgs & ST_CMD_DELAY; // If hibit set, delay follows args - numArgs &= ~ST_CMD_DELAY; // Mask out delay bit - while (numArgs--) { // For each argument... - writedata(pgm_read_byte(addr++)); // Read, issue argument - } - - if (ms) { - ms = pgm_read_byte(addr++); // Read post-command delay time (ms) - if (ms == 255) ms = 500; // If 255, delay for 500 ms - delay(ms); - } - } -} - - -// Initialization code common to all ST7789 displays -void Arduino_ST7789::commonInit(const uint8_t *cmdList) { - _ystart = _xstart = 0; - _colstart = _rowstart = 0; // May be overridden in init func - - pinMode(_dc, OUTPUT); - if (_cs>=0) { - pinMode(_cs, OUTPUT); - } - - if (_bp>=0) { -// #define ESP32_PWM_CHANNEL 1 -#ifdef ST7789_DIMMER - analogWrite(_bp, 128); -#else - pinMode(_bp, OUTPUT); -#endif - - } - - -#if defined(USE_FAST_IO) - dcport = portOutputRegister(digitalPinToPort(_dc)); - dcpinmask = digitalPinToBitMask(_dc); - if (_cs>=0) { - csport = portOutputRegister(digitalPinToPort(_cs)); - cspinmask = digitalPinToBitMask(_cs); - } -#endif - - if(_hwSPI) { // Using hardware SPI -#if defined (SPI_HAS_TRANSACTION) - SPI.begin(); - // ST7789_SPISettings = SPISettings(24000000, MSBFIRST, SPI_MODE2); - ST7789_SPISettings = SPISettings(1000000, MSBFIRST, SPI_MODE2); -#elif defined (__AVR__) || defined(CORE_TEENSY) - SPCRbackup = SPCR; - SPI.begin(); - SPI.setClockDivider(SPI_CLOCK_DIV4); - SPI.setDataMode(SPI_MODE2); - mySPCR = SPCR; // save our preferred state - SPCR = SPCRbackup; // then restore -#elif defined (__SAM3X8E__) - SPI.begin(); - SPI.setClockDivider(21); //4MHz - SPI.setDataMode(SPI_MODE2); -#endif - } else { - pinMode(_sclk, OUTPUT); - pinMode(_sid , OUTPUT); - digitalWrite(_sclk, LOW); - digitalWrite(_sid, LOW); - -#if defined(USE_FAST_IO) - clkport = portOutputRegister(digitalPinToPort(_sclk)); - dataport = portOutputRegister(digitalPinToPort(_sid)); - clkpinmask = digitalPinToBitMask(_sclk); - datapinmask = digitalPinToBitMask(_sid); -#endif - } - - // toggle RST low to reset; CS low so it'll listen to us - CS_LOW(); - if (_rst != -1) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(50); - digitalWrite(_rst, LOW); - delay(50); - digitalWrite(_rst, HIGH); - delay(50); - } - - if (cmdList) - displayInit(cmdList); -} - -void Arduino_ST7789::setRotation(uint8_t m) { - - writecommand(ST7789_MADCTL); - rotation = m % 4; // can't be higher than 3 - switch (rotation) { - case 0: - writedata(ST7789_MADCTL_MX | ST7789_MADCTL_MY | ST7789_MADCTL_RGB); - - _xstart = 0; - _ystart = 0; - if (_width==240 && _height==240) { - _xstart = ST7789_240x240_XSTART_R0; - _ystart = ST7789_240x240_YSTART_R0; - } - if (_width==135 && _height==240) { - _xstart = ST7789_135x240_XSTART_R0; - _ystart = ST7789_135x240_YSTART_R0; - } - break; - case 1: - writedata(ST7789_MADCTL_MY | ST7789_MADCTL_MV | ST7789_MADCTL_RGB); - - _ystart = 0; - _xstart = 0; - if (_width==240 && _height==240) { - _xstart = ST7789_240x240_XSTART_R1; - _ystart = ST7789_240x240_YSTART_R1; - } - if (_width==240 && _height==135) { - _xstart = ST7789_135x240_XSTART_R1; - _ystart = ST7789_135x240_YSTART_R1; - } - break; - case 2: - writedata(ST7789_MADCTL_RGB); - - _xstart = 0; - _ystart = 0; - if (_width==240 && _height==240) { - _xstart = ST7789_240x240_XSTART_R2; - _ystart = ST7789_240x240_YSTART_R2; - } - if (_width==135 && _height==240) { - _xstart = ST7789_135x240_XSTART_R2; - _ystart = ST7789_135x240_YSTART_R2; - } - break; - - case 3: - writedata(ST7789_MADCTL_MX | ST7789_MADCTL_MV | ST7789_MADCTL_RGB); - - _xstart = 0; - _ystart = 0; - if (_width==240 && _height==240) { - _xstart = ST7789_240x240_XSTART_R3; - _ystart = ST7789_240x240_YSTART_R3; - } - if (_width==240 && _height==135) { - _xstart = ST7789_135x240_XSTART_R3; - _ystart = ST7789_135x240_YSTART_R3; - } - break; - } -} - -void Arduino_ST7789::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { - setAddrWindow_int(x0,y0,x1-1,y1-1); -} - -void Arduino_ST7789::setAddrWindow_int(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { - uint16_t x_start = x0 + _xstart, x_end = x1 + _xstart; - uint16_t y_start = y0 + _ystart, y_end = y1 + _ystart; - - writecommand(ST7789_CASET); // Column addr set - writedata(x_start >> 8); - writedata(x_start & 0xFF); // XSTART - writedata(x_end >> 8); - writedata(x_end & 0xFF); // XEND - - writecommand(ST7789_RASET); // Row addr set - writedata(y_start >> 8); - writedata(y_start & 0xFF); // YSTART - writedata(y_end >> 8); - writedata(y_end & 0xFF); // YEND - - writecommand(ST7789_RAMWR); // write to RAM -} - -void Arduino_ST7789::drawPixel(int16_t x, int16_t y, uint16_t color) { - - if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; - - setAddrWindow_int(x,y,x+1,y+1); - - SPI_BEGIN_TRANSACTION(); - DC_HIGH(); - CS_LOW(); - - spiwrite(color >> 8); - spiwrite(color); - - CS_HIGH(); - SPI_END_TRANSACTION(); -} - -void Arduino_ST7789::drawFastVLine(int16_t x, int16_t y, int16_t h, - uint16_t color) { - - // Rudimentary clipping - if((x >= _width) || (y >= _height)) return; - if((y+h-1) >= _height) h = _height-y; - setAddrWindow_int(x, y, x, y+h-1); - - uint8_t hi = color >> 8, lo = color; - - SPI_BEGIN_TRANSACTION(); - DC_HIGH(); - CS_LOW(); - - while (h--) { - spiwrite(hi); - spiwrite(lo); - } - - CS_HIGH(); - SPI_END_TRANSACTION(); -} - -void Arduino_ST7789::drawFastHLine(int16_t x, int16_t y, int16_t w, - uint16_t color) { - - // Rudimentary clipping - if((x >= _width) || (y >= _height)) return; - if((x+w-1) >= _width) w = _width-x; - setAddrWindow_int(x, y, x+w-1, y); - - uint8_t hi = color >> 8, lo = color; - - SPI_BEGIN_TRANSACTION(); - DC_HIGH(); - CS_LOW(); - - while (w--) { - spiwrite(hi); - spiwrite(lo); - } - - CS_HIGH(); - SPI_END_TRANSACTION(); -} - -void Arduino_ST7789::fillScreen(uint16_t color) { - fillRect(0, 0, _width, _height, color); -} - -// fill a rectangle -void Arduino_ST7789::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color) { - - // rudimentary clipping (drawChar w/big text requires this) - if((x >= _width) || (y >= _height)) return; - if((x + w - 1) >= _width) w = _width - x; - if((y + h - 1) >= _height) h = _height - y; - - setAddrWindow_int(x, y, x+w-1, y+h-1); - - uint8_t hi = color >> 8, lo = color; - - SPI_BEGIN_TRANSACTION(); - - DC_HIGH(); - CS_LOW(); - for(y=h; y>0; y--) { - for(x=w; x>0; x--) { - spiwrite(hi); - spiwrite(lo); - } - delay(0); - } - CS_HIGH(); - SPI_END_TRANSACTION(); -} - -// Pass 8-bit (each) R,G,B, get back 16-bit packed color -uint16_t Arduino_ST7789::Color565(uint8_t r, uint8_t g, uint8_t b) { - return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); -} - -void Arduino_ST7789::invertDisplay(boolean i) { - writecommand(i ? ST7789_INVON : ST7789_INVOFF); -} - -/******** low level bit twiddling **********/ - -inline void Arduino_ST7789::CS_HIGH(void) { - if(_cs>=0) { - #if defined(USE_FAST_IO) - *csport |= cspinmask; - #else - digitalWrite(_cs, HIGH); - #endif - } -} - -inline void Arduino_ST7789::CS_LOW(void) { - if(_cs>=0) { - #if defined(USE_FAST_IO) - *csport &= ~cspinmask; - #else - digitalWrite(_cs, LOW); - #endif - } -} - -inline void Arduino_ST7789::DC_HIGH(void) { - _DCbit = true; -#if defined(USE_FAST_IO) - *dcport |= dcpinmask; -#else - digitalWrite(_dc, HIGH); -#endif -} - -inline void Arduino_ST7789::DC_LOW(void) { - _DCbit = false; -#if defined(USE_FAST_IO) - *dcport &= ~dcpinmask; -#else - digitalWrite(_dc, LOW); -#endif -} - -void Arduino_ST7789::init(uint16_t width, uint16_t height) { - commonInit(NULL); - - _height = height; - _width = width; - - displayInit(init_cmd); - - setRotation(2); - -} - -void Arduino_ST7789::DisplayOnff(int8_t on) { - if (on) { - writecommand(ST7789_DISPON); //Display on - if (_bp>=0) { -#ifdef ST7789_DIMMER - analogWrite(_bp, dimmer); - // ledcWrite(ESP32_PWM_CHANNEL,dimmer); -#else - digitalWrite(_bp,HIGH); -#endif - } - } else { - writecommand(ST7789_DISPOFF); - if (_bp>=0) { -#ifdef ST7789_DIMMER - analogWrite(_bp, 0); - // ledcWrite(ESP32_PWM_CHANNEL,0); -#else - digitalWrite(_bp,LOW); -#endif - } - } -} - -// dimmer 0-100 -void Arduino_ST7789::dim(uint8_t dim) { - dimmer = dim; - if (dimmer>15) dimmer=15; - dimmer=((float)dimmer/15.0)*255.0; -#ifdef ESP32 - analogWrite(_bp, dimmer); - // ledcWrite(ESP32_PWM_CHANNEL,dimmer); -#endif -} - -void Arduino_ST7789::pushColor(uint16_t color) { - SPI_BEGIN_TRANSACTION(); - DC_HIGH(); - CS_LOW(); - - spiwrite(color >> 8); - spiwrite(color); - - CS_HIGH(); - SPI_END_TRANSACTION(); -} - -void Arduino_ST7789::pushColors(uint16_t *data, uint16_t len, boolean first) { - uint16_t color; - - SPI_BEGIN_TRANSACTION(); - DC_HIGH(); - CS_LOW(); - - while (len--) { - color = *data++; - spiwrite(color >> 8); - spiwrite(color); - } - - CS_HIGH(); - SPI_END_TRANSACTION(); -} diff --git a/lib/lib_display/Arduino_ST7789-gemu-1.0/Arduino_ST7789.h b/lib/lib_display/Arduino_ST7789-gemu-1.0/Arduino_ST7789.h deleted file mode 100644 index ebd39dc25..000000000 --- a/lib/lib_display/Arduino_ST7789-gemu-1.0/Arduino_ST7789.h +++ /dev/null @@ -1,195 +0,0 @@ -/*************************************************** - This is a library for the ST7789 IPS SPI display. - - Originally written by Limor Fried/Ladyada for - Adafruit Industries. - - Modified by Ananev Ilia - ****************************************************/ - -#ifndef _ADAFRUIT_ST7789H_ -#define _ADAFRUIT_ST7789H_ - -#include "Arduino.h" -#include "Print.h" -#include -#include - -#ifdef ESP8266 -#define USE_FAST_IO -#endif - -#if defined(__AVR__) || defined(CORE_TEENSY) - #include - #define USE_FAST_IO - typedef volatile uint8_t RwReg; -#elif defined(ARDUINO_STM32_FEATHER) - typedef volatile uint32 RwReg; - #define USE_FAST_IO -#elif defined(ARDUINO_FEATHER52) - typedef volatile uint32_t RwReg; - #define USE_FAST_IO -#elif defined(ESP8266) - #include -#elif defined(__SAM3X8E__) - #undef __FlashStringHelper::F(string_literal) - #define F(string_literal) string_literal - #include - #define PROGMEM - #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) - #define pgm_read_word(addr) (*(const unsigned short *)(addr)) - typedef unsigned char prog_uchar; -#endif - -//#define SPI_HAS_TRANSACTION // already defined in SPI.h - -#define ST7789_240x240_XSTART_R0 0 -#define ST7789_240x240_YSTART_R0 80 -#define ST7789_240x240_XSTART_R1 80 -#define ST7789_240x240_YSTART_R1 0 -#define ST7789_240x240_XSTART_R2 0 -#define ST7789_240x240_YSTART_R2 0 -#define ST7789_240x240_XSTART_R3 0 -#define ST7789_240x240_YSTART_R3 0 - -#define ST7789_135x240_XSTART_R0 53 -#define ST7789_135x240_YSTART_R0 40 -#define ST7789_135x240_XSTART_R1 40 -#define ST7789_135x240_YSTART_R1 52 -#define ST7789_135x240_XSTART_R2 52 -#define ST7789_135x240_YSTART_R2 40 -#define ST7789_135x240_XSTART_R3 40 -#define ST7789_135x240_YSTART_R3 53 - -#define ST_CMD_DELAY 0x80 // special signifier for command lists - -#define ST7789_NOP 0x00 -#define ST7789_SWRESET 0x01 -#define ST7789_RDDID 0x04 -#define ST7789_RDDST 0x09 - -#define ST7789_SLPIN 0x10 -#define ST7789_SLPOUT 0x11 -#define ST7789_PTLON 0x12 -#define ST7789_NORON 0x13 - -#define ST7789_INVOFF 0x20 -#define ST7789_INVON 0x21 -#define ST7789_DISPOFF 0x28 -#define ST7789_DISPON 0x29 -#define ST7789_CASET 0x2A -#define ST7789_RASET 0x2B -#define ST7789_RAMWR 0x2C -#define ST7789_RAMRD 0x2E - -#define ST7789_PTLAR 0x30 -#define ST7789_COLMOD 0x3A -#define ST7789_MADCTL 0x36 - -#define ST7789_MADCTL_MY 0x80 -#define ST7789_MADCTL_MX 0x40 -#define ST7789_MADCTL_MV 0x20 -#define ST7789_MADCTL_ML 0x10 -#define ST7789_MADCTL_RGB 0x00 - -#define ST7789_RDID1 0xDA -#define ST7789_RDID2 0xDB -#define ST7789_RDID3 0xDC -#define ST7789_RDID4 0xDD - -// Color definitions -#undef BLACK -#define BLACK 0x0000 -#define BLUE 0x001F -#define RED 0xF800 -#define GREEN 0x07E0 -#define CYAN 0x07FF -#define MAGENTA 0xF81F -#define YELLOW 0xFFE0 -#undef WHITE -#define WHITE 0xFFFF - - -// Color definitions -#define ST7789_BLACK 0x0000 /* 0, 0, 0 */ -#define ST7789_NAVY 0x000F /* 0, 0, 128 */ -#define ST7789_DARKGREEN 0x03E0 /* 0, 128, 0 */ -#define ST7789_DARKCYAN 0x03EF /* 0, 128, 128 */ -#define ST7789_MAROON 0x7800 /* 128, 0, 0 */ -#define ST7789_PURPLE 0x780F /* 128, 0, 128 */ -#define ST7789_OLIVE 0x7BE0 /* 128, 128, 0 */ -#define ST7789_LIGHTGREY 0xC618 /* 192, 192, 192 */ -#define ST7789_DARKGREY 0x7BEF /* 128, 128, 128 */ -#define ST7789_BLUE 0x001F /* 0, 0, 255 */ -#define ST7789_GREEN 0x07E0 /* 0, 255, 0 */ -#define ST7789_CYAN 0x07FF /* 0, 255, 255 */ -#define ST7789_RED 0xF800 /* 255, 0, 0 */ -#define ST7789_MAGENTA 0xF81F /* 255, 0, 255 */ -#define ST7789_YELLOW 0xFFE0 /* 255, 255, 0 */ -#define ST7789_WHITE 0xFFFF /* 255, 255, 255 */ -#define ST7789_ORANGE 0xFD20 /* 255, 165, 0 */ -#define ST7789_GREENYELLOW 0xAFE5 /* 173, 255, 47 */ -#define ST7789_PINK 0xF81F - - -class Arduino_ST7789 : public Renderer { - - public: - - Arduino_ST7789(int8_t DC, int8_t RST, int8_t SID, int8_t SCLK, int8_t CS, int8_t bp); - Arduino_ST7789(int8_t DC, int8_t RST, int8_t CS, int8_t bp); - - void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1), - pushColor(uint16_t color), - fillScreen(uint16_t color), - drawPixel(int16_t x, int16_t y, uint16_t color), - drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), - drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), - fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color), - setRotation(uint8_t r), - invertDisplay(boolean i), - DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font), - setAddrWindow_int(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1), - init(uint16_t width, uint16_t height); - uint16_t Color565(uint8_t r, uint8_t g, uint8_t b); - uint16_t GetColorFromIndex(uint8_t index); - uint16_t color565(uint8_t r, uint8_t g, uint8_t b) { return Color565(r, g, b); } - void DisplayOnff(int8_t on); - void dim(uint8_t contrast); - void pushColors(uint16_t *data, uint16_t len, boolean first); - - protected: - uint8_t _colstart, _rowstart, _xstart, _ystart; // some displays need this changed - - void displayInit(const uint8_t *addr); - void spiwrite(uint8_t), - writecommand(uint8_t c), - writedata(uint8_t d), - commonInit(const uint8_t *cmdList); - - private: - - inline void CS_HIGH(void); - inline void CS_LOW(void); - inline void DC_HIGH(void); - inline void DC_LOW(void); - - boolean _hwSPI; - boolean _SPI9bit; - boolean _DCbit; - uint8_t dimmer; - int8_t _cs, _dc, _rst, _sid, _sclk, _bp; - -#if defined(USE_FAST_IO) - volatile uint32_t *dataport, *clkport, *csport, *dcport; - - #if defined(__AVR__) || defined(CORE_TEENSY) // 8 bit! - uint8_t datapinmask, clkpinmask, cspinmask, dcpinmask; - #else // 32 bit! - uint32_t datapinmask, clkpinmask, cspinmask, dcpinmask; - #endif -#endif - -}; - -#endif diff --git a/lib/lib_display/Arduino_ST7789-gemu-1.0/README.txt b/lib/lib_display/Arduino_ST7789-gemu-1.0/README.txt deleted file mode 100644 index 8aad7c0e9..000000000 --- a/lib/lib_display/Arduino_ST7789-gemu-1.0/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -This is a library for the ST7789 IPS SPI display. - -Also requires the Adafruit_GFX library for Arduino. diff --git a/lib/lib_display/Arduino_ST7789-gemu-1.0/examples/graphicstest/graphicstest.ino b/lib/lib_display/Arduino_ST7789-gemu-1.0/examples/graphicstest/graphicstest.ino deleted file mode 100644 index baed077ab..000000000 --- a/lib/lib_display/Arduino_ST7789-gemu-1.0/examples/graphicstest/graphicstest.ino +++ /dev/null @@ -1,278 +0,0 @@ -/*************************************************** - This is a library for the ST7789 IPS SPI display. - - Originally written by Limor Fried/Ladyada for - Adafruit Industries. - - Modified by Ananev Ilia - ****************************************************/ - -#include // Core graphics library by Adafruit -#include // Hardware-specific library for ST7789 (with or without CS pin) -#include - -#define TFT_DC 8 -#define TFT_RST 9 -#define TFT_CS 10 // only for displays with CS pin -#define TFT_MOSI 11 // for hardware SPI data pin (all of available pins) -#define TFT_SCLK 13 // for hardware SPI sclk pin (all of available pins) - -//You can use different type of hardware initialization -//using hardware SPI (11, 13 on UNO; 51, 52 on MEGA; ICSP-4, ICSP-3 on DUE and etc) -//Arduino_ST7789 tft = Arduino_ST7789(TFT_DC, TFT_RST); //for display without CS pin -//Arduino_ST7789 tft = Arduino_ST7789(TFT_DC, TFT_RST, TFT_CS); //for display with CS pin -//or you can use software SPI on all available pins (slow) -//Arduino_ST7789 tft = Arduino_ST7789(TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK); //for display without CS pin -//Arduino_ST7789 tft = Arduino_ST7789(TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_CS); //for display with CS pin -Arduino_ST7789 tft = Arduino_ST7789(-1, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_CS); //for display with CS pin and DC via 9bit SPI - - -float p = 3.1415926; - -void setup(void) { - Serial.begin(9600); - Serial.print("Hello! ST7789 TFT Test"); - - tft.init(240, 240); // initialize a ST7789 chip, 240x240 pixels - - Serial.println("Initialized"); - - uint16_t time = millis(); - tft.fillScreen(BLACK); - time = millis() - time; - - Serial.println(time, DEC); - delay(500); - - // large block of text - tft.fillScreen(BLACK); - testdrawtext("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a tortor imperdiet posuere. ", WHITE); - delay(1000); - - // tft print function - tftPrintTest(); - delay(4000); - - // a single pixel - tft.drawPixel(tft.width()/2, tft.height()/2, GREEN); - delay(500); - - // line draw test - testlines(YELLOW); - delay(500); - - // optimized lines - testfastlines(RED, BLUE); - delay(500); - - testdrawrects(GREEN); - delay(500); - - testfillrects(YELLOW, MAGENTA); - delay(500); - - tft.fillScreen(BLACK); - testfillcircles(10, BLUE); - testdrawcircles(10, WHITE); - delay(500); - - testroundrects(); - delay(500); - - testtriangles(); - delay(500); - - mediabuttons(); - delay(500); - - Serial.println("done"); - delay(1000); -} - -void loop() { - tft.invertDisplay(true); - delay(500); - tft.invertDisplay(false); - delay(500); -} - -void testlines(uint16_t color) { - tft.fillScreen(BLACK); - for (int16_t x=0; x < tft.width(); x+=6) { - tft.drawLine(0, 0, x, tft.height()-1, color); - } - for (int16_t y=0; y < tft.height(); y+=6) { - tft.drawLine(0, 0, tft.width()-1, y, color); - } - - tft.fillScreen(BLACK); - for (int16_t x=0; x < tft.width(); x+=6) { - tft.drawLine(tft.width()-1, 0, x, tft.height()-1, color); - } - for (int16_t y=0; y < tft.height(); y+=6) { - tft.drawLine(tft.width()-1, 0, 0, y, color); - } - - tft.fillScreen(BLACK); - for (int16_t x=0; x < tft.width(); x+=6) { - tft.drawLine(0, tft.height()-1, x, 0, color); - } - for (int16_t y=0; y < tft.height(); y+=6) { - tft.drawLine(0, tft.height()-1, tft.width()-1, y, color); - } - - tft.fillScreen(BLACK); - for (int16_t x=0; x < tft.width(); x+=6) { - tft.drawLine(tft.width()-1, tft.height()-1, x, 0, color); - } - for (int16_t y=0; y < tft.height(); y+=6) { - tft.drawLine(tft.width()-1, tft.height()-1, 0, y, color); - } -} - -void testdrawtext(char *text, uint16_t color) { - tft.setCursor(0, 0); - tft.setTextColor(color); - tft.setTextWrap(true); - tft.print(text); -} - -void testfastlines(uint16_t color1, uint16_t color2) { - tft.fillScreen(BLACK); - for (int16_t y=0; y < tft.height(); y+=5) { - tft.drawFastHLine(0, y, tft.width(), color1); - } - for (int16_t x=0; x < tft.width(); x+=5) { - tft.drawFastVLine(x, 0, tft.height(), color2); - } -} - -void testdrawrects(uint16_t color) { - tft.fillScreen(BLACK); - for (int16_t x=0; x < tft.width(); x+=6) { - tft.drawRect(tft.width()/2 -x/2, tft.height()/2 -x/2 , x, x, color); - } -} - -void testfillrects(uint16_t color1, uint16_t color2) { - tft.fillScreen(BLACK); - for (int16_t x=tft.width()-1; x > 6; x-=6) { - tft.fillRect(tft.width()/2 -x/2, tft.height()/2 -x/2 , x, x, color1); - tft.drawRect(tft.width()/2 -x/2, tft.height()/2 -x/2 , x, x, color2); - } -} - -void testfillcircles(uint8_t radius, uint16_t color) { - for (int16_t x=radius; x < tft.width(); x+=radius*2) { - for (int16_t y=radius; y < tft.height(); y+=radius*2) { - tft.fillCircle(x, y, radius, color); - } - } -} - -void testdrawcircles(uint8_t radius, uint16_t color) { - for (int16_t x=0; x < tft.width()+radius; x+=radius*2) { - for (int16_t y=0; y < tft.height()+radius; y+=radius*2) { - tft.drawCircle(x, y, radius, color); - } - } -} - -void testtriangles() { - tft.fillScreen(BLACK); - int color = 0xF800; - int t; - int w = tft.width()/2; - int x = tft.height()-1; - int y = 0; - int z = tft.width(); - for(t = 0 ; t <= 15; t++) { - tft.drawTriangle(w, y, y, x, z, x, color); - x-=4; - y+=4; - z-=4; - color+=100; - } -} - -void testroundrects() { - tft.fillScreen(BLACK); - int color = 100; - int i; - int t; - for(t = 0 ; t <= 4; t+=1) { - int x = 0; - int y = 0; - int w = tft.width()-2; - int h = tft.height()-2; - for(i = 0 ; i <= 16; i+=1) { - tft.drawRoundRect(x, y, w, h, 5, color); - x+=2; - y+=3; - w-=4; - h-=6; - color+=1100; - } - color+=100; - } -} - -void tftPrintTest() { - tft.setTextWrap(false); - tft.fillScreen(BLACK); - tft.setCursor(0, 30); - tft.setTextColor(RED); - tft.setTextSize(1); - tft.println("Hello World!"); - tft.setTextColor(YELLOW); - tft.setTextSize(2); - tft.println("Hello World!"); - tft.setTextColor(GREEN); - tft.setTextSize(3); - tft.println("Hello World!"); - tft.setTextColor(BLUE); - tft.setTextSize(4); - tft.print(1234.567); - delay(1500); - tft.setCursor(0, 0); - tft.fillScreen(BLACK); - tft.setTextColor(WHITE); - tft.setTextSize(0); - tft.println("Hello World!"); - tft.setTextSize(1); - tft.setTextColor(GREEN); - tft.print(p, 6); - tft.println(" Want pi?"); - tft.println(" "); - tft.print(8675309, HEX); // print 8,675,309 out in HEX! - tft.println(" Print HEX!"); - tft.println(" "); - tft.setTextColor(WHITE); - tft.println("Sketch has been"); - tft.println("running for: "); - tft.setTextColor(MAGENTA); - tft.print(millis() / 1000); - tft.setTextColor(WHITE); - tft.print(" seconds."); -} - -void mediabuttons() { - // play - tft.fillScreen(BLACK); - tft.fillRoundRect(25, 10, 78, 60, 8, WHITE); - tft.fillTriangle(42, 20, 42, 60, 90, 40, RED); - delay(500); - // pause - tft.fillRoundRect(25, 90, 78, 60, 8, WHITE); - tft.fillRoundRect(39, 98, 20, 45, 5, GREEN); - tft.fillRoundRect(69, 98, 20, 45, 5, GREEN); - delay(500); - // play color - tft.fillTriangle(42, 20, 42, 60, 90, 40, BLUE); - delay(50); - // pause color - tft.fillRoundRect(39, 98, 20, 45, 5, RED); - tft.fillRoundRect(69, 98, 20, 45, 5, RED); - // play color - tft.fillTriangle(42, 20, 42, 60, 90, 40, GREEN); -} diff --git a/lib/lib_display/Arduino_ST7789-gemu-1.0/keywords.txt b/lib/lib_display/Arduino_ST7789-gemu-1.0/keywords.txt deleted file mode 100644 index bb1efcdcc..000000000 --- a/lib/lib_display/Arduino_ST7789-gemu-1.0/keywords.txt +++ /dev/null @@ -1,30 +0,0 @@ -####################################### -# Syntax Coloring Map -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -ST7789 KEYWORD1 - - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - -setRotation KEYWORD2 -setAddrWindow KEYWORD2 -pushColor KEYWORD2 -drawPixel KEYWORD2 -drawFastVLine KEYWORD2 -drawFastHLine KEYWORD2 -fillRect KEYWORD2 -setRotation KEYWORD2 -setRotation KEYWORD2 -height KEYWORD2 -width KEYWORD2 -invertDisplay KEYWORD2 -drawImage KEYWORD2 -setScrollArea KEYWORD2 -scroll KEYWORD2 diff --git a/lib/lib_display/Arduino_ST7789-gemu-1.0/library.properties b/lib/lib_display/Arduino_ST7789-gemu-1.0/library.properties deleted file mode 100644 index 2511928c9..000000000 --- a/lib/lib_display/Arduino_ST7789-gemu-1.0/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=Arduino ST7789 Library -version=0.9.5 -author=Ananev Ilya -maintainer=Ananev Ilya -sentence=This is a library for the ST7789 IPS SPI display. -paragraph=This is a library for the ST7789 IPS SPI display. -category=Display -url=https://github.com/ananevilya/Arduino-ST7789-Library -architectures=* diff --git a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h index 7ef7d86ab..3abe7800b 100644 --- a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h +++ b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h @@ -28,7 +28,7 @@ // b. textcolor,textbgcolor => public; typedef struct LVGL_PARAMS { - uint16_t fluslines; + uint16_t flushlines; union { uint8_t data; struct { diff --git a/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.cpp b/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.cpp deleted file mode 100644 index 2da8d4091..000000000 --- a/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.cpp +++ /dev/null @@ -1,678 +0,0 @@ -/*! -* @file ILI9341_2.cpp -* -* @mainpage Adafruit ILI9341 TFT Displays -* -* @section intro_sec Introduction -* -* This is the documentation for Adafruit's ILI9341 driver for the -* Arduino platform. -* -* This library works with the Adafruit 2.8" Touch Shield V2 (SPI) -* http://www.adafruit.com/products/1651 -* -* Adafruit 2.4" TFT LCD with Touchscreen Breakout w/MicroSD Socket - ILI9341 -* https://www.adafruit.com/product/2478 -* -* 2.8" TFT LCD with Touchscreen Breakout Board w/MicroSD Socket - ILI9341 -* https://www.adafruit.com/product/1770 -* -* 2.2" 18-bit color TFT LCD display with microSD card breakout - ILI9340 -* https://www.adafruit.com/product/1770 -* -* TFT FeatherWing - 2.4" 320x240 Touchscreen For All Feathers -* https://www.adafruit.com/product/3315 -* -* These displays use SPI to communicate, 4 or 5 pins are required -* to interface (RST is optional). -* -* Adafruit invests time and resources providing this open source code, -* please support Adafruit and open-source hardware by purchasing -* products from Adafruit! -* -* @section dependencies Dependencies -* -* This library depends on -* Adafruit_GFX being present on your system. Please make sure you have -* installed the latest version before using this library. -* -* @section author Author -* -* Written by Limor "ladyada" Fried for Adafruit Industries. -* -* @section license License -* -* BSD license, all text here must be included in any redistribution. -* -*/ - -//#ifdef ESP32 -#include "ILI9341_2.h" -#include - - -// ESP32 uses 2. SPI BUS, ESP8266 uses software spi -#ifdef ESP32 -#include "esp8266toEsp32.h" -#undef ILI9341_2_DIMMER -#define ILI9341_2_DIMMER -#undef ESP32_PWM_CHANNEL -#define ESP32_PWM_CHANNEL 1 -#endif - -#define ILI9341_2_HWSPI - -#if defined (ILI9341_2_HWSPI) -#define SPI_BEGIN_TRANSACTION() if (_hwspi) spi2->beginTransaction(sspi2) -#define SPI_END_TRANSACTION() if (_hwspi) spi2->endTransaction() -#else -#define SPI_BEGIN_TRANSACTION() -#define SPI_END_TRANSACTION() -#endif - - - -const uint16_t ili9341_2_colors[]={ILI9341_BLACK,ILI9341_WHITE,ILI9341_RED,ILI9341_GREEN,ILI9341_BLUE,ILI9341_CYAN,ILI9341_MAGENTA,\ - ILI9341_YELLOW,ILI9341_NAVY,ILI9341_DARKGREEN,ILI9341_DARKCYAN,ILI9341_MAROON,ILI9341_PURPLE,ILI9341_OLIVE,\ -ILI9341_LIGHTGREY,ILI9341_DARKGREY,ILI9341_ORANGE,ILI9341_GREENYELLOW,ILI9341_PINK}; - -uint16_t ILI9341_2::GetColorFromIndex(uint8_t index) { - if (index >= sizeof(ili9341_2_colors) / 2) index = 0; - return ili9341_2_colors[index]; -} - -static const uint8_t PROGMEM ili9341_2_initcmd[] = { - 0xEF, 3, 0x03, 0x80, 0x02, - 0xCF, 3, 0x00, 0xC1, 0x30, - 0xED, 4, 0x64, 0x03, 0x12, 0x81, - 0xE8, 3, 0x85, 0x00, 0x78, - 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, - 0xF7, 1, 0x20, - 0xEA, 2, 0x00, 0x00, - ILI9341_2_PWCTR1 , 1, 0x23, // Power control VRH[5:0] - ILI9341_2_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0] - ILI9341_2_VMCTR1 , 2, 0x3e, 0x28, // VCM control - ILI9341_2_VMCTR2 , 1, 0x86, // VCM control2 - ILI9341_2_MADCTL , 1, 0x48, // Memory Access Control - ILI9341_2_VSCRSADD, 1, 0x00, // Vertical scroll zero - ILI9341_2_PIXFMT , 1, 0x55, - ILI9341_2_FRMCTR1 , 2, 0x00, 0x18, - ILI9341_2_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control - 0xF2, 1, 0x00, // 3Gamma Function Disable - ILI9341_2_GAMMASET , 1, 0x01, // Gamma curve selected - ILI9341_2_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma - 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, - ILI9341_2_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma - 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, - ILI9341_2_SLPOUT , 0x80, // Exit Sleep - ILI9341_2_DISPON , 0x80, // Display on -// ILI9341_2_DISPOFF , 0x80, // Display on - 0x00 // End of list -}; - -static const uint8_t PROGMEM ili9342_initcmd[] = { - 0xEF, 3, 0x03, 0x80, 0x02, - 0xCF, 3, 0x00, 0xC1, 0x30, - 0xED, 4, 0x64, 0x03, 0x12, 0x81, - 0xE8, 3, 0x85, 0x00, 0x78, - 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, - 0xF7, 1, 0x20, - 0xEA, 2, 0x00, 0x00, - ILI9341_2_PWCTR1 , 1, 0x23, // Power control VRH[5:0] - ILI9341_2_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0] - ILI9341_2_VMCTR1 , 2, 0x2B, 0x2B, // 0x3e, 0x28, // VCM control - ILI9341_2_VMCTR2 , 1, 0xC0, // VCM control2 - ILI9341_2_MADCTL , 1, 0x48, // Memory Access Control - ILI9341_2_VSCRSADD, 1, 0x00, // Vertical scroll zero - ILI9341_2_PIXFMT , 1, 0x55, - ILI9341_2_FRMCTR1 , 2, 0x00, 0x1B, - ILI9341_2_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control - 0xF2, 1, 0x00, // 3Gamma Function Disable - ILI9341_2_GAMMASET , 1, 0x01, // Gamma curve selected - ILI9341_2_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, - ILI9341_2_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, - ILI9341_2_INVON , 0x80, - ILI9341_2_SLPOUT , 0x80, // Exit Sleep - ILI9341_2_DISPON , 0x80, // Display on - 0x00 // End of list -}; - -ILI9341_2::ILI9341_2(int8_t cs, int8_t mosi, int8_t miso, int8_t sclk, int8_t res, int8_t dc, int8_t bp, int8_t spibus, uint8_t dtype) : Renderer(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) { - _cs = cs; - _mosi = mosi; - _miso = miso; - _sclk = sclk; - _res = res; - _dc = dc; - _bp = bp; - _hwspi = dtype; // sign ili9341 or 2 - _spibus = spibus; -} - -// special init for ILI9342 uses SPI1 previously defined with SDCard -ILI9341_2::ILI9341_2(int8_t cs, int8_t res, int8_t dc, int8_t bp) : Renderer(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) { - _cs = cs; - _res = res; - _dc = dc; - _bp = bp; - _hwspi = 2; // sign ili9342 - _spibus = 1; -} - -#define ILI9341_2_CS_LOW if (_cs>=0) digitalWrite( _cs, LOW); -#define ILI9341_2_CS_HIGH if (_cs>=0) digitalWrite( _cs, HIGH); - - -void ILI9341_2::writecmd(uint8_t d) { - digitalWrite( _dc, LOW); -#ifdef ILI9341_2_HWSPI - spi2->write(d); -#else - spiwrite(d); -#endif - digitalWrite( _dc, HIGH); -} - -void ILI9341_2::init(uint16_t width, uint16_t height) { - //sspi2 = SPISettings(2500000, MSBFIRST, SPI_MODE3); - - if (_hwspi >= 2) { - iwidth = ILI9341_TFTWIDTH; - iheight = ILI9341_TFTHEIGHT; - } else { - iwidth = ILI9341_TFTHEIGHT; - iheight = ILI9341_TFTWIDTH; - } - -#ifdef ILI9341_2_HWSPI - - sspi2 = SPISettings(40000000, MSBFIRST, SPI_MODE0); - - if (_hwspi >= 2) { - spi2 = &SPI; -#ifdef ESP32 - if (_hwspi > 2) { - spi2->begin(_sclk, _miso, _mosi, -1); - } -#else - SPI.begin(); -#endif // ESP32 - } else { -#ifdef ESP32 - if (_spibus == 2) { - spi2 = new SPIClass(HSPI); - } else { - spi2 = &SPI; - } - spi2->begin(_sclk, _miso, _mosi, -1); -#else - SPI.begin(); - spi2 = &SPI; -#endif - } - -#else - pinMode(_mosi, OUTPUT); - digitalWrite(_mosi,HIGH); - pinMode(_sclk, OUTPUT); - digitalWrite(_sclk,LOW); - pinMode(_miso, INPUT); -#endif - - pinMode(_cs, OUTPUT); - digitalWrite(_cs,HIGH); - - pinMode(_dc, OUTPUT); - digitalWrite(_dc,HIGH); - - if (_bp >= 0) { - pinMode(_bp, OUTPUT); - digitalWrite(_bp,HIGH); - } - - if (_res >= 0) { - pinMode(_res, OUTPUT); - digitalWrite(_res, HIGH); - delay(100); - digitalWrite(_res, LOW); - delay(100); - digitalWrite(_res, HIGH); - delay(200); - } else { - SPI_BEGIN_TRANSACTION(); - ILI9341_2_CS_LOW - writecmd(ILI9341_2_SWRESET); // software reset - ILI9341_2_CS_HIGH - SPI_END_TRANSACTION(); - delay(150); - } - - if (_bp >= 0) { -#ifdef ILI9341_2_DIMMER - analogWrite(_bp, 511); -#else - pinMode(_bp, OUTPUT); -#endif - } - - uint8_t cmd, x, numArgs; - const uint8_t *addr; - - if (_hwspi<2) { - addr = ili9341_2_initcmd; - } else { - addr = ili9342_initcmd; - } - - SPI_BEGIN_TRANSACTION(); - - while ((cmd = pgm_read_byte(addr++)) > 0) { - ILI9341_2_CS_LOW - writecmd(cmd); - x = pgm_read_byte(addr++); - numArgs = x & 0x7F; - -#ifdef ILI9341_2_HWSPI - while (numArgs--) spi2->write(pgm_read_byte(addr++)); -#else - while (numArgs--) spiwrite(pgm_read_byte(addr++)); -#endif - - ILI9341_2_CS_HIGH - if (x & 0x80) delay(120); - } - SPI_END_TRANSACTION(); -} - -void ILI9341_2::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { -// SPI_BEGIN_TRANSACTION(); -// writecmd(ILI9341_2_INVOFF); -// SPI_END_TRANSACTION(); - setRotation(rot); - setTextFont(font&3); - setTextSize(size&7); - setTextColor(ILI9341_WHITE,ILI9341_BLACK); - setCursor(0,0); - fillScreen(ILI9341_BLACK); -} - -void ILI9341_2::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { - - if (!x0 && !y0 && !x1 && !y1) { - ILI9341_2_CS_HIGH - SPI_END_TRANSACTION(); - } else { - ILI9341_2_CS_LOW - SPI_BEGIN_TRANSACTION(); - setAddrWindow_int(x0,y0,x1-x0,y1-y0); - } -} - -void ILI9341_2::pushColors(uint16_t *data, uint16_t len, boolean first) { - uint16_t color; - - while (len--) { - color = *data++; -#ifdef ILI9341_2_HWSPI - spi2->write16(color); -#else - spiwrite16(color); -#endif - } - -} - -void ILI9341_2::setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { - uint32_t xa = ((uint32_t)x << 16) | (x+w-1); - uint32_t ya = ((uint32_t)y << 16) | (y+h-1); - - - writecmd(ILI9341_2_CASET); // Column addr set -#ifdef ILI9341_2_HWSPI - spi2->write32(xa); -#else - spiwrite32(xa); -#endif - writecmd(ILI9341_2_PASET); // Row addr set - -#ifdef ILI9341_2_HWSPI - spi2->write32(ya); -#else - spiwrite32(ya); -#endif - writecmd(ILI9341_2_RAMWR); // write to RAM - - -} - -void ILI9341_2::drawPixel(int16_t x, int16_t y, uint16_t color) { - - if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; - - SPI_BEGIN_TRANSACTION(); - - ILI9341_2_CS_LOW - - setAddrWindow_int(x,y,1,1); - -#ifdef ILI9341_2_HWSPI - spi2->write16(color); -#else - spiwrite16(color); -#endif - - ILI9341_2_CS_HIGH - - SPI_END_TRANSACTION(); -} - - -void ILI9341_2::setRotation(uint8_t m) { - - if (_hwspi < 2) { - rotation = m % 4; // can't be higher than 3 - switch (rotation) { - case 0: - m = (MADCTL_2_MX | MADCTL_2_BGR); - _width = iwidth; - _height = iheight; - break; - case 1: - m = (MADCTL_2_MV | MADCTL_2_BGR); - _width = iheight; - _height = iwidth; - break; - case 2: - m = (MADCTL_2_MY | MADCTL_2_BGR); - _width = iwidth; - _height = iheight; - break; - case 3: - m = (MADCTL_2_MX | MADCTL_2_MY | MADCTL_2_MV | MADCTL_2_BGR); - _width = iheight; - _height = iwidth; - break; - } - -} else { - -#define MADCTL_MY 0x80 ///< Bottom to top -#define MADCTL_MX 0x40 ///< Right to left -#define MADCTL_MV 0x20 ///< Reverse Mode -#define MADCTL_ML 0x10 ///< LCD refresh Bottom to top -#define MADCTL_RGB 0x00 ///< Red-Green-Blue pixel order -#define MADCTL_BGR 0x08 ///< Blue-Green-Red pixel order -#define MADCTL_MH 0x04 ///< LCD refresh right to left - - rotation = m % 4; // can't be higher than 3 - switch (rotation) { - case 0: - m = (MADCTL_BGR); - _width = iwidth; - _height = iheight; - break; - case 1: - m = (MADCTL_MY | MADCTL_MV | MADCTL_BGR); - _width = iheight; - _height = iwidth; - break; - case 2: - m = (MADCTL_MY | MADCTL_MX | MADCTL_BGR); - _width = iwidth; - _height = iheight; - break; - case 3: - m = (MADCTL_MX | MADCTL_MV | MADCTL_BGR); - _width = iheight; - _height = iwidth; - break; - } - } - SPI_BEGIN_TRANSACTION(); - ILI9341_2_CS_LOW - writecmd(ILI9341_2_MADCTL); - spiwrite(m); - ILI9341_2_CS_HIGH - SPI_END_TRANSACTION(); -} - - -void ILI9341_2::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { - - // Rudimentary clipping - if ((x >= _width) || (y >= _height)) return; - if ((y + h - 1) >= _height) h = _height - y; - - SPI_BEGIN_TRANSACTION(); - - ILI9341_2_CS_LOW - - setAddrWindow_int(x, y, 1, h); - - while (h--) { -#ifdef ILI9341_2_HWSPI - spi2->write16(color); -#else - spiwrite16(color); -#endif - } - - ILI9341_2_CS_HIGH - - SPI_END_TRANSACTION(); -} - -void ILI9341_2::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { - - // Rudimentary clipping - if((x >= _width) || (y >= _height)) return; - if((x+w-1) >= _width) w = _width-x; - - - SPI_BEGIN_TRANSACTION(); - - ILI9341_2_CS_LOW - - setAddrWindow_int(x, y, w, 1); - - - while (w--) { -#ifdef ILI9341_2_HWSPI - spi2->write16(color); -#else - spiwrite16(color); -#endif - } - - ILI9341_2_CS_HIGH - - SPI_END_TRANSACTION(); -} - -void ILI9341_2::fillScreen(uint16_t color) { - fillRect(0, 0, _width, _height, color); -} - -// fill a rectangle -void ILI9341_2::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { - - // rudimentary clipping (drawChar w/big text requires this) - if((x >= _width) || (y >= _height)) return; - if((x + w - 1) >= _width) w = _width - x; - if((y + h - 1) >= _height) h = _height - y; - - - SPI_BEGIN_TRANSACTION(); - - ILI9341_2_CS_LOW - - setAddrWindow_int(x, y, w, h); - - for (y=h; y>0; y--) { - for (x=w; x>0; x--) { -#ifdef ILI9341_2_HWSPI - spi2->write16(color); -#else - spiwrite16(color); -#endif - } - } - ILI9341_2_CS_HIGH - - SPI_END_TRANSACTION(); -} - - - -void ili9342_bpwr(uint8_t on); - -void ILI9341_2::DisplayOnff(int8_t on) { - - if ((_hwspi >= 2) && (_bp < 0)) { - //ili9342_bpwr(on); - if (pwr_cbp) { - pwr_cbp(on); - } - } - - if (on) { - SPI_BEGIN_TRANSACTION(); - ILI9341_2_CS_LOW - writecmd(ILI9341_2_DISPON); - ILI9341_2_CS_HIGH - SPI_END_TRANSACTION(); - if (_bp >= 0) { -#ifdef ILI9341_2_DIMMER - analogWrite(_bp, dimmer * 4); - // ledcWrite(ESP32_PWM_CHANNEL, dimmer); -#else - digitalWrite(_bp, HIGH); -#endif - } - } else { - SPI_BEGIN_TRANSACTION(); - ILI9341_2_CS_LOW - writecmd(ILI9341_2_DISPOFF); - ILI9341_2_CS_HIGH - SPI_END_TRANSACTION(); - if (_bp >= 0) { -#ifdef ILI9341_2_DIMMER - analogWrite(_bp, 0); - // ledcWrite(ESP32_PWM_CHANNEL, 0); -#else - digitalWrite(_bp, LOW); -#endif - } - } -} - -void ILI9341_2::invertDisplay(boolean i) { - SPI_BEGIN_TRANSACTION(); - ILI9341_2_CS_LOW - writecmd(i ? ILI9341_2_INVON : ILI9341_2_INVOFF); - ILI9341_2_CS_HIGH - SPI_END_TRANSACTION(); -} - -void ILI9341_2::reverseDisplay(boolean i) { - SPI_BEGIN_TRANSACTION(); - ILI9341_2_CS_LOW - if (i) { - writecmd(ILI9341_2_FRMCTR1); - spiwrite(0x00); - spiwrite(0x13); - writecmd(ILI9341_2_MADCTL); - spiwrite(0x01); - spiwrite(0x08); - } else { - writecmd(ILI9341_2_FRMCTR1); - spiwrite(0x00); - spiwrite(0x18); - writecmd(ILI9341_2_MADCTL); - spiwrite(0x01); - spiwrite(0x48); - } - ILI9341_2_CS_HIGH - SPI_END_TRANSACTION(); -} - -void ili9342_dimm(uint8_t dim); - -// dimmer 0-100 -void ILI9341_2::dim(uint8_t dim) { - dimmer = dim; - if (dimmer>15) dimmer=15; - dimmer=((float)dimmer/15.0)*255.0; -#ifdef ESP32 - if (_bp>=0) { - analogWrite(_bp, dimmer * 4); - // ledcWrite(ESP32_PWM_CHANNEL,dimmer); - } else { - if (_hwspi>=2) { - //ili9342_dimm(dim); - if (dim_cbp) { - dim_cbp(dim); - } - } - } -#endif -} - - -void ILI9341_2::spiwrite(uint8_t c) { - -#ifdef ILI9341_2_HWSPI - spi2->write(c); -#else - for (uint8_t bit = 0x80; bit; bit >>= 1) { - digitalWrite(_sclk, LOW); - if (c & bit) digitalWrite(_mosi, HIGH); - else digitalWrite(_mosi, LOW); - digitalWrite(_sclk, HIGH); - } -#endif - -} - -void ILI9341_2::spiwrite16(uint16_t c) { -#ifdef ILI9341_2_HWSPI - spi2->write16(c); -#else - spiwrite(c>>8); - spiwrite(c); -#endif -} - -void ILI9341_2::spiwrite32(uint32_t c) { -#ifdef ILI9341_2_HWSPI - spi2->write32(c); -#else - spiwrite(c>>24); - spiwrite(c>>16); - spiwrite(c>>8); - spiwrite(c); -#endif -} - -void ILI9341_2::setScrollMargins(uint16_t top, uint16_t bottom) { - uint16_t height = _height - (top + bottom); - SPI_BEGIN_TRANSACTION(); - ILI9341_2_CS_LOW - writecmd(0x33); - - spiwrite16(top); - spiwrite16(height); - spiwrite16(bottom); - ILI9341_2_CS_HIGH - SPI_END_TRANSACTION(); -} - - -void ILI9341_2::scrollTo(uint16_t y) { - SPI_BEGIN_TRANSACTION(); - ILI9341_2_CS_LOW - writecmd(ILI9341_2_VSCRSADD); - spiwrite16(y); - ILI9341_2_CS_HIGH - SPI_END_TRANSACTION(); -} diff --git a/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.h b/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.h deleted file mode 100644 index 88843016c..000000000 --- a/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.h +++ /dev/null @@ -1,163 +0,0 @@ -/*************************************************** - STM32 Support added by Jaret Burkett at OSHlab.com - - This is our library for the Adafruit ILI9341_2 Breakout and Shield - ----> http://www.adafruit.com/products/1651 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - -#ifndef _ILI9341_2H_ -#define _ILI9341_2H_ - -#include "Arduino.h" -#include -#include - -#define ILI9341_TFTWIDTH 320 -#define ILI9341_TFTHEIGHT 240 - -#define ILI9341_2_NOP 0x00 ///< No-op register -#define ILI9341_2_SWRESET 0x01 ///< Software reset register -#define ILI9341_2_RDDID 0x04 ///< Read display identification information -#define ILI9341_2_RDDST 0x09 ///< Read Display Status - -#define ILI9341_2_SLPIN 0x10 ///< Enter Sleep Mode -#define ILI9341_2_SLPOUT 0x11 ///< Sleep Out -#define ILI9341_2_PTLON 0x12 ///< Partial Mode ON -#define ILI9341_2_NORON 0x13 ///< Normal Display Mode ON - -#define ILI9341_2_RDMODE 0x0A ///< Read Display Power Mode -#define ILI9341_2_RDMADCTL 0x0B ///< Read Display MADCTL -#define ILI9341_2_RDPIXFMT 0x0C ///< Read Display Pixel Format -#define ILI9341_2_RDIMGFMT 0x0D ///< Read Display Image Format -#define ILI9341_2_RDSELFDIAG 0x0F ///< Read Display Self-Diagnostic Result - -#define ILI9341_2_INVOFF 0x20 ///< Display Inversion OFF -#define ILI9341_2_INVON 0x21 ///< Display Inversion ON -#define ILI9341_2_GAMMASET 0x26 ///< Gamma Set -#define ILI9341_2_DISPOFF 0x28 ///< Display OFF -#define ILI9341_2_DISPON 0x29 ///< Display ON - -#define ILI9341_2_CASET 0x2A ///< Column Address Set -#define ILI9341_2_PASET 0x2B ///< Page Address Set -#define ILI9341_2_RAMWR 0x2C ///< Memory Write -#define ILI9341_2_RAMRD 0x2E ///< Memory Read - -#define ILI9341_2_PTLAR 0x30 ///< Partial Area -#define ILI9341_2_MADCTL 0x36 ///< Memory Access Control -#define ILI9341_2_VSCRSADD 0x37 ///< Vertical Scrolling Start Address -#define ILI9341_2_PIXFMT 0x3A ///< COLMOD: Pixel Format Set - -#define ILI9341_2_FRMCTR1 0xB1 ///< Frame Rate Control (In Normal Mode/Full Colors) -#define ILI9341_2_FRMCTR2 0xB2 ///< Frame Rate Control (In Idle Mode/8 colors) -#define ILI9341_2_FRMCTR3 0xB3 ///< Frame Rate control (In Partial Mode/Full Colors) -#define ILI9341_2_INVCTR 0xB4 ///< Display Inversion Control -#define ILI9341_2_DFUNCTR 0xB6 ///< Display Function Control - -#define ILI9341_2_PWCTR1 0xC0 ///< Power Control 1 -#define ILI9341_2_PWCTR2 0xC1 ///< Power Control 2 -#define ILI9341_2_PWCTR3 0xC2 ///< Power Control 3 -#define ILI9341_2_PWCTR4 0xC3 ///< Power Control 4 -#define ILI9341_2_PWCTR5 0xC4 ///< Power Control 5 -#define ILI9341_2_VMCTR1 0xC5 ///< VCOM Control 1 -#define ILI9341_2_VMCTR2 0xC7 ///< VCOM Control 2 - -#define ILI9341_2_RDID1 0xDA ///< Read ID 1 -#define ILI9341_2_RDID2 0xDB ///< Read ID 2 -#define ILI9341_2_RDID3 0xDC ///< Read ID 3 -#define ILI9341_2_RDID4 0xDD ///< Read ID 4 - -#define ILI9341_2_GMCTRP1 0xE0 ///< Positive Gamma Correction -#define ILI9341_2_GMCTRN1 0xE1 ///< Negative Gamma Correction - - -// Color definitions -#define ILI9341_BLACK 0x0000 /* 0, 0, 0 */ -#define ILI9341_NAVY 0x000F /* 0, 0, 128 */ -#define ILI9341_DARKGREEN 0x03E0 /* 0, 128, 0 */ -#define ILI9341_DARKCYAN 0x03EF /* 0, 128, 128 */ -#define ILI9341_MAROON 0x7800 /* 128, 0, 0 */ -#define ILI9341_PURPLE 0x780F /* 128, 0, 128 */ -#define ILI9341_OLIVE 0x7BE0 /* 128, 128, 0 */ -#define ILI9341_LIGHTGREY 0xC618 /* 192, 192, 192 */ -#define ILI9341_DARKGREY 0x7BEF /* 128, 128, 128 */ -#define ILI9341_BLUE 0x001F /* 0, 0, 255 */ -#define ILI9341_GREEN 0x07E0 /* 0, 255, 0 */ -#define ILI9341_CYAN 0x07FF /* 0, 255, 255 */ -#define ILI9341_RED 0xF800 /* 255, 0, 0 */ -#define ILI9341_MAGENTA 0xF81F /* 255, 0, 255 */ -#define ILI9341_YELLOW 0xFFE0 /* 255, 255, 0 */ -#define ILI9341_WHITE 0xFFFF /* 255, 255, 255 */ -#define ILI9341_ORANGE 0xFD20 /* 255, 165, 0 */ -#define ILI9341_GREENYELLOW 0xAFE5 /* 173, 255, 47 */ -#define ILI9341_PINK 0xF81F - - -#define MADCTL_2_MY 0x80 ///< Bottom to top -#define MADCTL_2_MX 0x40 ///< Right to left -#define MADCTL_2_MV 0x20 ///< Reverse Mode -#define MADCTL_2_ML 0x10 ///< LCD refresh Bottom to top -#define MADCTL_2_RGB 0x00 ///< Red-Green-Blue pixel order -#define MADCTL_2_BGR 0x08 ///< Blue-Green-Red pixel order -#define MADCTL_2_MH 0x04 ///< LCD refresh right to left - - -class ILI9341_2 : public Renderer { - - public: - - ILI9341_2(int8_t cs, int8_t mosi, int8_t miso, int8_t sclk, int8_t res, int8_t dc, int8_t bp, int8_t spibus, uint8_t dtype); - ILI9341_2(int8_t cs, int8_t res, int8_t dc, int8_t bp); - - void init(uint16_t width, uint16_t height); - uint16_t GetColorFromIndex(uint8_t index); - - private: - SPIClass *spi2; - SPISettings sspi2; - void writecmd(uint8_t d); - void setAddrWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); - void setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h); - void drawPixel(int16_t x, int16_t y, uint16_t color); - void DisplayOnff(int8_t on); - void setRotation(uint8_t m); - void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font); - void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); - void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); - void fillScreen(uint16_t color); - void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void dim(uint8_t dim); - void pushColors(uint16_t *data, uint16_t len, boolean first); - void invertDisplay(boolean i); - void reverseDisplay(boolean i); - void spiwrite(uint8_t c); - void spiwrite16(uint16_t c); - void spiwrite32(uint32_t c); - void setScrollMargins(uint16_t top, uint16_t bottom); - void scrollTo(uint16_t y); - - uint8_t tabcolor; - uint8_t dimmer; - int8_t _cs; - int8_t _mosi; - int8_t _miso; - int8_t _sclk; - int8_t _res; - int8_t _dc; - int8_t _bp; - int8_t _spibus; - int8_t _hwspi; - uint16_t iwidth; - uint16_t iheight; -}; - -#endif diff --git a/lib/lib_display/ILI9341-gemu-1.0/library.properties b/lib/lib_display/ILI9341-gemu-1.0/library.properties deleted file mode 100644 index 5373590b5..000000000 --- a/lib/lib_display/ILI9341-gemu-1.0/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=ILI9341 -version=1.0.0 -author=Gerhard Mutz -maintainer=Gerhard Mutz -sentence=ILI9341 ESP8266 ESP32 display driver for Tasmota -paragraph=ILI9341 ESP8266 ESP32 display driver for Tasmota -category=Display -url=https://github.com/arendst/Tasmota -architectures=* diff --git a/lib/lib_display/LiquidCrystal_I2C-1.1.3/LiquidCrystal_I2C.o b/lib/lib_display/LiquidCrystal_I2C-1.1.3/LiquidCrystal_I2C.o deleted file mode 100644 index bca78e0d2..000000000 Binary files a/lib/lib_display/LiquidCrystal_I2C-1.1.3/LiquidCrystal_I2C.o and /dev/null differ diff --git a/lib/lib_display/UDisplay/uDisplay.cpp b/lib/lib_display/UDisplay/uDisplay.cpp index 9f2b54216..3b4ed0449 100755 --- a/lib/lib_display/UDisplay/uDisplay.cpp +++ b/lib/lib_display/UDisplay/uDisplay.cpp @@ -24,6 +24,10 @@ #include "esp8266toEsp32.h" #endif +#ifdef USE_ESP32_S3 +#include "esp_cache.h" +#endif // USE_ESP32_S3 + #include "tasmota_options.h" extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size); @@ -142,13 +146,14 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { epc_full_cnt = 0; lut_num = 0; lvgl_param.data = 0; - lvgl_param.fluslines = 40; + lvgl_param.flushlines = 40; rot_t[0] = 0; rot_t[1] = 1; rot_t[2] = 2; rot_t[3] = 3; epcoffs_full = 0; epcoffs_part = 0; + interface = 0; for (uint32_t cnt = 0; cnt < MAX_LUTS; cnt++) { lut_cnt[cnt] = 0; @@ -589,7 +594,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { lut3time = next_val(&lp1); break; case 'B': - lvgl_param.fluslines = next_val(&lp1); + lvgl_param.flushlines = next_val(&lp1); lvgl_param.data = next_val(&lp1); break; case 'M': @@ -687,6 +692,19 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { ep_mode = 2; } + +#ifdef USE_ESP32_S3 +void UfsCheckSDCardInit(void); + + if (spec_init == _UDSP_SPI) { + // special case, assuming sd card and display on same spi bus + // end spi in case it was running + SPI.end(); + // reininit SD card + UfsCheckSDCardInit(); + } +#endif + #ifdef UDSP_DEBUG Serial.printf("Device : %s\n", dname); Serial.printf("xs : %d\n", gxs); @@ -699,6 +717,9 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { Serial.printf("CLK : %d\n", spi_clk); Serial.printf("MOSI: %d\n", spi_mosi); Serial.printf("DC : %d\n", spi_dc); + Serial.printf("TS_CS: %d\n", ut_spi_cs); + Serial.printf("TS_RST: %d\n", ut_reset); + Serial.printf("TS_IRQ: %d\n", ut_irq); Serial.printf("BPAN: %d\n", bpanel); Serial.printf("RES : %d\n", reset); Serial.printf("MISO: %d\n", spi_miso); @@ -1011,6 +1032,13 @@ exit: Renderer *uDisplay::Init(void) { extern bool UsePSRAM(void); + if (!interface) { // no valid configuration, abort + #ifdef UDSP_DEBUG + Serial.printf("Dsp Init no valid configuration\n"); + #endif + return NULL; + } + #ifdef UDSP_DEBUG Serial.printf("Dsp Init 1 start \n"); #endif @@ -1138,6 +1166,12 @@ Renderer *uDisplay::Init(void) { if (interface == _UDSP_RGB) { #ifdef USE_ESP32_S3 + if (!UsePSRAM()) { // RGB is not supported on S3 without PSRAM + #ifdef UDSP_DEBUG + Serial.printf("Dsp RGB requires PSRAM, abort\n"); + #endif + return NULL; + } if (bpanel >= 0) { analogWrite(bpanel, 32); @@ -1728,6 +1762,9 @@ void uDisplay::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { if (interface == _UDSP_RGB) { #ifdef USE_ESP32_S3 + if (lvgl_param.swap_color) { + color = color << 8 | color >> 8; + } if (cur_rot > 0) { while (h--) { drawPixel_RGB(x , y , color); @@ -1798,6 +1835,9 @@ void uDisplay::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { if (interface == _UDSP_RGB) { #ifdef USE_ESP32_S3 + if (lvgl_param.swap_color) { + color = color << 8 | color >> 8; + } if (cur_rot > 0) { while (w--) { drawPixel_RGB(x , y , color); @@ -2161,42 +2201,67 @@ void uDisplay::pushColors(uint16_t *data, uint16_t len, boolean not_swapped) { } //Serial.printf("push %x - %d - %d - %d\n", (uint32_t)data, len, not_swapped, lvgl_param.data); - if (not_swapped == false) { - // called from LVGL bytes are swapped - if (interface == _UDSP_RGB) { + + // Isolating _UDPS_RGB to increase code sharing + // + // LVGL documentation suggest to call the following: + // lv_draw_sw_rgb565_swap() to invert bytes + // esp_lcd_panel_draw_bitmap() to paste bytes + // but it appears to be faster to include the color swap in the copy loop + // because the CPU is much faster than PSRAM (SPI bus), therefore + // swapping bytes on the fly costs zero performance + // + // not_swapped == false : called from LVGL bytes are swapped + // not_swapped == true : called from displaytext, no byte swap, currently no dma here + if (interface == _UDSP_RGB) { #ifdef USE_ESP32_S3 - if (cur_rot > 0) { - for (uint32_t y = seta_yp1; y < seta_yp2; y++) { - seta_yp1++; - for (uint32_t x = seta_xp1; x < seta_xp2; x++) { - uint16_t color = *data++; - color = color << 8 | color >> 8; - drawPixel_RGB(x, y, color); - len--; - if (!len) return; // failsafe - exist if len (pixel number) is exhausted - } - } - } else { - for (uint32_t y = seta_yp1; y < seta_yp2; y++) { - seta_yp1++; - uint16_t *fb = rgb_fb; - fb += (int32_t)y * _width; - fb += seta_xp1; - for (uint32_t x = seta_xp1; x < seta_xp2; x++) { - uint16_t color = *data++; - color = color << 8 | color >> 8; - *fb = color; - Cache_WriteBack_Addr((uint32_t)fb, 2); - fb++; - len--; - if (!len) return; // failsafe - exist if len (pixel number) is exhausted - } + // check that bytes count matches the size of area, and remove from inner loop + if ((seta_yp2 - seta_yp1) * (seta_xp2 - seta_xp2) > len) { return; } + + if (cur_rot > 0) { + for (uint32_t y = seta_yp1; y < seta_yp2; y++) { + seta_yp1++; + for (uint32_t x = seta_xp1; x < seta_xp2; x++) { + uint16_t color = *data++; + if (!not_swapped) { color = color << 8 | color >> 8; } + drawPixel_RGB(x, y, color); + len--; + if (!len) return; // failsafe - exist if len (pixel number) is exhausted } } -#endif - return; + } else { + uint16_t *fb_y = rgb_fb + (int32_t)seta_yp1 * _width; + for (uint32_t y = seta_yp1; y < seta_yp2; y++) { + uint16_t * fb_xy = fb_y + seta_xp1; + // we get the 'not_swapped' test outside of the inner loop + if (not_swapped) { + for (uint32_t x = seta_xp1; x < seta_xp2; x++) { + uint16_t color = *data++; + *fb_xy = color; + fb_xy++; + } + } else { + for (uint32_t x = seta_xp1; x < seta_xp2; x++) { + uint16_t color = *data++; + color = color << 8 | color >> 8; + *fb_xy = color; + fb_xy++; + } + } + fb_y += _width; + } + // using esp_cache_msync() to flush the PSRAM cache and ensure that all data is actually written to PSRAM + // from https://github.com/espressif/esp-idf/blob/636ff35b52f10e1a804a3760a5bd94e68f4b1b71/components/esp_lcd/rgb/esp_lcd_panel_rgb.c#L159 + uint16_t * flush_ptr = rgb_fb + (int32_t)seta_yp1 * _width; + esp_cache_msync(flush_ptr, (seta_yp2 - seta_yp1) * _width * 2, 0); } +#endif + return; + } + + if (not_swapped == false) { + // called from LVGL bytes are swapped if (bpp != 16) { // lvgl_color_swap(data, len); -- no need to swap anymore, we have inverted the mask pushColorsMono(data, len, true); @@ -2270,35 +2335,6 @@ void uDisplay::pushColors(uint16_t *data, uint16_t len, boolean not_swapped) { } } else { // called from displaytext, no byte swap, currently no dma here - if (interface == _UDSP_RGB) { -#ifdef USE_ESP32_S3 - if (cur_rot > 0) { - for (uint32_t y = seta_yp1; y < seta_yp2; y++) { - seta_yp1++; - for (uint32_t x = seta_xp1; x < seta_xp2; x++) { - drawPixel_RGB(x, y, *data++); - len--; - if (!len) return; // failsafe - exist if len (pixel number) is exhausted - } - } - } else { - for (uint32_t y = seta_yp1; y < seta_yp2; y++) { - seta_yp1++; - uint16_t *fb = rgb_fb; - fb += (int32_t)y * _width; - fb += seta_xp1; - for (uint32_t x = seta_xp1; x < seta_xp2; x++) { - *fb = *data++; - Cache_WriteBack_Addr((uint32_t)fb, 2); - fb++; - len--; - if (!len) return; // failsafe - exist if len (pixel number) is exhausted - } - } - } -#endif - return; - } if (bpp != 16) { pushColorsMono(data, len); @@ -2387,6 +2423,9 @@ void uDisplay::drawPixel(int16_t x, int16_t y, uint16_t color) { #ifdef USE_ESP32_S3 if (interface == _UDSP_RGB) { + if (lvgl_param.swap_color) { + color = color << 8 | color >> 8; + } drawPixel_RGB(x, y, color); return; } @@ -2743,6 +2782,14 @@ void uDisplay::ut_trans(char **sp, uint8_t **code) { // cmp and set *ut_code++ = UT_CPR; *ut_code++ = ut_par(&cp, 0); + } else if (!strncmp(cp, "CPM", 3)) { + // cmp multiple and set + *ut_code++ = UT_CPM; + uint8_t num = ut_par(&cp, 0); + *ut_code++ = num; + for (uint32_t cnt = 0; cnt < num; cnt++) { + *ut_code++ = ut_par(&cp, 0); + } } else if (!strncmp(cp, "CP", 2)) { // cmp and set *ut_code++ = UT_CP; @@ -2979,6 +3026,16 @@ uint16_t wval; result = (iob == ut_array[0]); break; + case UT_CPM: + // compare multiple + len = *ut_code++; + result = 0; + for (uint32_t cnt = 0; cnt < len; cnt++) { + iob = *ut_code++; + result |= (iob == ut_array[0]); + } + break; + case UT_CPR: // compare iob = *ut_code++; diff --git a/lib/lib_display/UDisplay/uDisplay.h b/lib/lib_display/UDisplay/uDisplay.h index bf031f5fa..c054bd9c6 100755 --- a/lib/lib_display/UDisplay/uDisplay.h +++ b/lib/lib_display/UDisplay/uDisplay.h @@ -18,7 +18,7 @@ #endif enum { - UT_RD,UT_RDM,UT_CP,UT_RTF,UT_MV,UT_MVB,UT_RT,UT_RTT,UT_RDW,UT_RDWM,UT_WR,UT_WRW,UT_CPR,UT_AND,UT_SCALE,UT_LIM,UT_DBG,UT_GSRT,UT_XPT,UT_END + UT_RD,UT_RDM,UT_CP,UT_RTF,UT_MV,UT_MVB,UT_RT,UT_RTT,UT_RDW,UT_RDWM,UT_WR,UT_WRW,UT_CPR,UT_AND,UT_SCALE,UT_LIM,UT_DBG,UT_GSRT,UT_XPT,UT_CPM,UT_END }; #define RA8876_DATA_WRITE 0x80 @@ -456,18 +456,18 @@ class uDisplay : public Renderer { uint8_t ut_array[16]; uint8_t ut_i2caddr; - uint8_t ut_spi_cs; - int8_t ut_reset; - int8_t ut_irq; + uint8_t ut_spi_cs = -1; + int8_t ut_reset = -1; + int8_t ut_irq = -1; uint8_t ut_spi_nr; - TwoWire *ut_wire; - SPIClass *ut_spi; + TwoWire *ut_wire = nullptr;; + SPIClass *ut_spi = nullptr;; SPISettings ut_spiSettings; char ut_name[8]; - uint8_t *ut_init_code; - uint8_t *ut_touch_code; - uint8_t *ut_getx_code; - uint8_t *ut_gety_code; + uint8_t *ut_init_code = nullptr; + uint8_t *ut_touch_code = nullptr; + uint8_t *ut_getx_code = nullptr; + uint8_t *ut_gety_code = nullptr; #endif // USE_UNIVERSAL_TOUCH }; diff --git a/lib/lib_display/Xlatb_RA8876-gemu-1.0/RA8876.cpp b/lib/lib_display/Xlatb_RA8876-gemu-1.0/RA8876.cpp index d050d83ac..77d48daa0 100644 --- a/lib/lib_display/Xlatb_RA8876-gemu-1.0/RA8876.cpp +++ b/lib/lib_display/Xlatb_RA8876-gemu-1.0/RA8876.cpp @@ -493,7 +493,7 @@ void RA8876::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { bool RA8876::initDisplay() { - lvgl_param.fluslines = 10; + lvgl_param.flushlines = 10; SPI.beginTransaction(m_spiSettings); diff --git a/lib/lib_div/A4988_Stepper/src/A4988_Stepper.h b/lib/lib_div/A4988_Stepper/src/A4988_Stepper.h index a907adfb1..f48041a6a 100644 --- a/lib/lib_div/A4988_Stepper/src/A4988_Stepper.h +++ b/lib/lib_div/A4988_Stepper/src/A4988_Stepper.h @@ -34,7 +34,7 @@ class A4988_Stepper { void setRPM (int whatRPM ); int getRPM (void ); - void setMIS (short OneToSixteen); + void setMIS (short oneToSixteen); short getMIS (void ); void setSPR (int howMany ); diff --git a/lib/lib_div/ESPFtpServer/ESPFtpServer.cpp b/lib/lib_div/ESPFtpServer/ESPFtpServer.cpp index c70d17dcf..afe14f5e5 100755 --- a/lib/lib_div/ESPFtpServer/ESPFtpServer.cpp +++ b/lib/lib_div/ESPFtpServer/ESPFtpServer.cpp @@ -25,6 +25,7 @@ #include #ifdef ESP32 +#undef F #define F(A) A #endif diff --git a/lib/lib_div/LibTeleinfo/library.json b/lib/lib_div/LibTeleinfo/library.json index 84593d3a6..61cf20b90 100644 --- a/lib/lib_div/LibTeleinfo/library.json +++ b/lib/lib_div/LibTeleinfo/library.json @@ -1,6 +1,6 @@ { "name": "LibTeleinfo", - "version": "1.1.5", + "version": "1.1.7", "keywords": "teleinfo, french, meter, power, erdf, linky, tic", "description": "Decoder for Teleinfo (aka TIC) from French smart power meters", "repository": diff --git a/lib/lib_div/LibTeleinfo/library.properties b/lib/lib_div/LibTeleinfo/library.properties index 562d96c62..2b4877ca5 100644 --- a/lib/lib_div/LibTeleinfo/library.properties +++ b/lib/lib_div/LibTeleinfo/library.properties @@ -1,5 +1,5 @@ name=LibTeleinfo -version=1.1.5 +version=1.1.7 author=Charles-Henri Hallard maintainer=Charles-Henri Hallard sentence=Decoder for Teleinfo (aka TIC) from French smart power meters diff --git a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp index 92bd7e359..94f0c6af1 100644 --- a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp +++ b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp @@ -700,8 +700,8 @@ unsigned char TInfo::calcChecksum(char *etiquette, char *valeur, char * horodate if (strlen(etiquette) && strlen(valeur)) { while (*etiquette) { c =*etiquette++; - // Add another validity check since checksum may not be sufficient - if ( (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='-' || c=='+') { + // Add another validity check + if (c>=0x20 && c<=0x7E) { sum += c ; } else { return 0; @@ -710,8 +710,8 @@ unsigned char TInfo::calcChecksum(char *etiquette, char *valeur, char * horodate while(*valeur) { c = *valeur++ ; - // Add another validity check since checksum may not be sufficient (space authorized in Standard mode) - if ( (c>='A' && c<='Z') || (c>='0' && c<='9') || c==' ' || c=='.' || c=='-' || c=='+' || c=='/') { + // Add another validity check + if (c>=0x20 && c<=0x7E) { sum += c ; } else { return 0; diff --git a/lib/lib_i2c/SPL06_007/README.md b/lib/lib_i2c/SPL06_007/README.md new file mode 100644 index 000000000..541b511cf --- /dev/null +++ b/lib/lib_i2c/SPL06_007/README.md @@ -0,0 +1,7 @@ +# SPL06-007 +Ardino SPL06-007 Library + +This is a work in progress to create a working Arduino library for the SPL06-007 pressure sensor. I am able to get the coefficents, pressure, and temperature readings from the sensor. Need to convert to a standard Arduino library format. Code was developed and tested on an ESP32 microcontroller. + +Link to datasheet +https://datasheet.lcsc.com/szlcsc/1912111437_Goertek-SPL06-007_C233787.pdf diff --git a/lib/lib_i2c/SPL06_007/datasheets/1912111437_Goertek-SPL06-007_C233787.pdf b/lib/lib_i2c/SPL06_007/datasheets/1912111437_Goertek-SPL06-007_C233787.pdf new file mode 100644 index 000000000..163475e78 Binary files /dev/null and b/lib/lib_i2c/SPL06_007/datasheets/1912111437_Goertek-SPL06-007_C233787.pdf differ diff --git a/lib/lib_i2c/SPL06_007/examples/Pressure_Info/Pressure_Info.ino b/lib/lib_i2c/SPL06_007/examples/Pressure_Info/Pressure_Info.ino new file mode 100644 index 000000000..f6e913307 --- /dev/null +++ b/lib/lib_i2c/SPL06_007/examples/Pressure_Info/Pressure_Info.ino @@ -0,0 +1,119 @@ +#include +#include + +//#define Serial SerialUSB + +void setup() { + Wire.begin(); // begin Wire(I2C) + Serial.begin(115200); // begin Serial + + Serial.println("\nGoertek-SPL06-007 Demo\n"); + + SPL_init(); // Setup initial SPL chip registers - default i2c address 0x76 + // SPL_init(0x77); // Uncomment for alternate I2C address 0x77 +} + +void loop() { + + // ---- Register Values ---------------- + Serial.print("ID: "); + Serial.println(get_spl_id()); + + Serial.print("PRS_CFG: "); + Serial.println(get_spl_prs_cfg(),BIN); + + Serial.print("TMP_CFG: "); + Serial.println(get_spl_tmp_cfg(),BIN); + + Serial.print("MEAS_CFG: "); + Serial.println(get_spl_meas_cfg(),BIN); + + Serial.print("CFG_REG: "); + Serial.println(get_spl_cfg_reg(),BIN); + + Serial.print("INT_STS: "); + Serial.println(get_spl_int_sts(),BIN); + + Serial.print("FIFO_STS: "); + Serial.println(get_spl_fifo_sts(),BIN); + + + // ---- Coefficients ---------------- + Serial.print("c0: "); + Serial.println(get_c0()); + + Serial.print("c1: "); + Serial.println(get_c1()); + + Serial.print("c00: "); + Serial.println(get_c00()); + + Serial.print("c10: "); + Serial.println(get_c10()); + + Serial.print("c01: "); + Serial.println(get_c01()); + + Serial.print("c11: "); + Serial.println(get_c11()); + + Serial.print("c20: "); + Serial.println(get_c20()); + + Serial.print("c21: "); + Serial.println(get_c21()); + + Serial.print("c30: "); + Serial.println(get_c30()); + + + // ---- Temperature Values ---------------- + Serial.print("traw: "); + Serial.println(get_traw()); + + Serial.print("traw_sc: "); + Serial.println(get_traw_sc(),3); + + Serial.print("Temperature: "); + Serial.print(get_temp_c()); + Serial.println(" C"); + + Serial.print("Temperature: "); + Serial.print(get_temp_f()); + Serial.println(" F"); + + + // ---- Pressure Values ---------------- + Serial.print("praw: "); + Serial.println(get_praw()); + + Serial.print("praw_sc: "); + Serial.println(get_praw_sc(),3); + + Serial.print("pcomp: "); + Serial.println(get_pcomp(),2); + + Serial.print("Measured Air Pressure: "); + Serial.print(get_pressure(),2); + Serial.println(" mb"); + + + // ---- Altitude Values ---------------- + double local_pressure = 1011.3; // Look up local sea level pressure on google // Local pressure from airport website 8/22 + Serial.print("Local Airport Sea Level Pressure: "); + Serial.print(local_pressure,2); + Serial.println(" mb"); + + Serial.print("altitude: "); + Serial.print(get_altitude(get_pressure(),local_pressure),1); + Serial.println(" m"); + + Serial.print("altitude: "); + Serial.print(get_altitude_f(get_pressure(),local_pressure),1); // convert from meters to feet + Serial.println(" ft"); + + + + Serial.println("\n"); + delay(2000); +} diff --git a/lib/lib_i2c/SPL06_007/keywords.txt b/lib/lib_i2c/SPL06_007/keywords.txt new file mode 100644 index 000000000..b70bce924 --- /dev/null +++ b/lib/lib_i2c/SPL06_007/keywords.txt @@ -0,0 +1,57 @@ +####################################### +# Syntax Coloring Map For SHT21 +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SPL06-007 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +SPL_init KEYWORD2 +get_spl_id KEYWORD2 +get_spl_prs_cfg KEYWORD2 +get_spl_tmp_cfg KEYWORD2 +get_spl_meas_cfg KEYWORD2 +get_spl_cfg_reg KEYWORD2 +get_spl_int_sts KEYWORD2 +get_spl_fifo_sts KEYWORD2 + +get_traw KEYWORD2 +get_traw_sc KEYWORD2 +get_temp_c KEYWORD2 +get_temperature_scale_factor KEYWORD2 + + +get_pressure_scale_factor KEYWORD2 +get_pcomp KEYWORD2 +get_praw_sc KEYWORD2 +get_praw KEYWORD2 +get_pressure KEYWORD2 + +get_c0 KEYWORD2 +get_c1 KEYWORD2 +get_c00 KEYWORD2 +get_c10 KEYWORD2 +get_c01 KEYWORD2 +get_c11 KEYWORD2 +get_c20 KEYWORD2 +get_c21 KEYWORD2 +get_c30 KEYWORD2 +i2c_eeprom_write_uint8_t KEYWORD2 +i2c_eeprom_read_uint8_t KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + + + + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/lib/lib_i2c/SPL06_007/library.properties b/lib/lib_i2c/SPL06_007/library.properties new file mode 100644 index 000000000..74a199a35 --- /dev/null +++ b/lib/lib_i2c/SPL06_007/library.properties @@ -0,0 +1,11 @@ +name=SPL06-007 +version=0.1.0 +author=rv701 +maintainer=rv701 +sentence=SPL06-007 library for Arduino processors +paragraph=Supports SPL06-007 I2C pressure sensor. +category=Sensors +url=https://github.com/rv701/SPL06-007 +architectures=* +includes=SPL06-007.h + diff --git a/lib/lib_i2c/SPL06_007/src/SPL06-007.cpp b/lib/lib_i2c/SPL06_007/src/SPL06-007.cpp new file mode 100644 index 000000000..35c968bbf --- /dev/null +++ b/lib/lib_i2c/SPL06_007/src/SPL06-007.cpp @@ -0,0 +1,371 @@ +#include "SPL06-007.h" +#include "Wire.h" + +uint8_t SPL_CHIP_ADDRESS = 0x76; + +void SPL_init(uint8_t spl_address) +{ + if(spl_address == 0x77) + SPL_CHIP_ADDRESS = 0x77; + + // ---- Oversampling of >8x for temperature or pressuse requires FIFO operational mode which is not implemented --- + // ---- Use rates of 8x or less until feature is implemented --- + i2c_eeprom_write_uint8_t(SPL_CHIP_ADDRESS, 0X06, 0x03); // Pressure 8x oversampling + + i2c_eeprom_write_uint8_t(SPL_CHIP_ADDRESS, 0X07, 0X83); // Temperature 8x oversampling + + i2c_eeprom_write_uint8_t(SPL_CHIP_ADDRESS, 0X08, 0B0111); // continuous temp and pressure measurement + + i2c_eeprom_write_uint8_t(SPL_CHIP_ADDRESS, 0X09, 0X00); // FIFO Pressure measurement +} + +uint8_t get_spl_id() +{ + return i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0x0D); +} + +uint8_t get_spl_prs_cfg() +{ + return i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0x06); +} + +uint8_t get_spl_tmp_cfg() +{ + return i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0x07); +} + +uint8_t get_spl_meas_cfg() +{ + return i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0x08); +} + +uint8_t get_spl_cfg_reg() +{ + return i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0x09); +} + +uint8_t get_spl_int_sts() +{ + return i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0x0A); +} + +uint8_t get_spl_fifo_sts() +{ + return i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0x0B); +} + +float get_traw_sc() { + int32_t traw = get_traw(); + return (float(traw)/get_temperature_scale_factor()); +} + +float get_temp_c() { + int16_t c0,c1; + c0 = get_c0(); + c1 = get_c1(); + float traw_sc = get_traw_sc(); + return (float(c0) * 0.5f) + (float(c1) * traw_sc); +} + +float get_temperature_scale_factor() +{ + float k; + uint8_t tmp_Byte; + tmp_Byte = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X07); // MSB + //tmp_Byte = tmp_Byte >> 4; //Focus on bits 6-4 + tmp_Byte = tmp_Byte & 0B00000111; + + switch (tmp_Byte) + { + case 0B000: + k = 524288.0f; + break; + + case 0B001: + k = 1572864.0f; + break; + + case 0B010: + k = 3670016.0f; + break; + + case 0B011: + k = 7864320.0f; + break; + + case 0B100: + k = 253952.0f; + break; + + case 0B101: + k = 516096.0f; + break; + + case 0B110: + k = 1040384.0f; + break; + + case 0B111: + k = 2088960.0f; + break; + } + return k; +} + + +int32_t get_traw() +{ + int32_t tmp; + uint8_t tmp_MSB,tmp_LSB,tmp_XLSB; + tmp_MSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X03); // MSB + + tmp_LSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X04); // LSB + + tmp_XLSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X05); // XLSB + + tmp = (tmp_MSB << 8) | tmp_LSB; + tmp = (tmp << 8) | tmp_XLSB; + + if(tmp & (1 << 23)) + tmp = tmp | 0XFF000000; // Set left bits to one for 2's complement conversion of negitive number + return tmp; +} + +float get_praw_sc() +{ + int32_t praw = get_praw(); + return (float(praw)/get_pressure_scale_factor()); +} + +float get_pcomp() +{ + int32_t c00,c10; + int16_t c01,c11,c20,c21,c30; + c00 = get_c00(); + c10 = get_c10(); + c01 = get_c01(); + c11 = get_c11(); + c20 = get_c20(); + c21 = get_c21(); + c30 = get_c30(); + float traw_sc = get_traw_sc(); + float praw_sc = get_praw_sc(); + return float(c00) + praw_sc * (float(c10) + praw_sc * (float(c20) + praw_sc * float(c30))) + traw_sc * float(c01) + traw_sc * praw_sc * ( float(c11) + praw_sc * float(c21)); +} + +float get_pressure() +{ + return get_pcomp() / 100; // convert to mb +} + +float get_pressure_scale_factor() +{ + float k; + + uint8_t tmp_Byte; + tmp_Byte = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X06); // MSB + + tmp_Byte = tmp_Byte & 0B00000111; // Focus on 2-0 oversampling rate + + + switch (tmp_Byte) // oversampling rate + { + case 0B000: + k = 524288.0f; + break; + + case 0B001: + k = 1572864.0f; + break; + + case 0B010: + k = 3670016.0f; + break; + + case 0B011: + k = 7864320.0f; + break; + + case 0B100: + k = 253952.0f; + break; + + case 0B101: + k = 516096.0f; + break; + + case 0B110: + k = 1040384.0f; + break; + + case 0B111: + k = 2088960.0f; + break; + } + + return k; +} + +int32_t get_praw() +{ + int32_t tmp; + uint8_t tmp_MSB,tmp_LSB,tmp_XLSB; + tmp_MSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X00); // MSB + + + tmp_LSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X01); // LSB + + + tmp_XLSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X02); // XLSB + + + tmp = (tmp_MSB << 8) | tmp_LSB; + tmp = (tmp << 8) | tmp_XLSB; + + if(tmp & (1 << 23)) + tmp = tmp | 0XFF000000; // Set left bits to one for 2's complement conversion of negitive number + + + return tmp; +} + +int16_t get_c0() +{ + int16_t tmp; + uint8_t tmp_MSB,tmp_LSB; + + tmp_MSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X10); + tmp_LSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X11); + + tmp_LSB = tmp_LSB >> 4; + + tmp = (tmp_MSB << 4) | tmp_LSB; + + if(tmp & (1 << 11)) // Check for 2's complement negative number + tmp = tmp | 0XF000; // Set left bits to one for 2's complement conversion of negitive number + return tmp; +} + +int16_t get_c1() +{ + int16_t tmp; + uint8_t tmp_MSB,tmp_LSB; + + tmp_MSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X11); + tmp_LSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X12); + + tmp_MSB = tmp_MSB & 0XF; + + tmp = (tmp_MSB << 8) | tmp_LSB; + + if(tmp & (1 << 11)) // Check for 2's complement negative number + tmp = tmp | 0XF000; // Set left bits to one for 2's complement conversion of negitive number + + return tmp; +} + +int32_t get_c00() +{ + int32_t tmp; + uint8_t tmp_MSB,tmp_LSB,tmp_XLSB; + + tmp_MSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X13); + tmp_LSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X14); + tmp_XLSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X15); + tmp = (tmp_MSB & 0x80 ? 0xFFF00000 : 0) | ((uint32_t)tmp_MSB << 12) | ((uint32_t)tmp_LSB << 4) | (((uint32_t)tmp_XLSB & 0xF0) >> 4); + return tmp; +} + +int32_t get_c10() +{ + int32_t tmp; + uint8_t tmp_MSB,tmp_LSB,tmp_XLSB; + + tmp_MSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X15); // 4 bits + tmp_LSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X16); // 8 bits + tmp_XLSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X17); // 8 bits + tmp = (tmp_MSB & 0x8 ? 0xFFF00000 : 0) | (((uint32_t)tmp_MSB & 0x0F) << 16) | ((uint32_t)tmp_LSB << 8) | (uint32_t)tmp_XLSB; + return tmp; +} + +int16_t get_c01() +{ + int16_t tmp; + uint8_t tmp_MSB,tmp_LSB; + + tmp_MSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X18); + tmp_LSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X19); + + tmp = (tmp_MSB << 8) | tmp_LSB; + return tmp; +} + +int16_t get_c11() +{ + int16_t tmp; + uint8_t tmp_MSB,tmp_LSB; + + tmp_MSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X1A); + tmp_LSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X1B); + + tmp = (tmp_MSB << 8) | tmp_LSB; + return tmp; +} + +int16_t get_c20() +{ + int16_t tmp; + uint8_t tmp_MSB,tmp_LSB; + + tmp_MSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X1C); + tmp_LSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X1D); + + tmp = (tmp_MSB << 8) | tmp_LSB; + return tmp; +} + +int16_t get_c21() +{ + int16_t tmp; + uint8_t tmp_MSB,tmp_LSB; + + tmp_MSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X1E); + tmp_LSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X1F); + + tmp = (tmp_MSB << 8) | tmp_LSB; + return tmp; +} + +int16_t get_c30() +{ + int16_t tmp; + uint8_t tmp_MSB,tmp_LSB; + + tmp_MSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X20); + tmp_LSB = i2c_eeprom_read_uint8_t(SPL_CHIP_ADDRESS, 0X21); + + tmp = (tmp_MSB << 8) | tmp_LSB; + return tmp; +} + +void i2c_eeprom_write_uint8_t( uint8_t deviceaddress, uint8_t eeaddress, uint8_t data ) +{ + uint8_t rdata = data; + delay(5); // Make sure to delay log enough for EEPROM I2C refresh time + Wire.beginTransmission(deviceaddress); + Wire.write((uint8_t)(eeaddress)); + Wire.write(rdata); + Wire.endTransmission(); +} + +uint8_t i2c_eeprom_read_uint8_t( uint8_t deviceaddress, uint8_t eeaddress ) +{ + uint8_t rdata = 0xFF; + Wire.beginTransmission(deviceaddress); + Wire.write(eeaddress); + Wire.endTransmission(false); // false to not release the line + + Wire.requestFrom(deviceaddress, (uint8_t)1); + if (Wire.available()) rdata = Wire.read(); + return rdata; +} diff --git a/lib/lib_i2c/SPL06_007/src/SPL06-007.h b/lib/lib_i2c/SPL06_007/src/SPL06-007.h new file mode 100644 index 000000000..807ff5b27 --- /dev/null +++ b/lib/lib_i2c/SPL06_007/src/SPL06-007.h @@ -0,0 +1,37 @@ +#include "Arduino.h" + +void SPL_init(uint8_t spl_address=0x76); + +uint8_t get_spl_id(); // Get ID Register 0x0D +uint8_t get_spl_prs_cfg(); // Get PRS_CFG Register 0x06 +uint8_t get_spl_tmp_cfg(); // Get TMP_CFG Register 0x07 +uint8_t get_spl_meas_cfg(); // Get MEAS_CFG Register 0x08 +uint8_t get_spl_cfg_reg(); // Get CFG_REG Register 0x09 +uint8_t get_spl_int_sts(); // Get INT_STS Register 0x0A +uint8_t get_spl_fifo_sts(); // Get FIFO_STS Register 0x0B + + +int32_t get_traw(); +float get_traw_sc(); +float get_temp_c(); +float get_temperature_scale_factor(); + +int32_t get_praw(); +float get_praw_sc(); +float get_pcomp(); +float get_pressure_scale_factor(); +float get_pressure(); + +int16_t get_c0(); +int16_t get_c1(); +int32_t get_c00(); +int32_t get_c10(); +int16_t get_c01(); +int16_t get_c11(); +int16_t get_c20(); +int16_t get_c21(); +int16_t get_c30(); + +void i2c_eeprom_write_uint8_t( uint8_t deviceaddress, uint8_t eeaddress, uint8_t data ); +uint8_t i2c_eeprom_read_uint8_t( uint8_t deviceaddress, uint8_t eeaddress ); + diff --git a/lib/lib_rf/LoRa/.travis.yml b/lib/lib_rf/LoRa/.travis.yml new file mode 100644 index 000000000..b574b4e2c --- /dev/null +++ b/lib/lib_rf/LoRa/.travis.yml @@ -0,0 +1,39 @@ +language: generic +env: + global: + - IDE_VERSION=1.8.2 + matrix: + - BOARD="arduino:avr:uno" + - BOARD="arduino:avr:micro" + - BOARD="arduino:avr:mega:cpu=atmega2560" + - BOARD="arduino:samd:arduino_zero_edbg" + - BOARD="arduino:samd:mkr1000" + - BOARD="arduino:samd:mkrzero" + - BOARD="arduino:samd:mkrwan1300" + - BOARD="arduino:samd:mkrwan1310" +before_install: + - wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz + - tar xf arduino-$IDE_VERSION-linux64.tar.xz + - mv arduino-$IDE_VERSION $HOME/arduino-ide + - export PATH=$PATH:$HOME/arduino-ide + - if [[ "$BOARD" =~ "arduino:samd:" ]]; then + arduino --install-boards arduino:samd &> /dev/null; + fi + - buildExampleSketch() { arduino --verbose-build --verify --board $BOARD $PWD/examples/$1/$1.ino; } +install: + - mkdir -p $HOME/Arduino/libraries + - ln -s $PWD $HOME/Arduino/libraries/LoRa +script: + - buildExampleSketch LoRaDumpRegisters + - buildExampleSketch LoRaDuplex + - if [[ "$BOARD" != "arduino:samd:mkrwan1300" ]]; then + buildExampleSketch LoRaDuplexCallback; + fi + - buildExampleSketch LoRaReceiver + - if [[ "$BOARD" != "arduino:samd:mkrwan1300" ]]; then + buildExampleSketch LoRaReceiverCallback; + fi + - buildExampleSketch LoRaSender + - buildExampleSketch LoRaSenderNonBlocking + - buildExampleSketch LoRaSetSpread + - buildExampleSketch LoRaSetSyncWord diff --git a/lib/lib_rf/LoRa/API.md b/lib/lib_rf/LoRa/API.md new file mode 100644 index 000000000..572eded63 --- /dev/null +++ b/lib/lib_rf/LoRa/API.md @@ -0,0 +1,417 @@ +# LoRa API + +## Include Library + +```arduino +#include +``` + +## Setup + +### Begin + +Initialize the library with the specified frequency. + +```arduino +LoRa.begin(frequency); +``` + * `frequency` - frequency in Hz (`433E6`, `868E6`, `915E6`) + +Returns `1` on success, `0` on failure. + +### Set pins + +Override the default `NSS`, `NRESET`, and `DIO0` pins used by the library. **Must** be called before `LoRa.begin()`. + +```arduino +LoRa.setPins(ss, reset, dio0); +``` + * `ss` - new slave select pin to use, defaults to `10` + * `reset` - new reset pin to use, defaults to `9` + * `dio0` - new DIO0 pin to use, defaults to `2`. **Must** be interrupt capable via [attachInterrupt(...)](https://www.arduino.cc/en/Reference/AttachInterrupt). + +This call is optional and only needs to be used if you need to change the default pins used. + +#### No MCU controlled reset pin + +To save further pins one could connect the reset pin of the MCU with reset pin of the radio thus resetting only during startup. + +* `reset` - set to `-1` to omit this pin + +#### Pin dio0 interrupt callbacks + +The dio0 pin can be used for channel activity detection callback, transmission finish callback and/or receiving callback, check `onCadDone` , `onTxDone`, and `onReceive`. + +### Set SPI interface + +Override the default SPI interface used by the library. **Must** be called before `LoRa.begin()`. + +```arduino +LoRa.setSPI(spi); +``` + * `spi` - new SPI interface to use, defaults to `SPI` + +This call is optional and only needs to be used if you need to change the default SPI interface used, in the case your Arduino (or compatible) board has more than one SPI interface present. + +### Set SPI Frequency + +Override the default SPI frequency of 10 MHz used by the library. **Must** be called before `LoRa.begin()`. + +```arduino +LoRa.setSPIFrequency(frequency); +``` + * `frequency` - new SPI frequency to use, defaults to `8E6` + +This call is optional and only needs to be used if you need to change the default SPI frequency used. Some logic level converters cannot support high speeds such as 8 MHz, so a lower SPI frequency can be selected with `LoRa.setSPIFrequency(frequency)`. + +### End + +Stop the library + +```arduino +LoRa.end() +``` + +## Sending data + +### Begin packet + +Start the sequence of sending a packet. + +```arduino +LoRa.beginPacket(); + +LoRa.beginPacket(implicitHeader); +``` + + * `implicitHeader` - (optional) `true` enables implicit header mode, `false` enables explicit header mode (default) + +Returns `1` if radio is ready to transmit, `0` if busy or on failure. + +### Writing + +Write data to the packet. Each packet can contain up to 255 bytes. + +```arduino +LoRa.write(byte); + +LoRa.write(buffer, length); +``` +* `byte` - single byte to write to packet + +or + +* `buffer` - data to write to packet +* `length` - size of data to write + +Returns the number of bytes written. + +**Note:** Other Arduino `Print` API's can also be used to write data into the packet + +### End packet + +End the sequence of sending a packet. + +```arduino +LoRa.endPacket(); + +LoRa.endPacket(async); +``` + * `async` - (optional) `true` enables non-blocking mode, `false` waits for transmission to be completed (default) + +Returns `1` on success, `0` on failure. + +### Tx Done + +**WARNING**: TxDone callback uses the interrupt pin on the `dio0` check `setPins` function! + +### Register callback + +Register a callback function for when a packet transmission finish. + +```arduino +LoRa.onTxDone(onTxDone); + +void onTxDone() { + // ... +} +``` + + * `onTxDone` - function to call when a packet transmission finish. + +## Receiving data + +### Parsing packet + +Check if a packet has been received. + +```arduino +int packetSize = LoRa.parsePacket(); + +int packetSize = LoRa.parsePacket(size); +``` + + * `size` - (optional) if `> 0` implicit header mode is enabled with the expected a packet of `size` bytes, default mode is explicit header mode + + +Returns the packet size in bytes or `0` if no packet was received. + +### Continuous receive mode + +**WARNING**: Receive callback uses the interrupt pin on the `dio0`, check `setPins` function! + +#### Register callback + +Register a callback function for when a packet is received. + +```arduino +LoRa.onReceive(onReceive); + +void onReceive(int packetSize) { + // ... +} +``` + + * `onReceive` - function to call when a packet is received. + +#### Receive mode + +Puts the radio in continuous receive mode. + +```arduino +LoRa.receive(); + +LoRa.receive(int size); +``` + + * `size` - (optional) if `> 0` implicit header mode is enabled with the expected a packet of `size` bytes, default mode is explicit header mode + +The `onReceive` callback will be called when a packet is received. + +### Packet RSSI + +```arduino +int rssi = LoRa.packetRssi(); +``` + +Returns the averaged RSSI of the last received packet (dBm). + +### Packet SNR + +```arduino +float snr = LoRa.packetSnr(); +``` + +Returns the estimated SNR of the received packet in dB. + +## RSSI + +```arduino +int rssi = LoRa.rssi(); +``` + +Returns the current RSSI of the radio (dBm). RSSI can be read at any time (during packet reception or not) + +### Packet Frequency Error + +```arduino +long freqErr = LoRa.packetFrequencyError(); +``` + +Returns the frequency error of the received packet in Hz. The frequency error is the frequency offset between the receiver centre frequency and that of an incoming LoRa signal. + +### Available + +```arduino +int availableBytes = LoRa.available() +``` + +Returns number of bytes available for reading. + +### Peeking + +Peek at the next byte in the packet. + +```arduino +byte b = LoRa.peek(); +``` + +Returns the next byte in the packet or `-1` if no bytes are available. + +### Reading + +Read the next byte from the packet. + +```arduino +byte b = LoRa.read(); +``` + +Returns the next byte in the packet or `-1` if no bytes are available. + +**Note:** Other Arduino [`Stream` API's](https://www.arduino.cc/en/Reference/Stream) can also be used to read data from the packet + +## Channel Activity Detection +**WARNING**: Channel activity detection callback uses the interrupt pin on the `dio0`, check `setPins` function! + +### Register callback + +Register a callback function for when channel activity detection has done. +```arduino +LoRa.onCadDone(onCadDone); + +void onCadDone(boolean signalDetected) { + // ... +} +``` + * `onCadDone` - function to call when channel activity detection has done. + * `signalDetected` - if `true`, the radio detects the presence of other LoRa signals. + +### Channel Activity detection mode +Puts the radio in channel activity detection mode. +```arduino +LoRa.channelActivityDetection(); +``` +## Other radio modes + +### Idle mode + +Put the radio in idle (standby) mode. + +```arduino +LoRa.idle(); +``` + +### Sleep mode + +Put the radio in sleep mode. + +```arduino +LoRa.sleep(); +``` + +## Radio parameters + +### TX Power + +Change the TX power of the radio. + +```arduino +LoRa.setTxPower(txPower); + +LoRa.setTxPower(txPower, outputPin); +``` + * `txPower` - TX power in dB, defaults to `17` + * `outputPin` - (optional) PA output pin, supported values are `PA_OUTPUT_RFO_PIN` and `PA_OUTPUT_PA_BOOST_PIN`, defaults to `PA_OUTPUT_PA_BOOST_PIN`. + +Supported values are `2` to `20` for `PA_OUTPUT_PA_BOOST_PIN`, and `0` to `14` for `PA_OUTPUT_RFO_PIN`. + +Most modules have the PA output pin connected to PA BOOST, + +### Frequency + +Change the frequency of the radio. + +```arduino +LoRa.setFrequency(frequency); +``` + * `frequency` - frequency in Hz (`433E6`, `868E6`, `915E6`) + +### Spreading Factor + +Change the spreading factor of the radio. + +```arduino +LoRa.setSpreadingFactor(spreadingFactor); +``` + * `spreadingFactor` - spreading factor, defaults to `7` + +Supported values are between `6` and `12`. If a spreading factor of `6` is set, implicit header mode must be used to transmit and receive packets. + +### Signal Bandwidth + +Change the signal bandwidth of the radio. + +```arduino +LoRa.setSignalBandwidth(signalBandwidth); +``` + + * `signalBandwidth` - signal bandwidth in Hz, defaults to `125E3`. + +Supported values are `7.8E3`, `10.4E3`, `15.6E3`, `20.8E3`, `31.25E3`, `41.7E3`, `62.5E3`, `125E3`, `250E3`, and `500E3`. + +### Coding Rate + +Change the coding rate of the radio. + +```arduino +LoRa.setCodingRate4(codingRateDenominator); +``` + + * `codingRateDenominator` - denominator of the coding rate, defaults to `5` + +Supported values are between `5` and `8`, these correspond to coding rates of `4/5` and `4/8`. The coding rate numerator is fixed at `4`. + +### Preamble Length + +Change the preamble length of the radio. + +```arduino +LoRa.setPreambleLength(preambleLength); +``` + + * `preambleLength` - preamble length in symbols, defaults to `8` + +Supported values are between `6` and `65535`. + +### Sync Word + +Change the sync word of the radio. + +```arduino +LoRa.setSyncWord(syncWord); +``` + + * `syncWord` - byte value to use as the sync word, defaults to `0x12` + +### CRC + +Enable or disable CRC usage, by default a CRC is not used. + +```arduino +LoRa.enableCrc(); + +LoRa.disableCrc(); +``` + +### Invert IQ Signals + +Enable or disable Invert the LoRa I and Q signals, by default a invertIQ is not used. + +```arduino +LoRa.enableInvertIQ(); + +LoRa.disableInvertIQ(); +``` +### LNA Gain + +Set LNA Gain for better RX sensitivity, by default AGC (Automatic Gain Control) is used and LNA gain is not used. + +```arduino +LoRa.setGain(gain); +``` + + * `gain` - LNA gain + +Supported values are between `0` and `6`. If gain is 0, AGC will be enabled and LNA gain will not be used. Else if gain is from 1 to 6, AGC will be disabled and LNA gain will be used. + +## Other functions + +### Random + +Generate a random byte, based on the Wideband RSSI measurement. + +``` +byte b = LoRa.random(); +``` + +Returns random byte. diff --git a/lib/lib_rf/LoRa/LICENSE b/lib/lib_rf/LoRa/LICENSE new file mode 100644 index 000000000..1e85b9507 --- /dev/null +++ b/lib/lib_rf/LoRa/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Sandeep Mistry + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/lib_rf/LoRa/README.md b/lib/lib_rf/LoRa/README.md new file mode 100644 index 000000000..9663b616a --- /dev/null +++ b/lib/lib_rf/LoRa/README.md @@ -0,0 +1,91 @@ +# Arduino LoRa + +[![Build Status](https://travis-ci.org/sandeepmistry/arduino-LoRa.svg?branch=master)](https://travis-ci.org/sandeepmistry/arduino-LoRa) + +An [Arduino](https://arduino.cc/) library for sending and receiving data using [LoRa](https://www.lora-alliance.org/) radios. + +## Compatible Hardware + + * [Semtech SX1276/77/78/79](https://www.semtech.com/products/wireless-rf/lora-connect/sx1276) based boards including: + * [Dragino Lora Shield](https://www.dragino.com/products/lora/item/102-lora-shield.html) + * [HopeRF](https://www.hoperf.com/modules/lora/index.html) [RFM95W](https://www.hoperf.com/modules/lora/RFM95.html), [RFM96W](https://www.hoperf.com/modules/lora/RFM96.html), and [RFM98W](https://www.hoperf.com/modules/lora/RFM98.html) + * [Modtronix](http://modtronix.com/) [inAir4](http://modtronix.com/inair4.html), [inAir9](http://modtronix.com/inair9.html), and [inAir9B](http://modtronix.com/inair9b.html) + * [Arduino MKR WAN 1300](https://store.arduino.cc/usa/mkr-wan-1300) + * **NOTE:** Requires firmware v1.1.6 or later on the on-board Murata module. Please use the [MKRWANFWUpdate_standalone example](https://github.com/arduino-libraries/MKRWAN/blob/master/examples/MKRWANFWUpdate_standalone/MKRWANFWUpdate_standalone.ino) from latest [MKRWAN library](https://github.com/arduino-libraries/MKRWAN) release to update the firmware. + * **WARNING**: [LoRa.onReceive(...)](https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md#register-callback) and [LoRa.recieve()](https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md#receive-mode) is not compatible with this board! + +### Semtech SX1276/77/78/79 wiring + +| Semtech SX1276/77/78/79 | Arduino | +| :---------------------: | :------:| +| VCC | 3.3V | +| GND | GND | +| SCK | SCK | +| MISO | MISO | +| MOSI | MOSI | +| NSS | 10 | +| NRESET | 9 | +| DIO0 | 2 | + + +`NSS`, `NRESET`, and `DIO0` pins can be changed by using `LoRa.setPins(ss, reset, dio0)`. `DIO0` pin is optional, it is only needed for receive callback mode. If `DIO0` pin is used, it **must** be interrupt capable via [`attachInterrupt(...)`](https://www.arduino.cc/en/Reference/AttachInterrupt). + +**NOTES**: + * Some boards (like the Arduino Nano), cannot supply enough current for the SX127x in TX mode. This will cause lockups when sending, be sure to use an external 3.3V supply that can provide at least 120mA's when using these boards. + * If your Arduino board operates at 5V, like the Arduino Uno, Leonardo or Mega, you will need to use a level converter for the wiring to the Semtech SX127x module. Most Semtech SX127x breakout boards do not have logic level converters built-in. + +## Installation + +### Using the Arduino IDE Library Manager + +1. Choose `Sketch` -> `Include Library` -> `Manage Libraries...` +2. Type `LoRa` into the search box. +3. Click the row to select the library. +4. Click the `Install` button to install the library. + +### Using Git + +```sh +cd ~/Documents/Arduino/libraries/ +git clone https://github.com/sandeepmistry/arduino-LoRa LoRa +``` + +## API + +See [API.md](API.md). + +## Examples + +See [examples](examples) folder. + +## FAQ + +**1) Initilizating the LoRa radio is failing** + +Please check the wiring you are using matches what's listed in [Semtech SX1276/77/78/79 wiring](#semtech-sx1276777879-wiring). You can also use `LoRa.setPins(ss, reset, dio0)` to change the default pins used. Some logic level converters cannot operate at 8 MHz, you can call `LoRa.setSPIFrequency(frequency)` to lower the SPI frequency used by the library. Both API's must be called before `LoRa.begin(...)`. + +**2) Can other radios see the packets I'm sending?** + +Yes, any LoRa radio that are configured with the same radio parameters and in range can see the packets you send. + +**3) Is the data I'm sending encrypted?** + +No, all data is sent unencrypted. If want your packet data to be encrypted, you must encrypt it before passing it into this library, followed by decrypting on the receiving end. + +**4) How does this library differ from LoRaWAN libraries?** + +This library exposes the LoRa radio directly, and allows you to send data to any radios in range with same radio parameters. All data is broadcasted and there is no addressing. LoRaWAN builds on top of LoRA, but adds addressing, encryption, and additional layers. It also requires a LoRaWAN gateway and LoRaWAN network and application server. + +**5) Does this library honor duty cycles?** + +No, you have to manage it by your self. + +**6) Which frequencies can I use?** + +You can use [this table](https://www.thethingsnetwork.org/wiki/LoRaWAN/Frequencies/By-Country) to lookup the available frequencies by your country. The selectable frequency also depends on your hardware. You can lookup the data sheet or ask your supplier. + +Please also notice the frequency dependent duty cycles for legal reasons! + +## License + +This libary is [licensed](LICENSE) under the [MIT Licence](https://en.wikipedia.org/wiki/MIT_License). diff --git a/lib/lib_rf/LoRa/examples/LoRaCADCallback/LoRaCADCallback.ino b/lib/lib_rf/LoRa/examples/LoRaCADCallback/LoRaCADCallback.ino new file mode 100644 index 000000000..b3bead267 --- /dev/null +++ b/lib/lib_rf/LoRa/examples/LoRaCADCallback/LoRaCADCallback.ino @@ -0,0 +1,58 @@ +#include +#include "LoRa.h" + +#ifdef ARDUINO_SAMD_MKRWAN1300 +#error "This example is not compatible with the Arduino MKR WAN 1300 board!" +#endif + +void setup() { + Serial.begin(9600); + while (!Serial); + + Serial.println("LoRa Receiver Callback"); + + if (!LoRa.begin(915E6)) { + Serial.println("Starting LoRa failed!"); + while (1); + } + + // register the channel activity dectection callback + LoRa.onCadDone(onCadDone); + // register the receive callback + LoRa.onReceive(onReceive); + // put the radio into CAD mode + LoRa.channelActivityDetection(); +} + +void loop() { + // do nothing +} + +void onCadDone(boolean signalDetected) { + // detect preamble + if (signalDetected) { + Serial.println("Signal detected"); + // put the radio into continuous receive mode + LoRa.receive(); + } else { + // try next activity dectection + LoRa.channelActivityDetection(); + } +} + +void onReceive(int packetSize) { + // received a packet + Serial.print("Received packet '"); + + // read packet + for (int i = 0; i < packetSize; i++) { + Serial.print((char)LoRa.read()); + } + + // print RSSI of packet + Serial.print("' with RSSI "); + Serial.println(LoRa.packetRssi()); + + // put the radio into CAD mode + LoRa.channelActivityDetection(); +} diff --git a/lib/lib_rf/LoRa/examples/LoRaDumpRegisters/LoRaDumpRegisters.ino b/lib/lib_rf/LoRa/examples/LoRaDumpRegisters/LoRaDumpRegisters.ino new file mode 100644 index 000000000..5a23d2eea --- /dev/null +++ b/lib/lib_rf/LoRa/examples/LoRaDumpRegisters/LoRaDumpRegisters.ino @@ -0,0 +1,30 @@ +/* + LoRa register dump + + This examples shows how to inspect and output the LoRa radio's + registers on the Serial interface +*/ +#include // include libraries +#include + +void setup() { + Serial.begin(9600); // initialize serial + while (!Serial); + + Serial.println("LoRa Dump Registers"); + + // override the default CS, reset, and IRQ pins (optional) + // LoRa.setPins(7, 6, 1); // set CS, reset, IRQ pin + + if (!LoRa.begin(915E6)) { // initialize ratio at 915 MHz + Serial.println("LoRa init failed. Check your connections."); + while (true); // if failed, do nothing + } + + LoRa.dumpRegisters(Serial); +} + + +void loop() { +} + diff --git a/lib/lib_rf/LoRa/examples/LoRaDuplex/LoRaDuplex.ino b/lib/lib_rf/LoRa/examples/LoRaDuplex/LoRaDuplex.ino new file mode 100644 index 000000000..c914254f9 --- /dev/null +++ b/lib/lib_rf/LoRa/examples/LoRaDuplex/LoRaDuplex.ino @@ -0,0 +1,106 @@ +/* + LoRa Duplex communication + + Sends a message every half second, and polls continually + for new incoming messages. Implements a one-byte addressing scheme, + with 0xFF as the broadcast address. + + Uses readString() from Stream class to read payload. The Stream class' + timeout may affect other functuons, like the radio's callback. For an + + created 28 April 2017 + by Tom Igoe +*/ +#include // include libraries +#include + +const int csPin = 7; // LoRa radio chip select +const int resetPin = 6; // LoRa radio reset +const int irqPin = 1; // change for your board; must be a hardware interrupt pin + +String outgoing; // outgoing message + +byte msgCount = 0; // count of outgoing messages +byte localAddress = 0xBB; // address of this device +byte destination = 0xFF; // destination to send to +long lastSendTime = 0; // last send time +int interval = 2000; // interval between sends + +void setup() { + Serial.begin(9600); // initialize serial + while (!Serial); + + Serial.println("LoRa Duplex"); + + // override the default CS, reset, and IRQ pins (optional) + LoRa.setPins(csPin, resetPin, irqPin);// set CS, reset, IRQ pin + + if (!LoRa.begin(915E6)) { // initialize ratio at 915 MHz + Serial.println("LoRa init failed. Check your connections."); + while (true); // if failed, do nothing + } + + Serial.println("LoRa init succeeded."); +} + +void loop() { + if (millis() - lastSendTime > interval) { + String message = "HeLoRa World!"; // send a message + sendMessage(message); + Serial.println("Sending " + message); + lastSendTime = millis(); // timestamp the message + interval = random(2000) + 1000; // 2-3 seconds + } + + // parse for a packet, and call onReceive with the result: + onReceive(LoRa.parsePacket()); +} + +void sendMessage(String outgoing) { + LoRa.beginPacket(); // start packet + LoRa.write(destination); // add destination address + LoRa.write(localAddress); // add sender address + LoRa.write(msgCount); // add message ID + LoRa.write(outgoing.length()); // add payload length + LoRa.print(outgoing); // add payload + LoRa.endPacket(); // finish packet and send it + msgCount++; // increment message ID +} + +void onReceive(int packetSize) { + if (packetSize == 0) return; // if there's no packet, return + + // read packet header bytes: + int recipient = LoRa.read(); // recipient address + byte sender = LoRa.read(); // sender address + byte incomingMsgId = LoRa.read(); // incoming msg ID + byte incomingLength = LoRa.read(); // incoming msg length + + String incoming = ""; + + while (LoRa.available()) { + incoming += (char)LoRa.read(); + } + + if (incomingLength != incoming.length()) { // check length for error + Serial.println("error: message length does not match length"); + return; // skip rest of function + } + + // if the recipient isn't this device or broadcast, + if (recipient != localAddress && recipient != 0xFF) { + Serial.println("This message is not for me."); + return; // skip rest of function + } + + // if message is for this device, or broadcast, print details: + Serial.println("Received from: 0x" + String(sender, HEX)); + Serial.println("Sent to: 0x" + String(recipient, HEX)); + Serial.println("Message ID: " + String(incomingMsgId)); + Serial.println("Message length: " + String(incomingLength)); + Serial.println("Message: " + incoming); + Serial.println("RSSI: " + String(LoRa.packetRssi())); + Serial.println("Snr: " + String(LoRa.packetSnr())); + Serial.println(); +} + diff --git a/lib/lib_rf/LoRa/examples/LoRaDuplexCallback/LoRaDuplexCallback.ino b/lib/lib_rf/LoRa/examples/LoRaDuplexCallback/LoRaDuplexCallback.ino new file mode 100644 index 000000000..0511f3ebb --- /dev/null +++ b/lib/lib_rf/LoRa/examples/LoRaDuplexCallback/LoRaDuplexCallback.ino @@ -0,0 +1,110 @@ +/* + LoRa Duplex communication wth callback + + Sends a message every half second, and uses callback + for new incoming messages. Implements a one-byte addressing scheme, + with 0xFF as the broadcast address. + + Note: while sending, LoRa radio is not listening for incoming messages. + Note2: when using the callback method, you can't use any of the Stream + functions that rely on the timeout, such as readString, parseInt(), etc. + + created 28 April 2017 + by Tom Igoe +*/ +#include // include libraries +#include + +#ifdef ARDUINO_SAMD_MKRWAN1300 +#error "This example is not compatible with the Arduino MKR WAN 1300 board!" +#endif + +const int csPin = 7; // LoRa radio chip select +const int resetPin = 6; // LoRa radio reset +const int irqPin = 1; // change for your board; must be a hardware interrupt pin + +String outgoing; // outgoing message +byte msgCount = 0; // count of outgoing messages +byte localAddress = 0xBB; // address of this device +byte destination = 0xFF; // destination to send to +long lastSendTime = 0; // last send time +int interval = 2000; // interval between sends + +void setup() { + Serial.begin(9600); // initialize serial + while (!Serial); + + Serial.println("LoRa Duplex with callback"); + + // override the default CS, reset, and IRQ pins (optional) + LoRa.setPins(csPin, resetPin, irqPin);// set CS, reset, IRQ pin + + if (!LoRa.begin(915E6)) { // initialize ratio at 915 MHz + Serial.println("LoRa init failed. Check your connections."); + while (true); // if failed, do nothing + } + + LoRa.onReceive(onReceive); + LoRa.receive(); + Serial.println("LoRa init succeeded."); +} + +void loop() { + if (millis() - lastSendTime > interval) { + String message = "HeLoRa World!"; // send a message + sendMessage(message); + Serial.println("Sending " + message); + lastSendTime = millis(); // timestamp the message + interval = random(2000) + 1000; // 2-3 seconds + LoRa.receive(); // go back into receive mode + } +} + +void sendMessage(String outgoing) { + LoRa.beginPacket(); // start packet + LoRa.write(destination); // add destination address + LoRa.write(localAddress); // add sender address + LoRa.write(msgCount); // add message ID + LoRa.write(outgoing.length()); // add payload length + LoRa.print(outgoing); // add payload + LoRa.endPacket(); // finish packet and send it + msgCount++; // increment message ID +} + +void onReceive(int packetSize) { + if (packetSize == 0) return; // if there's no packet, return + + // read packet header bytes: + int recipient = LoRa.read(); // recipient address + byte sender = LoRa.read(); // sender address + byte incomingMsgId = LoRa.read(); // incoming msg ID + byte incomingLength = LoRa.read(); // incoming msg length + + String incoming = ""; // payload of packet + + while (LoRa.available()) { // can't use readString() in callback, so + incoming += (char)LoRa.read(); // add bytes one by one + } + + if (incomingLength != incoming.length()) { // check length for error + Serial.println("error: message length does not match length"); + return; // skip rest of function + } + + // if the recipient isn't this device or broadcast, + if (recipient != localAddress && recipient != 0xFF) { + Serial.println("This message is not for me."); + return; // skip rest of function + } + + // if message is for this device, or broadcast, print details: + Serial.println("Received from: 0x" + String(sender, HEX)); + Serial.println("Sent to: 0x" + String(recipient, HEX)); + Serial.println("Message ID: " + String(incomingMsgId)); + Serial.println("Message length: " + String(incomingLength)); + Serial.println("Message: " + incoming); + Serial.println("RSSI: " + String(LoRa.packetRssi())); + Serial.println("Snr: " + String(LoRa.packetSnr())); + Serial.println(); +} + diff --git a/lib/lib_rf/LoRa/examples/LoRaReceiver/LoRaReceiver.ino b/lib/lib_rf/LoRa/examples/LoRaReceiver/LoRaReceiver.ino new file mode 100644 index 000000000..ccbb453f1 --- /dev/null +++ b/lib/lib_rf/LoRa/examples/LoRaReceiver/LoRaReceiver.ino @@ -0,0 +1,32 @@ +#include +#include + +void setup() { + Serial.begin(9600); + while (!Serial); + + Serial.println("LoRa Receiver"); + + if (!LoRa.begin(915E6)) { + Serial.println("Starting LoRa failed!"); + while (1); + } +} + +void loop() { + // try to parse packet + int packetSize = LoRa.parsePacket(); + if (packetSize) { + // received a packet + Serial.print("Received packet '"); + + // read packet + while (LoRa.available()) { + Serial.print((char)LoRa.read()); + } + + // print RSSI of packet + Serial.print("' with RSSI "); + Serial.println(LoRa.packetRssi()); + } +} diff --git a/lib/lib_rf/LoRa/examples/LoRaReceiverCallback/LoRaReceiverCallback.ino b/lib/lib_rf/LoRa/examples/LoRaReceiverCallback/LoRaReceiverCallback.ino new file mode 100644 index 000000000..ff3231807 --- /dev/null +++ b/lib/lib_rf/LoRa/examples/LoRaReceiverCallback/LoRaReceiverCallback.ino @@ -0,0 +1,45 @@ +#include +#include + +#ifdef ARDUINO_SAMD_MKRWAN1300 +#error "This example is not compatible with the Arduino MKR WAN 1300 board!" +#endif + +void setup() { + Serial.begin(9600); + while (!Serial); + + Serial.println("LoRa Receiver Callback"); + + if (!LoRa.begin(915E6)) { + Serial.println("Starting LoRa failed!"); + while (1); + } + + // Uncomment the next line to disable the default AGC and set LNA gain, values between 1 - 6 are supported + // LoRa.setGain(6); + + // register the receive callback + LoRa.onReceive(onReceive); + + // put the radio into receive mode + LoRa.receive(); +} + +void loop() { + // do nothing +} + +void onReceive(int packetSize) { + // received a packet + Serial.print("Received packet '"); + + // read packet + for (int i = 0; i < packetSize; i++) { + Serial.print((char)LoRa.read()); + } + + // print RSSI of packet + Serial.print("' with RSSI "); + Serial.println(LoRa.packetRssi()); +} diff --git a/lib/lib_rf/LoRa/examples/LoRaSender/LoRaSender.ino b/lib/lib_rf/LoRa/examples/LoRaSender/LoRaSender.ino new file mode 100644 index 000000000..a252ee5f6 --- /dev/null +++ b/lib/lib_rf/LoRa/examples/LoRaSender/LoRaSender.ino @@ -0,0 +1,31 @@ +#include +#include + +int counter = 0; + +void setup() { + Serial.begin(9600); + while (!Serial); + + Serial.println("LoRa Sender"); + + if (!LoRa.begin(915E6)) { + Serial.println("Starting LoRa failed!"); + while (1); + } +} + +void loop() { + Serial.print("Sending packet: "); + Serial.println(counter); + + // send packet + LoRa.beginPacket(); + LoRa.print("hello "); + LoRa.print(counter); + LoRa.endPacket(); + + counter++; + + delay(5000); +} diff --git a/lib/lib_rf/LoRa/examples/LoRaSenderNonBlocking/LoRaSenderNonBlocking.ino b/lib/lib_rf/LoRa/examples/LoRaSenderNonBlocking/LoRaSenderNonBlocking.ino new file mode 100644 index 000000000..0f3907754 --- /dev/null +++ b/lib/lib_rf/LoRa/examples/LoRaSenderNonBlocking/LoRaSenderNonBlocking.ino @@ -0,0 +1,35 @@ +#include +#include + +int counter = 0; + +void setup() { + Serial.begin(9600); + while (!Serial); + + Serial.println("LoRa Sender non-blocking"); + + if (!LoRa.begin(915E6)) { + Serial.println("Starting LoRa failed!"); + while (1); + } +} + +void loop() { + // wait until the radio is ready to send a packet + while (LoRa.beginPacket() == 0) { + Serial.print("waiting for radio ... "); + delay(100); + } + + Serial.print("Sending packet non-blocking: "); + Serial.println(counter); + + // send in async / non-blocking mode + LoRa.beginPacket(); + LoRa.print("hello "); + LoRa.print(counter); + LoRa.endPacket(true); // true = async / non-blocking mode + + counter++; +} diff --git a/lib/lib_rf/LoRa/examples/LoRaSenderNonBlockingCallback/LoRaSenderNonBlockingCallback.ino b/lib/lib_rf/LoRa/examples/LoRaSenderNonBlockingCallback/LoRaSenderNonBlockingCallback.ino new file mode 100644 index 000000000..aa7949982 --- /dev/null +++ b/lib/lib_rf/LoRa/examples/LoRaSenderNonBlockingCallback/LoRaSenderNonBlockingCallback.ino @@ -0,0 +1,50 @@ +#include +#include + +int counter = 0; + +void setup() { + Serial.begin(9600); + while (!Serial); + + Serial.println("LoRa Sender non-blocking Callback"); + + if (!LoRa.begin(915E6)) { + Serial.println("Starting LoRa failed!"); + while (1); + } + + LoRa.onTxDone(onTxDone); +} + +void loop() { + if (runEvery(5000)) { // repeat every 5000 millis + + Serial.print("Sending packet non-blocking: "); + Serial.println(counter); + + // send in async / non-blocking mode + LoRa.beginPacket(); + LoRa.print("hello "); + LoRa.print(counter); + LoRa.endPacket(true); // true = async / non-blocking mode + + counter++; + } +} + +void onTxDone() { + Serial.println("TxDone"); +} + +boolean runEvery(unsigned long interval) +{ + static unsigned long previousMillis = 0; + unsigned long currentMillis = millis(); + if (currentMillis - previousMillis >= interval) + { + previousMillis = currentMillis; + return true; + } + return false; +} diff --git a/lib/lib_rf/LoRa/examples/LoRaSetSpread/LoRaSetSpread.ino b/lib/lib_rf/LoRa/examples/LoRaSetSpread/LoRaSetSpread.ino new file mode 100644 index 000000000..09fec54b8 --- /dev/null +++ b/lib/lib_rf/LoRa/examples/LoRaSetSpread/LoRaSetSpread.ino @@ -0,0 +1,87 @@ +/* + LoRa Duplex communication with Spreading Factor + + Sends a message every half second, and polls continually + for new incoming messages. Sets the LoRa radio's spreading factor. + + Spreading factor affects how far apart the radio's transmissions + are, across the available bandwidth. Radios with different spreading + factors will not receive each other's transmissions. This is one way you + can filter out radios you want to ignore, without making an addressing scheme. + + Spreading factor affects reliability of transmission at high rates, however, + so avoid a huge spreading factor when you're sending continually. + + See the Semtech datasheet, http://www.semtech.com/images/datasheet/sx1276.pdf + for more on Spreading Factor. + + created 28 April 2017 + by Tom Igoe +*/ +#include // include libraries +#include + +const int csPin = 7; // LoRa radio chip select +const int resetPin = 6; // LoRa radio reset +const int irqPin = 1; // change for your board; must be a hardware interrupt pin + +byte msgCount = 0; // count of outgoing messages +int interval = 2000; // interval between sends +long lastSendTime = 0; // time of last packet send + +void setup() { + Serial.begin(9600); // initialize serial + while (!Serial); + + Serial.println("LoRa Duplex - Set spreading factor"); + + // override the default CS, reset, and IRQ pins (optional) + LoRa.setPins(csPin, resetPin, irqPin); // set CS, reset, IRQ pin + + if (!LoRa.begin(915E6)) { // initialize ratio at 915 MHz + Serial.println("LoRa init failed. Check your connections."); + while (true); // if failed, do nothing + } + + LoRa.setSpreadingFactor(8); // ranges from 6-12,default 7 see API docs + Serial.println("LoRa init succeeded."); +} + +void loop() { + if (millis() - lastSendTime > interval) { + String message = "HeLoRa World! "; // send a message + message += msgCount; + sendMessage(message); + Serial.println("Sending " + message); + lastSendTime = millis(); // timestamp the message + interval = random(2000) + 1000; // 2-3 seconds + msgCount++; + } + + // parse for a packet, and call onReceive with the result: + onReceive(LoRa.parsePacket()); +} + +void sendMessage(String outgoing) { + LoRa.beginPacket(); // start packet + LoRa.print(outgoing); // add payload + LoRa.endPacket(); // finish packet and send it + msgCount++; // increment message ID +} + +void onReceive(int packetSize) { + if (packetSize == 0) return; // if there's no packet, return + + // read packet header bytes: + String incoming = ""; + + while (LoRa.available()) { + incoming += (char)LoRa.read(); + } + + Serial.println("Message: " + incoming); + Serial.println("RSSI: " + String(LoRa.packetRssi())); + Serial.println("Snr: " + String(LoRa.packetSnr())); + Serial.println(); +} + diff --git a/lib/lib_rf/LoRa/examples/LoRaSetSyncWord/LoRaSetSyncWord.ino b/lib/lib_rf/LoRa/examples/LoRaSetSyncWord/LoRaSetSyncWord.ino new file mode 100644 index 000000000..1e2c4b71f --- /dev/null +++ b/lib/lib_rf/LoRa/examples/LoRaSetSyncWord/LoRaSetSyncWord.ino @@ -0,0 +1,82 @@ +/* + LoRa Duplex communication with Sync Word + + Sends a message every half second, and polls continually + for new incoming messages. Sets the LoRa radio's Sync Word. + + The Sync Word is basically the radio's network ID. Radios with different + Sync Words will not receive each other's transmissions. This is one way you + can filter out radios you want to ignore, without making an addressing scheme. + + See the Semtech datasheet, http://www.semtech.com/images/datasheet/sx1276.pdf + for more on Sync Word. + + created 28 April 2017 + by Tom Igoe +*/ +#include // include libraries +#include +const int csPin = 7; // LoRa radio chip select +const int resetPin = 6; // LoRa radio reset +const int irqPin = 1; // change for your board; must be a hardware interrupt pin + +byte msgCount = 0; // count of outgoing messages +int interval = 2000; // interval between sends +long lastSendTime = 0; // time of last packet send + +void setup() { + Serial.begin(9600); // initialize serial + while (!Serial); + + Serial.println("LoRa Duplex - Set sync word"); + + // override the default CS, reset, and IRQ pins (optional) + LoRa.setPins(csPin, resetPin, irqPin);// set CS, reset, IRQ pin + + if (!LoRa.begin(915E6)) { // initialize ratio at 915 MHz + Serial.println("LoRa init failed. Check your connections."); + while (true); // if failed, do nothing + } + + LoRa.setSyncWord(0xF3); // ranges from 0-0xFF, default 0x34, see API docs + Serial.println("LoRa init succeeded."); +} + +void loop() { + if (millis() - lastSendTime > interval) { + String message = "HeLoRa World! "; // send a message + message += msgCount; + sendMessage(message); + Serial.println("Sending " + message); + lastSendTime = millis(); // timestamp the message + interval = random(2000) + 1000; // 2-3 seconds + msgCount++; + } + + // parse for a packet, and call onReceive with the result: + onReceive(LoRa.parsePacket()); +} + +void sendMessage(String outgoing) { + LoRa.beginPacket(); // start packet + LoRa.print(outgoing); // add payload + LoRa.endPacket(); // finish packet and send it + msgCount++; // increment message ID +} + +void onReceive(int packetSize) { + if (packetSize == 0) return; // if there's no packet, return + + // read packet header bytes: + String incoming = ""; + + while (LoRa.available()) { + incoming += (char)LoRa.read(); + } + + Serial.println("Message: " + incoming); + Serial.println("RSSI: " + String(LoRa.packetRssi())); + Serial.println("Snr: " + String(LoRa.packetSnr())); + Serial.println(); +} + diff --git a/lib/lib_rf/LoRa/examples/LoRaSimpleGateway/LoRaSimpleGateway.ino b/lib/lib_rf/LoRa/examples/LoRaSimpleGateway/LoRaSimpleGateway.ino new file mode 100644 index 000000000..95d84a72d --- /dev/null +++ b/lib/lib_rf/LoRa/examples/LoRaSimpleGateway/LoRaSimpleGateway.ino @@ -0,0 +1,117 @@ +/* + LoRa Simple Gateway/Node Exemple + + This code uses InvertIQ function to create a simple Gateway/Node logic. + + Gateway - Sends messages with enableInvertIQ() + - Receives messages with disableInvertIQ() + + Node - Sends messages with disableInvertIQ() + - Receives messages with enableInvertIQ() + + With this arrangement a Gateway never receive messages from another Gateway + and a Node never receive message from another Node. + Only Gateway to Node and vice versa. + + This code receives messages and sends a message every second. + + InvertIQ function basically invert the LoRa I and Q signals. + + See the Semtech datasheet, http://www.semtech.com/images/datasheet/sx1276.pdf + for more on InvertIQ register 0x33. + + created 05 August 2018 + by Luiz H. Cassettari +*/ + +#include // include libraries +#include + +const long frequency = 915E6; // LoRa Frequency + +const int csPin = 10; // LoRa radio chip select +const int resetPin = 9; // LoRa radio reset +const int irqPin = 2; // change for your board; must be a hardware interrupt pin + +void setup() { + Serial.begin(9600); // initialize serial + while (!Serial); + + LoRa.setPins(csPin, resetPin, irqPin); + + if (!LoRa.begin(frequency)) { + Serial.println("LoRa init failed. Check your connections."); + while (true); // if failed, do nothing + } + + Serial.println("LoRa init succeeded."); + Serial.println(); + Serial.println("LoRa Simple Gateway"); + Serial.println("Only receive messages from nodes"); + Serial.println("Tx: invertIQ enable"); + Serial.println("Rx: invertIQ disable"); + Serial.println(); + + LoRa.onReceive(onReceive); + LoRa.onTxDone(onTxDone); + LoRa_rxMode(); +} + +void loop() { + if (runEvery(5000)) { // repeat every 5000 millis + + String message = "HeLoRa World! "; + message += "I'm a Gateway! "; + message += millis(); + + LoRa_sendMessage(message); // send a message + + Serial.println("Send Message!"); + } +} + +void LoRa_rxMode(){ + LoRa.disableInvertIQ(); // normal mode + LoRa.receive(); // set receive mode +} + +void LoRa_txMode(){ + LoRa.idle(); // set standby mode + LoRa.enableInvertIQ(); // active invert I and Q signals +} + +void LoRa_sendMessage(String message) { + LoRa_txMode(); // set tx mode + LoRa.beginPacket(); // start packet + LoRa.print(message); // add payload + LoRa.endPacket(true); // finish packet and send it +} + +void onReceive(int packetSize) { + String message = ""; + + while (LoRa.available()) { + message += (char)LoRa.read(); + } + + Serial.print("Gateway Receive: "); + Serial.println(message); +} + +void onTxDone() { + Serial.println("TxDone"); + LoRa_rxMode(); +} + +boolean runEvery(unsigned long interval) +{ + static unsigned long previousMillis = 0; + unsigned long currentMillis = millis(); + if (currentMillis - previousMillis >= interval) + { + previousMillis = currentMillis; + return true; + } + return false; +} + diff --git a/lib/lib_rf/LoRa/examples/LoRaSimpleNode/LoRaSimpleNode.ino b/lib/lib_rf/LoRa/examples/LoRaSimpleNode/LoRaSimpleNode.ino new file mode 100644 index 000000000..db8c6fa98 --- /dev/null +++ b/lib/lib_rf/LoRa/examples/LoRaSimpleNode/LoRaSimpleNode.ino @@ -0,0 +1,117 @@ +/* + LoRa Simple Gateway/Node Exemple + + This code uses InvertIQ function to create a simple Gateway/Node logic. + + Gateway - Sends messages with enableInvertIQ() + - Receives messages with disableInvertIQ() + + Node - Sends messages with disableInvertIQ() + - Receives messages with enableInvertIQ() + + With this arrangement a Gateway never receive messages from another Gateway + and a Node never receive message from another Node. + Only Gateway to Node and vice versa. + + This code receives messages and sends a message every second. + + InvertIQ function basically invert the LoRa I and Q signals. + + See the Semtech datasheet, http://www.semtech.com/images/datasheet/sx1276.pdf + for more on InvertIQ register 0x33. + + created 05 August 2018 + by Luiz H. Cassettari +*/ + +#include // include libraries +#include + +const long frequency = 915E6; // LoRa Frequency + +const int csPin = 10; // LoRa radio chip select +const int resetPin = 9; // LoRa radio reset +const int irqPin = 2; // change for your board; must be a hardware interrupt pin + +void setup() { + Serial.begin(9600); // initialize serial + while (!Serial); + + LoRa.setPins(csPin, resetPin, irqPin); + + if (!LoRa.begin(frequency)) { + Serial.println("LoRa init failed. Check your connections."); + while (true); // if failed, do nothing + } + + Serial.println("LoRa init succeeded."); + Serial.println(); + Serial.println("LoRa Simple Node"); + Serial.println("Only receive messages from gateways"); + Serial.println("Tx: invertIQ disable"); + Serial.println("Rx: invertIQ enable"); + Serial.println(); + + LoRa.onReceive(onReceive); + LoRa.onTxDone(onTxDone); + LoRa_rxMode(); +} + +void loop() { + if (runEvery(1000)) { // repeat every 1000 millis + + String message = "HeLoRa World! "; + message += "I'm a Node! "; + message += millis(); + + LoRa_sendMessage(message); // send a message + + Serial.println("Send Message!"); + } +} + +void LoRa_rxMode(){ + LoRa.enableInvertIQ(); // active invert I and Q signals + LoRa.receive(); // set receive mode +} + +void LoRa_txMode(){ + LoRa.idle(); // set standby mode + LoRa.disableInvertIQ(); // normal mode +} + +void LoRa_sendMessage(String message) { + LoRa_txMode(); // set tx mode + LoRa.beginPacket(); // start packet + LoRa.print(message); // add payload + LoRa.endPacket(true); // finish packet and send it +} + +void onReceive(int packetSize) { + String message = ""; + + while (LoRa.available()) { + message += (char)LoRa.read(); + } + + Serial.print("Node Receive: "); + Serial.println(message); +} + +void onTxDone() { + Serial.println("TxDone"); + LoRa_rxMode(); +} + +boolean runEvery(unsigned long interval) +{ + static unsigned long previousMillis = 0; + unsigned long currentMillis = millis(); + if (currentMillis - previousMillis >= interval) + { + previousMillis = currentMillis; + return true; + } + return false; +} + diff --git a/lib/lib_rf/LoRa/issue_template.md b/lib/lib_rf/LoRa/issue_template.md new file mode 100644 index 000000000..3fa6d74b5 --- /dev/null +++ b/lib/lib_rf/LoRa/issue_template.md @@ -0,0 +1,3 @@ +Are you receiving `Starting LoRa failed` while using the demo code? + +PLEASE see the [FAQ #1](https://github.com/sandeepmistry/arduino-LoRa#faq) about using [setPins](https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md#set-pins) **BEFORE** submitting an issue. diff --git a/lib/lib_rf/LoRa/keywords.txt b/lib/lib_rf/LoRa/keywords.txt new file mode 100644 index 000000000..6b6587256 --- /dev/null +++ b/lib/lib_rf/LoRa/keywords.txt @@ -0,0 +1,68 @@ +####################################### +# Syntax Coloring Map For LoRa +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +LoRa KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +end KEYWORD2 + +beginPacket KEYWORD2 +endPacket KEYWORD2 + +parsePacket KEYWORD2 +packetRssi KEYWORD2 +packetSnr KEYWORD2 +packetFrequencyError KEYWORD2 + +rssi KEYWORD2 + +write KEYWORD2 + +available KEYWORD2 +read KEYWORD2 +peek KEYWORD2 +flush KEYWORD2 + +onReceive KEYWORD2 +onTxDone KEYWORD2 +onCadDone KEYWORD2 +channelActivityDetection KEYWORD2 +receive KEYWORD2 +idle KEYWORD2 +sleep KEYWORD2 + +setTxPower KEYWORD2 +setFrequency KEYWORD2 +setSpreadingFactor KEYWORD2 +setSignalBandwidth KEYWORD2 +setCodingRate4 KEYWORD2 +setPreambleLength KEYWORD2 +setSyncWord KEYWORD2 +enableCrc KEYWORD2 +disableCrc KEYWORD2 +enableInvertIQ KEYWORD2 +disableInvertIQ KEYWORD2 +enableLowDataRateOptimize KEYWORD2 +disableLowDataRateOptimize KEYWORD2 +setGain KEYWORD2 + +random KEYWORD2 +setPins KEYWORD2 +setSPIFrequency KEYWORD2 +dumpRegisters KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +PA_OUTPUT_RFO_PIN LITERAL1 +PA_OUTPUT_PA_BOOST_PIN LITERAL1 diff --git a/lib/lib_rf/LoRa/library.properties b/lib/lib_rf/LoRa/library.properties new file mode 100644 index 000000000..e869420ef --- /dev/null +++ b/lib/lib_rf/LoRa/library.properties @@ -0,0 +1,10 @@ +name=LoRa +version=0.8.0 +author=Sandeep Mistry +maintainer=Sandeep Mistry +sentence=An Arduino library for sending and receiving data using LoRa radios. +paragraph=Supports Semtech SX1276/77/78/79 based boards/shields. +category=Communication +url=https://github.com/sandeepmistry/arduino-LoRa +architectures=* +includes=LoRa.h diff --git a/lib/lib_rf/LoRa/src/LoRa.cpp b/lib/lib_rf/LoRa/src/LoRa.cpp new file mode 100644 index 000000000..0a6332fc3 --- /dev/null +++ b/lib/lib_rf/LoRa/src/LoRa.cpp @@ -0,0 +1,801 @@ +// Copyright (c) Sandeep Mistry. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include + +// registers +#define REG_FIFO 0x00 +#define REG_OP_MODE 0x01 +#define REG_FRF_MSB 0x06 +#define REG_FRF_MID 0x07 +#define REG_FRF_LSB 0x08 +#define REG_PA_CONFIG 0x09 +#define REG_OCP 0x0b +#define REG_LNA 0x0c +#define REG_FIFO_ADDR_PTR 0x0d +#define REG_FIFO_TX_BASE_ADDR 0x0e +#define REG_FIFO_RX_BASE_ADDR 0x0f +#define REG_FIFO_RX_CURRENT_ADDR 0x10 +#define REG_IRQ_FLAGS 0x12 +#define REG_RX_NB_BYTES 0x13 +#define REG_PKT_SNR_VALUE 0x19 +#define REG_PKT_RSSI_VALUE 0x1a +#define REG_RSSI_VALUE 0x1b +#define REG_MODEM_CONFIG_1 0x1d +#define REG_MODEM_CONFIG_2 0x1e +#define REG_PREAMBLE_MSB 0x20 +#define REG_PREAMBLE_LSB 0x21 +#define REG_PAYLOAD_LENGTH 0x22 +#define REG_MODEM_CONFIG_3 0x26 +#define REG_FREQ_ERROR_MSB 0x28 +#define REG_FREQ_ERROR_MID 0x29 +#define REG_FREQ_ERROR_LSB 0x2a +#define REG_RSSI_WIDEBAND 0x2c +#define REG_DETECTION_OPTIMIZE 0x31 +#define REG_INVERTIQ 0x33 +#define REG_DETECTION_THRESHOLD 0x37 +#define REG_SYNC_WORD 0x39 +#define REG_INVERTIQ2 0x3b +#define REG_DIO_MAPPING_1 0x40 +#define REG_VERSION 0x42 +#define REG_PA_DAC 0x4d + +// modes +#define MODE_LONG_RANGE_MODE 0x80 +#define MODE_SLEEP 0x00 +#define MODE_STDBY 0x01 +#define MODE_TX 0x03 +#define MODE_RX_CONTINUOUS 0x05 +#define MODE_RX_SINGLE 0x06 +#define MODE_CAD 0x07 + +// PA config +#define PA_BOOST 0x80 + +// IRQ masks +#define IRQ_TX_DONE_MASK 0x08 +#define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20 +#define IRQ_RX_DONE_MASK 0x40 +#define IRQ_CAD_DONE_MASK 0x04 +#define IRQ_CAD_DETECTED_MASK 0x01 + +#define RF_MID_BAND_THRESHOLD 525E6 +#define RSSI_OFFSET_HF_PORT 157 +#define RSSI_OFFSET_LF_PORT 164 + +#define MAX_PKT_LENGTH 255 + +#if (ESP8266 || ESP32) + #define ISR_PREFIX ICACHE_RAM_ATTR +#else + #define ISR_PREFIX +#endif + +LoRaClass::LoRaClass() : + _spiSettings(LORA_DEFAULT_SPI_FREQUENCY, MSBFIRST, SPI_MODE0), + _spi(&LORA_DEFAULT_SPI), + _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), + _frequency(0), + _packetIndex(0), + _implicitHeaderMode(0), + _onReceive(NULL), + _onCadDone(NULL), + _onTxDone(NULL) +{ + // overide Stream timeout value + setTimeout(0); +} + +int LoRaClass::begin(long frequency) +{ +#if defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) + pinMode(LORA_IRQ_DUMB, OUTPUT); + digitalWrite(LORA_IRQ_DUMB, LOW); + + // Hardware reset + pinMode(LORA_BOOT0, OUTPUT); + digitalWrite(LORA_BOOT0, LOW); + + pinMode(LORA_RESET, OUTPUT); + digitalWrite(LORA_RESET, HIGH); + delay(200); + digitalWrite(LORA_RESET, LOW); + delay(200); + digitalWrite(LORA_RESET, HIGH); + delay(50); +#endif + + // setup pins + pinMode(_ss, OUTPUT); + // set SS high + digitalWrite(_ss, HIGH); + + if (_reset != -1) { + pinMode(_reset, OUTPUT); + + // perform reset + digitalWrite(_reset, LOW); + delay(10); + digitalWrite(_reset, HIGH); + delay(10); + } + + // start SPI + _spi->begin(); + + // check version + uint8_t version = readRegister(REG_VERSION); + if (version != 0x12) { + return 0; + } + + // put in sleep mode + sleep(); + + // set frequency + setFrequency(frequency); + + // set base addresses + writeRegister(REG_FIFO_TX_BASE_ADDR, 0); + writeRegister(REG_FIFO_RX_BASE_ADDR, 0); + + // set LNA boost + writeRegister(REG_LNA, readRegister(REG_LNA) | 0x03); + + // set auto AGC + writeRegister(REG_MODEM_CONFIG_3, 0x04); + + // set output power to 17 dBm + setTxPower(17); + + // put in standby mode + idle(); + + return 1; +} + +void LoRaClass::end() +{ + // put in sleep mode + sleep(); + + // stop SPI + _spi->end(); +} + +int LoRaClass::beginPacket(int implicitHeader) +{ + if (isTransmitting()) { + return 0; + } + + // put in standby mode + idle(); + + if (implicitHeader) { + implicitHeaderMode(); + } else { + explicitHeaderMode(); + } + + // reset FIFO address and paload length + writeRegister(REG_FIFO_ADDR_PTR, 0); + writeRegister(REG_PAYLOAD_LENGTH, 0); + + return 1; +} + +int LoRaClass::endPacket(bool async) +{ + + if ((async) && (_onTxDone)) + writeRegister(REG_DIO_MAPPING_1, 0x40); // DIO0 => TXDONE + + // put in TX mode + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); + + if (!async) { + // wait for TX done + while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { +// yield(); + delay(0); // Prevent watchdog crashes + } + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); + } + + return 1; +} + +bool LoRaClass::isTransmitting() +{ + if ((readRegister(REG_OP_MODE) & MODE_TX) == MODE_TX) { + return true; + } + + if (readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) { + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); + } + + return false; +} + +int LoRaClass::parsePacket(int size) +{ + int packetLength = 0; + int irqFlags = readRegister(REG_IRQ_FLAGS); + + if (size > 0) { + implicitHeaderMode(); + + writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); + } else { + explicitHeaderMode(); + } + + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, irqFlags); + + if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { + // received a packet + _packetIndex = 0; + + // read packet length + if (_implicitHeaderMode) { + packetLength = readRegister(REG_PAYLOAD_LENGTH); + } else { + packetLength = readRegister(REG_RX_NB_BYTES); + } + + // set FIFO address to current RX address + writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); + + // put in standby mode + idle(); + } else if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) { + // not currently in RX mode + + // reset FIFO address + writeRegister(REG_FIFO_ADDR_PTR, 0); + + // put in single RX mode + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); + } + + return packetLength; +} + +int LoRaClass::packetRssi() +{ + return (readRegister(REG_PKT_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT)); +} + +float LoRaClass::packetSnr() +{ + return ((int8_t)readRegister(REG_PKT_SNR_VALUE)) * 0.25; +} + +long LoRaClass::packetFrequencyError() +{ + int32_t freqError = 0; + freqError = static_cast(readRegister(REG_FREQ_ERROR_MSB) & 0b111); + freqError <<= 8L; + freqError += static_cast(readRegister(REG_FREQ_ERROR_MID)); + freqError <<= 8L; + freqError += static_cast(readRegister(REG_FREQ_ERROR_LSB)); + + if (readRegister(REG_FREQ_ERROR_MSB) & 0b1000) { // Sign bit is on + freqError -= 524288; // 0b1000'0000'0000'0000'0000 + } + + const float fXtal = 32E6; // FXOSC: crystal oscillator (XTAL) frequency (2.5. Chip Specification, p. 14) + const float fError = ((static_cast(freqError) * (1L << 24)) / fXtal) * (getSignalBandwidth() / 500000.0f); // p. 37 + + return static_cast(fError); +} + +int LoRaClass::rssi() +{ + return (readRegister(REG_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT)); +} + +size_t LoRaClass::write(uint8_t byte) +{ + return write(&byte, sizeof(byte)); +} + +size_t LoRaClass::write(const uint8_t *buffer, size_t size) +{ + int currentLength = readRegister(REG_PAYLOAD_LENGTH); + + // check size + if ((currentLength + size) > MAX_PKT_LENGTH) { + size = MAX_PKT_LENGTH - currentLength; + } + + // write data + for (size_t i = 0; i < size; i++) { + writeRegister(REG_FIFO, buffer[i]); + } + + // update length + writeRegister(REG_PAYLOAD_LENGTH, currentLength + size); + + return size; +} + +int LoRaClass::available() +{ + return (readRegister(REG_RX_NB_BYTES) - _packetIndex); +} + +int LoRaClass::read() +{ + if (!available()) { + return -1; + } + + _packetIndex++; + + return readRegister(REG_FIFO); +} + +int LoRaClass::peek() +{ + if (!available()) { + return -1; + } + + // store current FIFO address + int currentAddress = readRegister(REG_FIFO_ADDR_PTR); + + // read + uint8_t b = readRegister(REG_FIFO); + + // restore FIFO address + writeRegister(REG_FIFO_ADDR_PTR, currentAddress); + + return b; +} + +void LoRaClass::flush() +{ +} + +#ifndef ARDUINO_SAMD_MKRWAN1300 +void LoRaClass::onReceive(void(*callback)(int)) +{ + _onReceive = callback; + + if (callback) { + pinMode(_dio0, INPUT); +#ifdef SPI_HAS_NOTUSINGINTERRUPT + SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); +#endif + attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); + } else { + detachInterrupt(digitalPinToInterrupt(_dio0)); +#ifdef SPI_HAS_NOTUSINGINTERRUPT + SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0)); +#endif + } +} + +void LoRaClass::onCadDone(void(*callback)(boolean)) +{ + _onCadDone = callback; + + if (callback) { + pinMode(_dio0, INPUT); +#ifdef SPI_HAS_NOTUSINGINTERRUPT + SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); +#endif + attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); + } else { + detachInterrupt(digitalPinToInterrupt(_dio0)); +#ifdef SPI_HAS_NOTUSINGINTERRUPT + SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0)); +#endif + } +} + +void LoRaClass::onTxDone(void(*callback)()) +{ + _onTxDone = callback; + + if (callback) { + pinMode(_dio0, INPUT); +#ifdef SPI_HAS_NOTUSINGINTERRUPT + SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); +#endif + attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); + } else { + detachInterrupt(digitalPinToInterrupt(_dio0)); +#ifdef SPI_HAS_NOTUSINGINTERRUPT + SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0)); +#endif + } +} + +void LoRaClass::receive(int size) +{ + + writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE + + if (size > 0) { + implicitHeaderMode(); + + writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); + } else { + explicitHeaderMode(); + } + + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS); +} + +void LoRaClass::channelActivityDetection(void) +{ + writeRegister(REG_DIO_MAPPING_1, 0x80);// DIO0 => CADDONE + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_CAD); +} +#endif + +void LoRaClass::idle() +{ + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY); +} + +void LoRaClass::sleep() +{ + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP); +} + +void LoRaClass::setTxPower(int level, int outputPin) +{ + if (PA_OUTPUT_RFO_PIN == outputPin) { + // RFO + if (level < 0) { + level = 0; + } else if (level > 14) { + level = 14; + } + + writeRegister(REG_PA_CONFIG, 0x70 | level); + } else { + // PA BOOST + if (level > 17) { + if (level > 20) { + level = 20; + } + + // subtract 3 from level, so 18 - 20 maps to 15 - 17 + level -= 3; + + // High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.) + writeRegister(REG_PA_DAC, 0x87); + setOCP(140); + } else { + if (level < 2) { + level = 2; + } + //Default value PA_HF/LF or +17dBm + writeRegister(REG_PA_DAC, 0x84); + setOCP(100); + } + + writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2)); + } +} + +void LoRaClass::setFrequency(long frequency) +{ + _frequency = frequency; + + uint64_t frf = ((uint64_t)frequency << 19) / 32000000; + + writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16)); + writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8)); + writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0)); +} + +int LoRaClass::getSpreadingFactor() +{ + return readRegister(REG_MODEM_CONFIG_2) >> 4; +} + +void LoRaClass::setSpreadingFactor(int sf) +{ + if (sf < 6) { + sf = 6; + } else if (sf > 12) { + sf = 12; + } + + if (sf == 6) { + writeRegister(REG_DETECTION_OPTIMIZE, 0xc5); + writeRegister(REG_DETECTION_THRESHOLD, 0x0c); + } else { + writeRegister(REG_DETECTION_OPTIMIZE, 0xc3); + writeRegister(REG_DETECTION_THRESHOLD, 0x0a); + } + + writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)); + setLdoFlag(); +} + +long LoRaClass::getSignalBandwidth() +{ + byte bw = (readRegister(REG_MODEM_CONFIG_1) >> 4); + + switch (bw) { + case 0: return 7.8E3; + case 1: return 10.4E3; + case 2: return 15.6E3; + case 3: return 20.8E3; + case 4: return 31.25E3; + case 5: return 41.7E3; + case 6: return 62.5E3; + case 7: return 125E3; + case 8: return 250E3; + case 9: return 500E3; + } + + return -1; +} + +void LoRaClass::setSignalBandwidth(long sbw) +{ + int bw; + + if (sbw <= 7.8E3) { + bw = 0; + } else if (sbw <= 10.4E3) { + bw = 1; + } else if (sbw <= 15.6E3) { + bw = 2; + } else if (sbw <= 20.8E3) { + bw = 3; + } else if (sbw <= 31.25E3) { + bw = 4; + } else if (sbw <= 41.7E3) { + bw = 5; + } else if (sbw <= 62.5E3) { + bw = 6; + } else if (sbw <= 125E3) { + bw = 7; + } else if (sbw <= 250E3) { + bw = 8; + } else /*if (sbw <= 250E3)*/ { + bw = 9; + } + + writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4)); + setLdoFlag(); +} + +void LoRaClass::setLdoFlag() +{ + // Section 4.1.1.5 + long symbolDuration = 1000 / ( getSignalBandwidth() / (1L << getSpreadingFactor()) ) ; + + // Section 4.1.1.6 + boolean ldoOn = symbolDuration > 16; + + uint8_t config3 = readRegister(REG_MODEM_CONFIG_3); + bitWrite(config3, 3, ldoOn); + writeRegister(REG_MODEM_CONFIG_3, config3); +} + +void LoRaClass::setLdoFlagForced(const boolean ldoOn) +{ + uint8_t config3 = readRegister(REG_MODEM_CONFIG_3); + bitWrite(config3, 3, ldoOn); + writeRegister(REG_MODEM_CONFIG_3, config3); +} + +void LoRaClass::setCodingRate4(int denominator) +{ + if (denominator < 5) { + denominator = 5; + } else if (denominator > 8) { + denominator = 8; + } + + int cr = denominator - 4; + + writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1)); +} + +void LoRaClass::setPreambleLength(long length) +{ + writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8)); + writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0)); +} + +void LoRaClass::setSyncWord(int sw) +{ + writeRegister(REG_SYNC_WORD, sw); +} + +void LoRaClass::enableCrc() +{ + writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) | 0x04); +} + +void LoRaClass::disableCrc() +{ + writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb); +} + +void LoRaClass::enableInvertIQ() +{ + writeRegister(REG_INVERTIQ, 0x66); + writeRegister(REG_INVERTIQ2, 0x19); +} + +void LoRaClass::disableInvertIQ() +{ + writeRegister(REG_INVERTIQ, 0x27); + writeRegister(REG_INVERTIQ2, 0x1d); +} + +void LoRaClass::enableLowDataRateOptimize() +{ + setLdoFlagForced(true); +} + +void LoRaClass::disableLowDataRateOptimize() +{ + setLdoFlagForced(false); +} + +void LoRaClass::setOCP(uint8_t mA) +{ + uint8_t ocpTrim = 27; + + if (mA <= 120) { + ocpTrim = (mA - 45) / 5; + } else if (mA <=240) { + ocpTrim = (mA + 30) / 10; + } + + writeRegister(REG_OCP, 0x20 | (0x1F & ocpTrim)); +} + +void LoRaClass::setGain(uint8_t gain) +{ + // check allowed range + if (gain > 6) { + gain = 6; + } + + // set to standby + idle(); + + // set gain + if (gain == 0) { + // if gain = 0, enable AGC + writeRegister(REG_MODEM_CONFIG_3, 0x04); + } else { + // disable AGC + writeRegister(REG_MODEM_CONFIG_3, 0x00); + + // clear Gain and set LNA boost + writeRegister(REG_LNA, 0x03); + + // set gain + writeRegister(REG_LNA, readRegister(REG_LNA) | (gain << 5)); + } +} + +byte LoRaClass::random() +{ + return readRegister(REG_RSSI_WIDEBAND); +} + +void LoRaClass::setPins(int ss, int reset, int dio0) +{ + _ss = ss; + _reset = reset; + _dio0 = dio0; +} + +void LoRaClass::setSPI(SPIClass& spi) +{ + _spi = &spi; +} + +void LoRaClass::setSPIFrequency(uint32_t frequency) +{ + _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); +} + +void LoRaClass::dumpRegisters(Stream& out) +{ + for (int i = 0; i < 128; i++) { + out.print("0x"); + out.print(i, HEX); + out.print(": 0x"); + out.println(readRegister(i), HEX); + } +} + +void LoRaClass::explicitHeaderMode() +{ + _implicitHeaderMode = 0; + + writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) & 0xfe); +} + +void LoRaClass::implicitHeaderMode() +{ + _implicitHeaderMode = 1; + + writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) | 0x01); +} + +void LoRaClass::handleDio0Rise() +{ + int irqFlags = readRegister(REG_IRQ_FLAGS); + + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, irqFlags); + + if ((irqFlags & IRQ_CAD_DONE_MASK) != 0) { + if (_onCadDone) { + _onCadDone((irqFlags & IRQ_CAD_DETECTED_MASK) != 0); + } + } else if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { + + if ((irqFlags & IRQ_RX_DONE_MASK) != 0) { + // received a packet + _packetIndex = 0; + + // read packet length + int packetLength = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH) : readRegister(REG_RX_NB_BYTES); + + // set FIFO address to current RX address + writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); + + if (_onReceive) { + _onReceive(packetLength); + } + } else if ((irqFlags & IRQ_TX_DONE_MASK) != 0) { + if (_onTxDone) { + _onTxDone(); + } + } + } +} + +uint8_t LoRaClass::readRegister(uint8_t address) +{ + return singleTransfer(address & 0x7f, 0x00); +} + +void LoRaClass::writeRegister(uint8_t address, uint8_t value) +{ + singleTransfer(address | 0x80, value); +} + +uint8_t LoRaClass::singleTransfer(uint8_t address, uint8_t value) +{ + uint8_t response; + + _spi->beginTransaction(_spiSettings); + digitalWrite(_ss, LOW); + _spi->transfer(address); + response = _spi->transfer(value); + digitalWrite(_ss, HIGH); + _spi->endTransaction(); + + return response; +} + +ISR_PREFIX void LoRaClass::onDio0Rise() +{ + LoRa.handleDio0Rise(); +} + +LoRaClass LoRa; diff --git a/lib/lib_rf/LoRa/src/LoRa.h b/lib/lib_rf/LoRa/src/LoRa.h new file mode 100644 index 000000000..a7002b4bb --- /dev/null +++ b/lib/lib_rf/LoRa/src/LoRa.h @@ -0,0 +1,136 @@ +// Copyright (c) Sandeep Mistry. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef LORA_H +#define LORA_H + +#include +#include + +#if defined(ARDUINO_SAMD_MKRWAN1300) +#define LORA_DEFAULT_SPI SPI1 +#define LORA_DEFAULT_SPI_FREQUENCY 200000 +#define LORA_DEFAULT_SS_PIN LORA_IRQ_DUMB +#define LORA_DEFAULT_RESET_PIN -1 +#define LORA_DEFAULT_DIO0_PIN -1 +#elif defined(ARDUINO_SAMD_MKRWAN1310) +#define LORA_DEFAULT_SPI SPI1 +#define LORA_DEFAULT_SPI_FREQUENCY 200000 +#define LORA_DEFAULT_SS_PIN LORA_IRQ_DUMB +#define LORA_DEFAULT_RESET_PIN -1 +#define LORA_DEFAULT_DIO0_PIN LORA_IRQ +#else +#define LORA_DEFAULT_SPI SPI +#define LORA_DEFAULT_SPI_FREQUENCY 8E6 +#define LORA_DEFAULT_SS_PIN 10 +#define LORA_DEFAULT_RESET_PIN 9 +#define LORA_DEFAULT_DIO0_PIN 2 +#endif + +#define PA_OUTPUT_RFO_PIN 0 +#define PA_OUTPUT_PA_BOOST_PIN 1 + +class LoRaClass : public Stream { +public: + LoRaClass(); + + int begin(long frequency); + void end(); + + int beginPacket(int implicitHeader = false); + int endPacket(bool async = false); + + int parsePacket(int size = 0); + int packetRssi(); + float packetSnr(); + long packetFrequencyError(); + + int rssi(); + + // from Print + virtual size_t write(uint8_t byte); + virtual size_t write(const uint8_t *buffer, size_t size); + + // from Stream + virtual int available(); + virtual int read(); + virtual int peek(); + virtual void flush(); + +#ifndef ARDUINO_SAMD_MKRWAN1300 + void onReceive(void(*callback)(int)); + void onCadDone(void(*callback)(boolean)); + void onTxDone(void(*callback)()); + + void receive(int size = 0); + void channelActivityDetection(void); +#endif + void idle(); + void sleep(); + + void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN); + void setFrequency(long frequency); + void setSpreadingFactor(int sf); + void setSignalBandwidth(long sbw); + void setCodingRate4(int denominator); + void setPreambleLength(long length); + void setSyncWord(int sw); + void enableCrc(); + void disableCrc(); + void enableInvertIQ(); + void disableInvertIQ(); + void enableLowDataRateOptimize(); + void disableLowDataRateOptimize(); + + void setOCP(uint8_t mA); // Over Current Protection control + + void setGain(uint8_t gain); // Set LNA gain + + // deprecated + void crc() { enableCrc(); } + void noCrc() { disableCrc(); } + + byte random(); + + void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN); + void setSPI(SPIClass& spi); + void setSPIFrequency(uint32_t frequency); + + void dumpRegisters(Stream& out); + +private: + void explicitHeaderMode(); + void implicitHeaderMode(); + + void handleDio0Rise(); + bool isTransmitting(); + + int getSpreadingFactor(); + long getSignalBandwidth(); + + void setLdoFlag(); + void setLdoFlagForced(const boolean); + + uint8_t readRegister(uint8_t address); + void writeRegister(uint8_t address, uint8_t value); + uint8_t singleTransfer(uint8_t address, uint8_t value); + + static void onDio0Rise(); + +private: + SPISettings _spiSettings; + SPIClass* _spi; + int _ss; + int _reset; + int _dio0; + long _frequency; + int _packetIndex; + int _implicitHeaderMode; + void (*_onReceive)(int); + void (*_onCadDone)(boolean); + void (*_onTxDone)(); +}; + +extern LoRaClass LoRa; + +#endif diff --git a/lib/lib_rf/RadioLib/.gitignore b/lib/lib_rf/RadioLib/.gitignore new file mode 100644 index 000000000..b65463c98 --- /dev/null +++ b/lib/lib_rf/RadioLib/.gitignore @@ -0,0 +1,28 @@ +# Arduino Library Development file +.development + +# Atom +*.tags +*.tags1 + +# VS Code +.vscode + +# Jetbrain IDEs +.idea + +# Debug decoder +extras/decoder/log.txt +extras/decoder/out.txt + +# Spectrum scan +extras/SX126x_Spectrum_Scan/out/* + +# PlatformIO +.pio* + +# cmake +build/ + +# Compote build output +dist diff --git a/lib/lib_rf/RadioLib/.gitmodules b/lib/lib_rf/RadioLib/.gitmodules new file mode 100644 index 000000000..7eb86944a --- /dev/null +++ b/lib/lib_rf/RadioLib/.gitmodules @@ -0,0 +1,3 @@ +[submodule "examples/NonArduino/Tock/libtock-c"] + path = examples/NonArduino/Tock/libtock-c + url = https://github.com/tock/libtock-c.git diff --git a/lib/lib_rf/RadioLib/CMakeLists.txt b/lib/lib_rf/RadioLib/CMakeLists.txt new file mode 100644 index 000000000..680864d28 --- /dev/null +++ b/lib/lib_rf/RadioLib/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.13) + +if(ESP_PLATFORM) + # Build RadioLib as an ESP-IDF component + # required because ESP-IDF runs cmake in script mode + # and needs idf_component_register() + file(GLOB_RECURSE RADIOLIB_ESP_SOURCES + "src/*.*" + ) + + idf_component_register( + SRCS ${RADIOLIB_ESP_SOURCES} + INCLUDE_DIRS . src + ) + + return() +endif() + +if(CMAKE_SCRIPT_MODE_FILE) + message(FATAL_ERROR "Attempted to build RadioLib in script mode") +endif() + +project(radiolib) + +file(GLOB_RECURSE RADIOLIB_SOURCES + "src/*.cpp" +) + +add_library(RadioLib ${RADIOLIB_SOURCES}) + +target_include_directories(RadioLib + PUBLIC $ + $) + +include(GNUInstallDirs) + +install(TARGETS RadioLib + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/RadioLib + FILES_MATCHING PATTERN "*.h" +) diff --git a/lib/lib_rf/RadioLib/CODE_OF_CONDUCT.md b/lib/lib_rf/RadioLib/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..1a32eaccb --- /dev/null +++ b/lib/lib_rf/RadioLib/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# Code of Conduct + +Don't be an a*shole. diff --git a/lib/lib_rf/RadioLib/CONTRIBUTING.md b/lib/lib_rf/RadioLib/CONTRIBUTING.md new file mode 100644 index 000000000..4bf96194b --- /dev/null +++ b/lib/lib_rf/RadioLib/CONTRIBUTING.md @@ -0,0 +1,110 @@ +# Contributing to RadioLib + +First of all, thank you very much for taking the time to contribute! All feedback and ideas are greatly appreciated. +To keep this library organized, please follow these rules. + +## Issues + +The following rules guide submission of new issues. These rules are in place mainly so that the issue author can get help as quickly as possible. + +1. **Questions are welcome, spam is not.** +Any issues without description will be considered spam and as such will be **CLOSED** and **LOCKED** immediately! +2. **This repository has issue templates.** +To report bugs or suggest new features, use the provided issue templates. Use the default issue only if the templates do not fit your issue type. +3. **Be as clear as possible when creating issues.** +Issues with generic titles (e.g. "not working", "lora", etc.) will be **CLOSED** until the title is fixed, since the title is supposed to categorize the issue. The same applies for issues with very little information and extensive grammatical or formatting errors that make it difficult to find out what is the actual issue. +4. **Issues deserve some attention too.** +Issues that are left for 2 weeks without response by the original author when asked for further information will be closed due to inactivity. This is to keep track of important issues, the author is encouraged to reopen the issue at a later date. + +## Code style guidelines + +I like pretty code! Or at least, I like *consistent* code style. When creating pull requests, please follow these style guidelines, they're in place to keep high code readability. + +1. **Bracket style** +This library uses the following style of bracket indentation (1TBS, or "javascript" style): + +```c++ +if (foo) { + bar(); +} else { + baz(); +} +``` + +2. **Tabs** +Use 2 space characters for tabs. + +3. **Single-line comments** +Comments can be very useful - and they can become the bane of readability. Every single-line comment should start at new line, have one space between comment delimiter `//` and the start of the comment itself. The comment should also start with a lower-case letter. + +```c++ +// this function does something +foo("bar"); + +// here it does something else +foo(12345); +``` + +4. **Split code into blocks** +It is very easy to write code that machine can read. It is much harder to write one that humans can read. That's why it's a great idea to split code into blocks - even if the block is just a single line! + +```c++ +// build a temporary buffer (first block) +uint8_t* data = new uint8_t[len + 1]; +if(!data) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); +} + +// read the received data (second block) +state = readData(data, len); + +// add null terminator (third block) +data[len] = 0; +``` + +5. **Doxygen** +If you're adding a new method, make sure to add appropriate Doxygen comments, so that the documentation is always complete. + +6. **Keywords** +This is an Arduino library, so it needs to comply with the Arduino library specification. To add a new keyword to the Arduino IDE syntax highlighting, add it to the keywords.txt file. **Use true tabs in keywords.txt! No spaces there!** + +7. **Dynamic memory** +Sometimes, RadioLib might be used in critical applications where dynamic memory allocation using `new` or `malloc` might cause issues. For such cases, RadioLib provides the option to compile using only static arrays. This means that every dynamically allocated array must have a sufficiently large static counterpart. Naturally, all dynamically allocated memory must be properly de-allocated using `delete` or `free`. + +```c++ +// build a temporary buffer +#if defined(RADIOLIB_STATIC_ONLY) + uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; +#else + uint8_t* data = new uint8_t[length + 1]; + if(!data) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } +#endif + +// read the received data +readData(data, length); + +// deallocate temporary buffer +#if !defined(RADIOLIB_STATIC_ONLY) + delete[] data; +#endif +``` + +8. **God Mode** +During development, it can be useful to have access to the low level drivers, such as the SPI commands. These are incredibly powerful, since they will basically let user do anything he wants with the module, outside of the normal level of sanity checks. As such, they are normally protected using C++ access modifiers `private` or `protected`. God mode disables this protection, and so any newly implemented `class` must contain the appropriate macro check: + +```c++ +class Module { + void publicMethod(); + +#if defined(RADIOLIB_GODMODE) + private: +#endif + + void privateMethod(); +}; +``` + +9. **No Arduino Strings** +Arduino `String` class should never be used internally in the library. The only allowed occurence of Arduino `String` is in public API methods, and only at the top-most layer. diff --git a/lib/libesp32_div/NimBLE-Arduino/docs/Doxyfile b/lib/lib_rf/RadioLib/Doxyfile similarity index 91% rename from lib/libesp32_div/NimBLE-Arduino/docs/Doxyfile rename to lib/lib_rf/RadioLib/Doxyfile index d9c430338..db6d223b3 100644 --- a/lib/libesp32_div/NimBLE-Arduino/docs/Doxyfile +++ b/lib/lib_rf/RadioLib/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.9.1 +# Doxyfile 1.8.15 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -32,19 +32,19 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = NimBLE-Arduino +PROJECT_NAME = RadioLib # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.4.1 +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = +PROJECT_BRIEF = "Universal wireless communication library for Arduino" # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 @@ -58,7 +58,7 @@ PROJECT_LOGO = # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = doxydocs +OUTPUT_DIRECTORY = docs # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and @@ -197,16 +197,6 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO -# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line -# such as -# /*************** -# as being the beginning of a Javadoc-style comment "banner". If set to NO, the -# Javadoc-style will behave just like regular comments and it will not be -# interpreted by doxygen. -# The default value is: NO. - -JAVADOC_BANNER = NO - # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus @@ -227,14 +217,6 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO -# By default Python docstrings are displayed as preformatted text and doxygen's -# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the -# doxygen's special commands can be used and the contents of the docstring -# documentation blocks is shown as doxygen documentation. -# The default value is: YES. - -PYTHON_DOCSTRING = YES - # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. @@ -271,6 +253,12 @@ TAB_SIZE = 4 ALIASES = +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -311,22 +299,19 @@ OPTIMIZE_OUTPUT_SLICE = NO # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, # Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the -# default for Fortran type files). For instance to make doxygen treat .inc files -# as Fortran files (default is PHP), and .f files as C (default is Fortran), -# use: inc=Fortran f=C. +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is +# Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. When specifying no_extension you should add -# * to the FILE_PATTERNS. -# -# Note see also the list of default file extension mappings. +# the files are not read by doxygen. EXTENSION_MAPPING = @@ -344,10 +329,10 @@ MARKDOWN_SUPPORT = YES # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 5. +# Minimum value: 0, maximum value: 99, default value: 0. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. -TOC_INCLUDE_HEADINGS = 5 +TOC_INCLUDE_HEADINGS = 0 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can @@ -460,19 +445,6 @@ TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 -# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use -# during processing. When set to 0 doxygen will based this on the number of -# cores available in the system. You can set it explicitly to a value larger -# than 0 to get more control over the balance between CPU load and processing -# speed. At this moment only the input processing can be done using multiple -# threads. Since this is still an experimental feature the default is set to 1, -# which efficively disables parallel processing. Please report any issues you -# encounter. Generating dot graphs in parallel is controlled by the -# DOT_NUM_THREADS setting. -# Minimum value: 0, maximum value: 32, default value: 1. - -NUM_PROC_THREADS = 1 - #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -493,12 +465,6 @@ EXTRACT_ALL = NO EXTRACT_PRIVATE = NO -# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual -# methods of a class will be included in the documentation. -# The default value is: NO. - -EXTRACT_PRIV_VIRTUAL = NO - # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. @@ -536,20 +502,13 @@ EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO -# If this flag is set to YES, the name of an unnamed parameter in a declaration -# will be determined by the corresponding definition. By default unnamed -# parameters remain unnamed in the output. -# The default value is: YES. - -RESOLVE_UNNAMED_PARAMS = YES - # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. -HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set @@ -557,21 +516,21 @@ HIDE_UNDOC_MEMBERS = YES # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. -HIDE_UNDOC_CLASSES = YES +HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# declarations. If set to NO, these declarations will be included in the -# documentation. +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. # The default value is: NO. -HIDE_FRIEND_COMPOUNDS = YES +HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. -HIDE_IN_BODY_DOCS = YES +HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation @@ -580,18 +539,11 @@ HIDE_IN_BODY_DOCS = YES INTERNAL_DOCS = NO -# With the correct setting of option CASE_SENSE_NAMES doxygen will better be -# able to match the capabilities of the underlying filesystem. In case the -# filesystem is case sensitive (i.e. it supports files in the same directory -# whose names only differ in casing), the option must be set to YES to properly -# deal with such files in case they appear in the input. For filesystems that -# are not case sensitive the option should be be set to NO to properly deal with -# output files written for symbols that only differ in casing, such as for two -# classes, one named CLASS and the other named Class, and to also support -# references to files without having to specify the exact matching casing. On -# Windows (including Cygwin) and MacOS, users should typically set this option -# to NO, whereas on Linux or other Unix flavors it should typically be set to -# YES. +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = NO @@ -614,7 +566,7 @@ HIDE_COMPOUND_REFERENCE= NO # the files that are included by a file in the documentation of that file. # The default value is: YES. -SHOW_INCLUDE_FILES = NO +SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader @@ -736,7 +688,7 @@ MAX_INITIALIZER_LINES = 30 # list will mention the files that were used to generate the documentation. # The default value is: YES. -SHOW_USED_FILES = NO +SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View @@ -750,7 +702,7 @@ SHOW_FILES = YES # Folder Tree View (if specified). # The default value is: YES. -SHOW_NAMESPACES = NO +SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from @@ -830,13 +782,10 @@ WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS -# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but -# at the end of the doxygen process doxygen will return with a non-zero status. -# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# a warning is encountered. # The default value is: NO. -WARN_AS_ERROR = YES +WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which @@ -864,14 +813,13 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = . \ - ../src +INPUT = src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: -# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 @@ -884,15 +832,11 @@ INPUT_ENCODING = UTF-8 # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # -# Note the list of default checked file patterns might differ from the list of -# default file extension mappings. -# # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), -# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, -# *.ucf, *.qsf and *.ice. +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.cc \ @@ -925,17 +869,15 @@ FILE_PATTERNS = *.c \ *.md \ *.mm \ *.dox \ - *.doc \ - *.txt \ *.py \ *.pyw \ *.f90 \ *.f95 \ *.f03 \ *.f08 \ - *.f18 \ *.f \ *.for \ + *.tcl \ *.vhd \ *.vhdl \ *.ucf \ @@ -955,11 +897,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = ./README.md \ - ./examples \ - ./CMakelists.txt \ - ../src/nimconfig_rename.h \ - ../src/nimble +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -1068,7 +1006,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = index.md +USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -1157,22 +1095,16 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the -# clang parser (see: -# http://clang.llvm.org/) for more accurate parsing at the cost of reduced -# performance. This can be particularly helpful with template rich C++ code for -# which doxygen's built-in parser lacks the necessary type information. +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO -# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to -# YES then doxygen will add the directory of each input to the include path. -# The default value is: YES. - -CLANG_ADD_INC_PATHS = YES - # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories @@ -1182,13 +1114,10 @@ CLANG_ADD_INC_PATHS = YES CLANG_OPTIONS = # If clang assisted parsing is enabled you can provide the clang parser with the -# path to the directory containing a file called compile_commands.json. This -# file is the compilation database (see: -# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the -# options used when the source files were built. This is equivalent to -# specifying the -p option to a clang tool, such as clang-check. These options -# will then be passed to the parser. Any options specified with CLANG_OPTIONS -# will be added as well. +# path to the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files +# were built. This is equivalent to specifying the "-p" option to a clang tool, +# such as clang-check. These options will then be passed to the parser. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. @@ -1205,6 +1134,13 @@ CLANG_DATABASE_PATH = ALPHABETICAL_INDEX = YES +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored @@ -1343,9 +1279,9 @@ HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that -# are dynamically created via JavaScript. If disabled, the navigation index will +# are dynamically created via Javascript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML -# page. Disable this option to support browsers that do not have JavaScript, +# page. Disable this option to support browsers that do not have Javascript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1375,11 +1311,10 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: -# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To -# create a documentation set, doxygen will generate a Makefile in the HTML -# output directory. Running make will produce the docset in that directory and -# running make install will install the docset in +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. @@ -1421,8 +1356,8 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: -# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1452,7 +1387,7 @@ CHM_FILE = HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the main .chm file (NO). +# (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1497,8 +1432,7 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1506,8 +1440,8 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# Folders (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- +# folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1515,30 +1449,30 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = -# The QHG_LOCATION tag can be used to specify the location (absolute path -# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to -# run qhelpgenerator on the generated .qhp file. +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = @@ -1615,17 +1549,6 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO -# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg -# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see -# https://inkscape.org) to generate formulas as SVG images instead of PNGs for -# the HTML output. These images will generally look nicer at scaled resolutions. -# Possible values are: png (the default) and svg (looks nicer but requires the -# pdf2svg or inkscape tool). -# The default value is: png. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FORMULA_FORMAT = png - # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML @@ -1646,14 +1569,8 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES -# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands -# to create new LaTeX commands to be used in formulas as building blocks. See -# the section "Including formulas" for details. - -FORMULA_MACROFILE = - # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# https://www.mathjax.org) which uses client side JavaScript for the rendering +# https://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1665,7 +1582,7 @@ USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. +# http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. @@ -1681,10 +1598,10 @@ MATHJAX_FORMAT = HTML-CSS # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example @@ -1695,8 +1612,7 @@ MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: -# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1724,7 +1640,7 @@ MATHJAX_CODEFILE = SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using JavaScript. There +# implemented using a web server instead of a web client using Javascript. There # are two flavors of web server based searching depending on the EXTERNAL_SEARCH # setting. When disabled, doxygen will generate a PHP script for searching and # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing @@ -1743,8 +1659,7 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: -# https://xapian.org/). +# Xapian (see: https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1757,9 +1672,8 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: -# https://xapian.org/). See the section "External Indexing and Searching" for -# details. +# Xapian (see: https://xapian.org/). See the section "External Indexing and +# Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = @@ -1830,14 +1744,13 @@ LATEX_CMD_NAME = MAKEINDEX_CMD_NAME = makeindex # The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to -# generate index for LaTeX. In case there is no backslash (\) as first character -# it will be automatically added in the LaTeX code. +# generate index for LaTeX. # Note: This tag is used in the generated output file (.tex). # See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. -# The default value is: makeindex. +# The default value is: \makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_MAKEINDEX_CMD = makeindex +LATEX_MAKEINDEX_CMD = \makeindex # If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some @@ -1923,11 +1836,9 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as -# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX -# files. Set this option to YES, to get a higher quality PDF documentation. -# -# See also section LATEX_CMD_NAME for selecting the engine. +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a +# higher quality PDF documentation. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -2118,7 +2029,7 @@ XML_OUTPUT = xml # The default value is: YES. # This tag requires that the tag GENERATE_XML is set to YES. -XML_PROGRAMLISTING = NO +XML_PROGRAMLISTING = YES # If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include # namespace members in file scope as well, matching the HTML output. @@ -2166,10 +2077,6 @@ DOCBOOK_PROGRAMLISTING = NO GENERATE_AUTOGEN_DEF = NO -#--------------------------------------------------------------------------- -# Configuration options related to Sqlite3 output -#--------------------------------------------------------------------------- - #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- @@ -2225,7 +2132,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -2233,7 +2140,7 @@ MACRO_EXPANSION = NO # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. @@ -2265,13 +2172,8 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = _DOXYGEN_ \ - CONFIG_BT_ENABLED \ - CONFIG_BT_NIMBLE_ROLE_CENTRAL \ - CONFIG_BT_NIMBLE_ROLE_OBSERVER \ - CONFIG_BT_NIMBLE_ROLE_PERIPHERAL \ - CONFIG_BT_NIMBLE_ROLE_BROADCASTER \ - CONFIG_BT_NIMBLE_EXT_ADV +PREDEFINED = protected=private \ + DOXYGEN # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -2338,6 +2240,12 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- @@ -2349,7 +2257,16 @@ EXTERNAL_PAGES = YES # powerful graphs. # The default value is: YES. -CLASS_DIAGRAMS = NO +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The @@ -2448,31 +2365,9 @@ UML_LOOK = NO # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. -# This tag requires that the tag UML_LOOK is set to YES. - -UML_LIMIT_NUM_FIELDS = 10 - -# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and -# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS -# tag is set to YES, doxygen will add type and arguments for attributes and -# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen -# will not generate fields with class member information in the UML graphs. The -# class diagrams will look similar to the default class diagrams but using UML -# notation for the relationships. -# Possible values are: NO, YES and NONE. -# The default value is: NO. -# This tag requires that the tag UML_LOOK is set to YES. - -DOT_UML_DETAILS = NO - -# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters -# to display on a single line. If the actual line length exceeds this threshold -# significantly it will wrapped across multiple lines. Some heuristics are apply -# to avoid ugly line breaks. -# Minimum value: 0, maximum value: 1000, default value: 17. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_WRAP_THRESHOLD = 17 +UML_LIMIT_NUM_FIELDS = 10 # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their @@ -2663,11 +2558,9 @@ DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot # files that are used to generate the various graphs. -# -# Note: This setting is not only used for dot files but also for msc and -# plantuml temporary files. # The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES diff --git a/lib/lib_rf/RadioLib/README.md b/lib/lib_rf/RadioLib/README.md new file mode 100644 index 000000000..d33794b37 --- /dev/null +++ b/lib/lib_rf/RadioLib/README.md @@ -0,0 +1,91 @@ +# RadioLib ![Build Status](https://github.com/jgromes/RadioLib/workflows/CI/badge.svg) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/jgromes/library/RadioLib.svg)](https://registry.platformio.org/libraries/jgromes/RadioLib) [![Component Registry](https://components.espressif.com/components/jgromes/radiolib/badge.svg)](https://components.espressif.com/components/jgromes/radiolib) + +### _One radio library to rule them all!_ + +## Universal wireless communication library for embedded devices + +## See the [Wiki](https://github.com/jgromes/RadioLib/wiki) and [FAQ](https://github.com/jgromes/RadioLib/wiki/Frequently-Asked-Questions) for further information. See the [GitHub Pages](https://jgromes.github.io/RadioLib) for detailed and up-to-date API reference. + +RadioLib allows its users to integrate all sorts of different wireless communication modules, protocols and even digital modes into a single consistent system. +Want to add a Bluetooth interface to your LoRa network? Sure thing! Do you just want to go really old-school and play around with radio teletype, slow-scan TV, or even Hellschreiber using nothing but a cheap radio module? Why not! + +RadioLib natively supports Arduino, but can run in non-Arduino environments as well! See [this Wiki page](https://github.com/jgromes/RadioLib/wiki/Porting-to-non-Arduino-Platforms) and [examples/NonArduino](https://github.com/jgromes/RadioLib/tree/master/examples/NonArduino). + +RadioLib was originally created as a driver for [__RadioShield__](https://github.com/jgromes/RadioShield), but it can be used to control as many different wireless modules as you like - or at least as many as your microcontroller can handle! + +### Supported modules: +* __CC1101__ FSK radio module +* __LLCC68__ LoRa module +* __nRF24L01__ 2.4 GHz module +* __RF69__ FSK/OOK radio module +* __RFM2x__ series FSK modules (RFM22, RM23) +* __RFM9x__ series LoRa modules (RFM95, RM96, RFM97, RFM98) +* __Si443x__ series FSK modules (Si4430, Si4431, Si4432) +* __STM32WL__ integrated microcontroller/LoRa module +* __SX126x__ series LoRa modules (SX1261, SX1262, SX1268) +* __SX127x__ series LoRa modules (SX1272, SX1273, SX1276, SX1277, SX1278, SX1279) +* __SX128x__ series LoRa/GFSK/BLE/FLRC modules (SX1280, SX1281, SX1282) +* __SX123x__ FSK/OOK radio modules (SX1231, SX1233) + +### Supported protocols and digital modes: +* [__AX.25__](https://www.sigidwiki.com/wiki/PACKET) using 2-FSK or AFSK for modules: +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x +* [__RTTY__](https://www.sigidwiki.com/wiki/RTTY) using 2-FSK or AFSK for modules: +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +* [__Morse Code__](https://www.sigidwiki.com/wiki/Morse_Code_(CW)) using 2-FSK or AFSK for modules: +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +* [__SSTV__](https://www.sigidwiki.com/wiki/SSTV) using 2-FSK or AFSK for modules: +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x +* [__Hellschreiber__](https://www.sigidwiki.com/wiki/Hellschreiber) using 2-FSK or AFSK for modules: +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +* [__APRS__](https://www.sigidwiki.com/wiki/APRS) using AFSK for modules: +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +* [__POCSAG__](https://www.sigidwiki.com/wiki/POCSAG) using 2-FSK for modules: +SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x +* [__LoRaWAN__](https://lora-alliance.org/) using LoRa for modules: +SX127x, RFM9x, SX126x and SX128x + * NOTE: LoRaWAN support is currently in beta, feedback via [Issues](https://github.com/jgromes/RadioLib/issues) and [Discussions](https://github.com/jgromes/RadioLib/discussions) is appreciated! + +### Supported Arduino platforms: +* __Arduino__ + * [__AVR__](https://github.com/arduino/ArduinoCore-avr) - Arduino Uno, Mega, Leonardo, Pro Mini, Nano etc. + * [__mbed__](https://github.com/arduino/ArduinoCore-mbed) - Arduino Nano 33 BLE and Arduino Portenta H7 + * [__megaAVR__](https://github.com/arduino/ArduinoCore-megaavr) - Arduino Uno WiFi Rev.2 and Nano Every + * [__SAM__](https://github.com/arduino/ArduinoCore-sam) - Arduino Due + * [__SAMD__](https://github.com/arduino/ArduinoCore-samd) - Arduino Zero, MKR boards, M0 Pro etc. + * [__Renesas__](https://github.com/arduino/ArduinoCore-renesas) - Arduino Uno R4 + +* __Adafruit__ + * [__SAMD__](https://github.com/adafruit/ArduinoCore-samd) - Adafruit Feather M0 and M4 boards (Feather, Metro, Gemma, Trinket etc.) + * [__nRF52__](https://github.com/adafruit/Adafruit_nRF52_Arduino) - Adafruit Feather nRF528x, Bluefruit and CLUE + +* __Espressif__ + * [__ESP32__](https://github.com/espressif/arduino-esp32) - ESP32-based boards + * [__ESP8266__](https://github.com/esp8266/Arduino) - ESP8266-based boards + +* __Intel__ + * [__Curie__](https://github.com/arduino/ArduinoCore-arc32) - Arduino 101 + +* __SparkFun__ + * [__Apollo3__](https://github.com/sparkfun/Arduino_Apollo3) - Sparkfun Artemis Redboard + +* __ST Microelectronics__ + * [__STM32__ (official core)](https://github.com/stm32duino/Arduino_Core_STM32) - STM32 Nucleo, Discovery, Maple, BluePill, BlackPill etc. + * [__STM32__ (unofficial core)](https://github.com/rogerclarkmelbourne/Arduino_STM32) - STM32F1 and STM32F4-based boards + +* __MCUdude__ + * [__MegaCoreX__](https://github.com/MCUdude/MegaCoreX) - megaAVR-0 series (ATmega4809, ATmega3209 etc.) + * [__MegaCore__](https://github.com/MCUdude/MegaCore) - AVR (ATmega1281, ATmega640 etc.) + +* __Raspberry Pi__ + * [__RP2040__ (official core)](https://github.com/arduino/ArduinoCore-mbed) - Raspberry Pi Pico and Arduino Nano RP2040 Connect + * [__RP2040__ (unofficial core)](https://github.com/earlephilhower/arduino-pico) - Raspberry Pi Pico/RP2040-based boards + * [__Raspberry Pi__](https://github.com/me-no-dev/RasPiArduino) - Arduino framework for RaspberryPI + +* __Heltec__ + * [__CubeCell__](https://github.com/HelTecAutomation/CubeCell-Arduino) - ASR650X series (CubeCell-Board, CubeCell-Capsule, CubeCell-Module etc.) + +* __PJRC__ + * [__Teensy__](https://github.com/PaulStoffregen/cores) - Teensy 2.x, 3.x and 4.x boards + +The list above is by no means exhaustive - RadioLib code is independent of the used platform! Compilation of all examples is tested for all platforms officially supported prior to releasing new version. In addition, RadioLib includes an internal hardware abstraction layer, which allows it to be easily ported even to non-Arduino environments. diff --git a/lib/lib_rf/RadioLib/SECURITY.md b/lib/lib_rf/RadioLib/SECURITY.md new file mode 100644 index 000000000..b43ea5c1d --- /dev/null +++ b/lib/lib_rf/RadioLib/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +## Reporting a Vulnerability + +RadioLib is provided as-is without any warranty, and is not intended to be used in security-critical applications. However, if you discover a vulnerability within the library code, please report it to gromes.jan@gmail.com. diff --git a/lib/lib_rf/RadioLib/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino b/lib/lib_rf/RadioLib/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino new file mode 100644 index 000000000..c933ebcc7 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino @@ -0,0 +1,89 @@ +/* + RadioLib AFSK External Radio example + + This example shows how to use your Arduino + as modulator for an external analogue FM radio. + + The example sends APRS position reports with + audio modulated as AFSK at 1200 baud using + Bell 202 tones. However, any other AFSK + protocol (RTTY, SSTV, etc.) may be used as well. + + DO NOT transmit in APRS bands unless + you have a ham radio license! + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// create a dummy radio module +ExternalRadio radio; + +// create AFSK client instance using the external radio +// pin 5 is connected to the radio sound input +AFSKClient audio(&radio, 5); + +// create AX.25 client instance using the AFSK instance +AX25Client ax25(&audio); + +// create APRS client instance using the AX.25 client +APRSClient aprs(&ax25); + +void setup() { + Serial.begin(9600); + + // initialize AX.25 client + Serial.print(F("[AX.25] Initializing ... ")); + // source station callsign: "N7LEM" + // source station SSID: 0 + // preamble length: 8 bytes + int16_t state = ax25.begin("N7LEM"); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize APRS client + Serial.print(F("[APRS] Initializing ... ")); + // symbol: '>' (car) + state = aprs.begin('>'); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[APRS] Sending position ... ")); + + // send a location without message or timestamp + int state = aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E"); + delay(500); + + // send a location with message and without timestamp + state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!"); + delay(500); + + // send a location with message and timestamp + state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!", "093045z"); + delay(500); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait one minute before transmitting again + delay(60000); +} diff --git a/lib/lib_rf/RadioLib/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino b/lib/lib_rf/RadioLib/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino new file mode 100644 index 000000000..7c8509166 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino @@ -0,0 +1,107 @@ +/* + RadioLib AFSK Imperial March Example + + This example shows how to EXECUTE ORDER 66 + + Other modules that can be used for AFSK: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// include the melody +#include "melody.h" + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create AFSK client instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 +AFSKClient audio(&radio, 5); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for AFSK + // (RF69, CC1101,, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize AFSK client + Serial.print(F("[AFSK] Initializing ... ")); + state = audio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[AFSK] Executing Order 66 ... ")); + + // calculate whole note duration + int wholenote = (60000 * 4) / 120; + + // iterate over the melody + for(unsigned int note = 0; note < sizeof(melody) / sizeof(melody[0]); note += 2) { + // calculate the duration of each note + int noteDuration = 0; + int divider = melody[note + 1]; + if(divider > 0) { + // regular note, just proceed + noteDuration = wholenote / divider; + } else if(divider < 0) { + // dotted notes are represented with negative durations!! + noteDuration = wholenote / abs(divider); + noteDuration *= 1.5; // increases the duration in half for dotted notes + } + + // we only play the note for 90% of the duration, leaving 10% as a pause + audio.tone(melody[note]); + delay(noteDuration*0.9); + audio.noTone(); + delay(noteDuration*0.1); + } + + Serial.println(F("done!")); + + // wait for a second + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/AFSK/AFSK_Imperial_March/melody.h b/lib/lib_rf/RadioLib/examples/AFSK/AFSK_Imperial_March/melody.h new file mode 100644 index 000000000..2f70f1292 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/AFSK/AFSK_Imperial_March/melody.h @@ -0,0 +1,128 @@ +/* + Note definitions, melody and melody-related functions + adapted from https://github.com/robsoncouto/arduino-songs + by Robson Couto, 2019 +*/ + +#define NOTE_B0 31 +#define NOTE_C1 33 +#define NOTE_CS1 35 +#define NOTE_D1 37 +#define NOTE_DS1 39 +#define NOTE_E1 41 +#define NOTE_F1 44 +#define NOTE_FS1 46 +#define NOTE_G1 49 +#define NOTE_GS1 52 +#define NOTE_A1 55 +#define NOTE_AS1 58 +#define NOTE_B1 62 +#define NOTE_C2 65 +#define NOTE_CS2 69 +#define NOTE_D2 73 +#define NOTE_DS2 78 +#define NOTE_E2 82 +#define NOTE_F2 87 +#define NOTE_FS2 93 +#define NOTE_G2 98 +#define NOTE_GS2 104 +#define NOTE_A2 110 +#define NOTE_AS2 117 +#define NOTE_B2 123 +#define NOTE_C3 131 +#define NOTE_CS3 139 +#define NOTE_D3 147 +#define NOTE_DS3 156 +#define NOTE_E3 165 +#define NOTE_F3 175 +#define NOTE_FS3 185 +#define NOTE_G3 196 +#define NOTE_GS3 208 +#define NOTE_A3 220 +#define NOTE_AS3 233 +#define NOTE_B3 247 +#define NOTE_C4 262 +#define NOTE_CS4 277 +#define NOTE_D4 294 +#define NOTE_DS4 311 +#define NOTE_E4 330 +#define NOTE_F4 349 +#define NOTE_FS4 370 +#define NOTE_G4 392 +#define NOTE_GS4 415 +#define NOTE_A4 440 +#define NOTE_AS4 466 +#define NOTE_B4 494 +#define NOTE_C5 523 +#define NOTE_CS5 554 +#define NOTE_D5 587 +#define NOTE_DS5 622 +#define NOTE_E5 659 +#define NOTE_F5 698 +#define NOTE_FS5 740 +#define NOTE_G5 784 +#define NOTE_GS5 831 +#define NOTE_A5 880 +#define NOTE_AS5 932 +#define NOTE_B5 988 +#define NOTE_C6 1047 +#define NOTE_CS6 1109 +#define NOTE_D6 1175 +#define NOTE_DS6 1245 +#define NOTE_E6 1319 +#define NOTE_F6 1397 +#define NOTE_FS6 1480 +#define NOTE_G6 1568 +#define NOTE_GS6 1661 +#define NOTE_A6 1760 +#define NOTE_AS6 1865 +#define NOTE_B6 1976 +#define NOTE_C7 2093 +#define NOTE_CS7 2217 +#define NOTE_D7 2349 +#define NOTE_DS7 2489 +#define NOTE_E7 2637 +#define NOTE_F7 2794 +#define NOTE_FS7 2960 +#define NOTE_G7 3136 +#define NOTE_GS7 3322 +#define NOTE_A7 3520 +#define NOTE_AS7 3729 +#define NOTE_B7 3951 +#define NOTE_C8 4186 +#define NOTE_CS8 4435 +#define NOTE_D8 4699 +#define NOTE_DS8 4978 +#define REST 0 + +// notes of the melody followed by the duration. +// a 4 means a quarter note, 8 an eighteenth , 16 sixteenth, so on +// !!negative numbers are used to represent dotted notes, +// so -4 means a dotted quarter note, that is, a quarter plus an eighteenth!! +int melody[] = { + + // Darth Vader theme (Imperial March) - Star wars + // Score available at https://musescore.com/user/202909/scores/1141521 + // The tenor saxophone part was used + + NOTE_A4,-4, NOTE_A4,-4, NOTE_A4,16, NOTE_A4,16, NOTE_A4,16, NOTE_A4,16, NOTE_F4,8, REST,8, + NOTE_A4,-4, NOTE_A4,-4, NOTE_A4,16, NOTE_A4,16, NOTE_A4,16, NOTE_A4,16, NOTE_F4,8, REST,8, + NOTE_A4,4, NOTE_A4,4, NOTE_A4,4, NOTE_F4,-8, NOTE_C5,16, + + NOTE_A4,4, NOTE_F4,-8, NOTE_C5,16, NOTE_A4,2,//4 + NOTE_E5,4, NOTE_E5,4, NOTE_E5,4, NOTE_F5,-8, NOTE_C5,16, + NOTE_A4,4, NOTE_F4,-8, NOTE_C5,16, NOTE_A4,2, + + NOTE_A5,4, NOTE_A4,-8, NOTE_A4,16, NOTE_A5,4, NOTE_GS5,-8, NOTE_G5,16, //7 + NOTE_DS5,16, NOTE_D5,16, NOTE_DS5,8, REST,8, NOTE_A4,8, NOTE_DS5,4, NOTE_D5,-8, NOTE_CS5,16, + + NOTE_C5,16, NOTE_B4,16, NOTE_C5,16, REST,8, NOTE_F4,8, NOTE_GS4,4, NOTE_F4,-8, NOTE_A4,-16,//9 + NOTE_C5,4, NOTE_A4,-8, NOTE_C5,16, NOTE_E5,2, + + NOTE_A5,4, NOTE_A4,-8, NOTE_A4,16, NOTE_A5,4, NOTE_GS5,-8, NOTE_G5,16, //7 + NOTE_DS5,16, NOTE_D5,16, NOTE_DS5,8, REST,8, NOTE_A4,8, NOTE_DS5,4, NOTE_D5,-8, NOTE_CS5,16, + + NOTE_C5,16, NOTE_B4,16, NOTE_C5,16, REST,8, NOTE_F4,8, NOTE_GS4,4, NOTE_F4,-8, NOTE_A4,-16,//9 + NOTE_A4,4, NOTE_F4,-8, NOTE_C5,16, NOTE_A4,2, + +}; diff --git a/lib/lib_rf/RadioLib/examples/AFSK/AFSK_Tone/AFSK_Tone.ino b/lib/lib_rf/RadioLib/examples/AFSK/AFSK_Tone/AFSK_Tone.ino new file mode 100644 index 000000000..3e2212269 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/AFSK/AFSK_Tone/AFSK_Tone.ino @@ -0,0 +1,92 @@ +/* + RadioLib AFSK Example + + This example shows hot to send audio FSK tones + using SX1278's FSK modem. + + Other modules that can be used for AFSK: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create AFSK client instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 +AFSKClient audio(&radio, 5); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for AFSK + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize AFSK client + Serial.print(F("[AFSK] Initializing ... ")); + state = audio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + // AFSKClient can be used to transmit tones, + // same as Arduino tone() function + + // 400 Hz tone + Serial.print(F("[AFSK] 400 Hz tone ... ")); + audio.tone(400); + delay(1000); + + // silence + Serial.println(F("done!")); + audio.noTone(); + delay(1000); + + // AFSKClient can also be used to transmit HAM-friendly + // RTTY, Morse code, Hellschreiber, SSTV and AX.25. + // Details on how to use AFSK are in the example + // folders for each of the above modes. +} diff --git a/lib/lib_rf/RadioLib/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino b/lib/lib_rf/RadioLib/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino new file mode 100644 index 000000000..9394d9ab2 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino @@ -0,0 +1,101 @@ +/* + RadioLib AM-modulated AFSK Example + + This example shows hot to send AM-modulated + audio FSK tones using SX1278's OOK modem. + + Other modules that can be used for AFSK: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +SX1278 radio = new Module(10, 2, 9); + +// create AFSK client instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +AFSKClient audio(&radio, 5); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for AFSK + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize AFSK client + Serial.print(F("[AFSK] Initializing ... ")); + state = audio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // after that, set mode to OOK + Serial.print(F("[SX1278] Switching to OOK ... ")); + state = radio.setOOK(true); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + // AFSKClient can be used to transmit tones, + // same as Arduino tone() function + + // 400 Hz tone + Serial.print(F("[AFSK] 400 Hz tone ... ")); + audio.tone(400); + delay(1000); + + // silence + Serial.println(F("done!")); + audio.noTone(); + delay(1000); + + // AFSKClient can also be used to transmit HAM-friendly + // RTTY, Morse code, Hellschreiber, SSTV and AX.25. + // Details on how to use AFSK are in the example + // folders for each of the above modes. + + // CAUTION: Unlike standard AFSK, the result when using OOK + // must be demodulated as AM! +} diff --git a/lib/lib_rf/RadioLib/examples/APRS/APRS_MicE/APRS_MicE.ino b/lib/lib_rf/RadioLib/examples/APRS/APRS_MicE/APRS_MicE.ino new file mode 100644 index 000000000..5a84d0ea9 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/APRS/APRS_MicE/APRS_MicE.ino @@ -0,0 +1,119 @@ +/* + RadioLib APRS Mic-E Example + + This example sends APRS position reports + encoded in the Mic-E format using SX1278's + FSK modem. The data is modulated as AFSK + at 1200 baud using Bell 202 tones. + + DO NOT transmit in APRS bands unless + you have a ham radio license! + + Other modules that can be used for APRS: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - nRF24 + - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 +AFSKClient audio(&radio, 5); + +// create AX.25 client instance using the AFSK instance +AX25Client ax25(&audio); + +// create APRS client instance using the AX.25 client +APRSClient aprs(&ax25); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 + // NOTE: moved to ISM band on purpose + // DO NOT transmit in APRS bands without ham radio license! + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for AX.25 + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize AX.25 client + Serial.print(F("[AX.25] Initializing ... ")); + // source station callsign: "N7LEM" + // source station SSID: 0 + // preamble length: 8 bytes + state = ax25.begin("N7LEM"); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize APRS client + Serial.print(F("[APRS] Initializing ... ")); + // symbol: '>' (car) + state = aprs.begin('>'); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[APRS] Sending Mic-E position ... ")); + int state = aprs.sendMicE(49.1945, 16.6000, 120, 10, RADIOLIB_APRS_MIC_E_TYPE_EN_ROUTE); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait one minute before transmitting again + delay(60000); +} diff --git a/lib/lib_rf/RadioLib/examples/APRS/APRS_Position/APRS_Position.ino b/lib/lib_rf/RadioLib/examples/APRS/APRS_Position/APRS_Position.ino new file mode 100644 index 000000000..c05ac1947 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/APRS/APRS_Position/APRS_Position.ino @@ -0,0 +1,131 @@ +/* + RadioLib APRS Position Example + + This example sends APRS position reports + using SX1278's FSK modem. The data is + modulated as AFSK at 1200 baud using Bell + 202 tones. + + DO NOT transmit in APRS bands unless + you have a ham radio license! + + Other modules that can be used for APRS: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - nRF24 + - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 +AFSKClient audio(&radio, 5); + +// create AX.25 client instance using the AFSK instance +AX25Client ax25(&audio); + +// create APRS client instance using the AX.25 client +APRSClient aprs(&ax25); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 + // NOTE: moved to ISM band on purpose + // DO NOT transmit in APRS bands without ham radio license! + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(434.0); + + // when using one of the non-LoRa modules for AX.25 + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize AX.25 client + Serial.print(F("[AX.25] Initializing ... ")); + // source station callsign: "N7LEM" + // source station SSID: 0 + // preamble length: 8 bytes + state = ax25.begin("N7LEM"); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize APRS client + Serial.print(F("[APRS] Initializing ... ")); + // symbol: '>' (car) + state = aprs.begin('>'); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[APRS] Sending position ... ")); + + // send a location without message or timestamp + int state = aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E"); + delay(500); + + // send a location with message and without timestamp + state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!"); + delay(500); + + // send a location with message and timestamp + state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!", "093045z"); + delay(500); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait one minute before transmitting again + delay(60000); +} diff --git a/lib/lib_rf/RadioLib/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino b/lib/lib_rf/RadioLib/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino new file mode 100644 index 000000000..6b3053a1d --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino @@ -0,0 +1,95 @@ +/* + RadioLib APRS Position over LoRa Example + + This example sends APRS position reports + using SX1278's LoRa modem. + + Other modules that can be used for APRS: + - SX127x/RFM9x + - SX126x/LLCC68 + - SX128x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create APRS client instance using the LoRa radio +APRSClient aprs(&radio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with the settings necessary for LoRa iGates + Serial.print(F("[SX1278] Initializing ... ")); + // frequency: 433.775 MHz + // bandwidth: 125 kHz + // spreading factor: 12 + // coding rate: 4/5 + int state = radio.begin(433.775, 125, 12, 5); + + // when using one of the non-LoRa modules for AX.25 + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize APRS client + Serial.print(F("[APRS] Initializing ... ")); + // symbol: '>' (car) + // callsign "N7LEM" + // SSID 1 + state = aprs.begin('>', "N7LEM", 1); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[APRS] Sending position ... ")); + + // send a location with message and timestamp + // SSID is set to 1, as APRS over LoRa uses WIDE1-1 path by default + int state = aprs.sendPosition("GPS", 1, "4911.67N", "01635.96E", "I'm here!", "093045z"); + delay(500); + + // you can also send Mic-E encoded messages + state |= state = aprs.sendMicE(49.1945, 16.6000, 120, 10, RADIOLIB_APRS_MIC_E_TYPE_EN_ROUTE); + delay(500); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait one minute before transmitting again + delay(60000); +} diff --git a/lib/lib_rf/RadioLib/examples/AX25/AX25_Frames/AX25_Frames.ino b/lib/lib_rf/RadioLib/examples/AX25/AX25_Frames/AX25_Frames.ino new file mode 100644 index 000000000..809d7176c --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/AX25/AX25_Frames/AX25_Frames.ino @@ -0,0 +1,174 @@ +/* + RadioLib AX.25 Frame Example + + This example shows how to send various + AX.25 frames using SX1278's FSK modem. + + Other modules that can be used for AX.25: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + + Using raw AX.25 frames requires some + knowledge of the protocol, refer to + AX25_Transmit for basic operation. + Frames shown in this example are not + exhaustive; all possible AX.25 frames + should be supported. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AX.25 client instance using the FSK module +AX25Client ax25(&radio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 + Serial.print(F("[SX1278] Initializing ... ")); + // carrier frequency: 434.0 MHz + // bit rate: 1.2 kbps (1200 baud 2-FSK AX.25) + // frequency deviation: 0.5 kHz (1200 baud 2-FSK AX.25) + int state = radio.beginFSK(434.0, 1.2, 0.5); + + // when using one of the non-LoRa modules for AX.25 + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize AX.25 client + Serial.print(F("[AX.25] Initializing ... ")); + // source station callsign: "N7LEM" + // source station SSID: 0 + // preamble length: 8 bytes + state = ax25.begin("N7LEM"); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + // create AX.25 Unnumbered Information frame + // destination station callsign: "NJ7P" + // destination station SSID: 0 + // source station callsign: "N7LEM" + // source station SSID: 0 + // control field: UI, P/F not used, unnumbered frame + // protocol identifier: no layer 3 protocol implemented + // information field: "Hello World!" + AX25Frame frameUI("NJ7P", 0, "N7LEM", 0, RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | + RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME, + RADIOLIB_AX25_PID_NO_LAYER_3, "Hello World (unnumbered)!"); + + // send the frame + Serial.print(F("[AX.25] Sending UI frame ... ")); + int state = ax25.sendFrame(&frameUI); + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else { + // some error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + delay(1000); + + // create AX.25 Receive Ready frame + // destination station callsign: "NJ7P" + // destination station SSID: 0 + // source station callsign: "N7LEM" + // source station SSID: 0 + // control field: RR, P/F not used, supervisory frame + AX25Frame frameRR("NJ7P", 0, "N7LEM", 0, RADIOLIB_AX25_CONTROL_S_RECEIVE_READY | + RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_SUPERVISORY_FRAME); + + // set receive sequence number (0 - 7) + frameRR.setRecvSequence(0); + + // send the frame + Serial.print(F("[AX.25] Sending RR frame ... ")); + state = ax25.sendFrame(&frameRR); + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else { + // some error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + delay(1000); + + // create AX.25 Information frame + // destination station callsign: "NJ7P" + // destination station SSID: 0 + // source station callsign: "N7LEM" + // source station SSID: 0 + // control field: P/F not used, information frame + // protocol identifier: no layer 3 protocol implemented + // information field: "Hello World (numbered)!" + AX25Frame frameI("NJ7P", 0, "N7LEM", 0, RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | + RADIOLIB_AX25_CONTROL_INFORMATION_FRAME, RADIOLIB_AX25_PID_NO_LAYER_3, + "Hello World (numbered)!"); + + // set receive sequence number (0 - 7) + frameI.setRecvSequence(0); + + // set send sequence number (0 - 7) + frameI.setSendSequence(0); + + // send the frame + Serial.print(F("[AX.25] Sending I frame ... ")); + state = ax25.sendFrame(&frameI); + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else { + // some error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/AX25/AX25_Transmit/AX25_Transmit.ino b/lib/lib_rf/RadioLib/examples/AX25/AX25_Transmit/AX25_Transmit.ino new file mode 100644 index 000000000..98236d108 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/AX25/AX25_Transmit/AX25_Transmit.ino @@ -0,0 +1,94 @@ +/* + RadioLib AX.25 Transmit Example + + This example sends AX.25 messages using + SX1278's FSK modem. + + Other modules that can be used for AX.25: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AX.25 client instance using the FSK module +AX25Client ax25(&radio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 + Serial.print(F("[SX1278] Initializing ... ")); + // carrier frequency: 434.0 MHz + // bit rate: 1.2 kbps (1200 baud 2-FSK AX.25) + int state = radio.beginFSK(434.0, 1.2); + + // when using one of the non-LoRa modules for AX.25 + // (RF69, CC1101,, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize AX.25 client + Serial.print(F("[AX.25] Initializing ... ")); + // source station callsign: "N7LEM" + // source station SSID: 0 + // preamble length: 8 bytes + state = ax25.begin("N7LEM"); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + // send AX.25 unnumbered information frame + Serial.print(F("[AX.25] Sending UI frame ... ")); + // destination station callsign: "NJ7P" + // destination station SSID: 0 + int state = ax25.transmit("Hello World!", "NJ7P"); + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else { + // some error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino b/lib/lib_rf/RadioLib/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino new file mode 100644 index 000000000..f60818c30 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino @@ -0,0 +1,121 @@ +/* + RadioLib AX.25 Transmit AFSK Example + + This example sends AX.25 messages using + SX1278's FSK modem. The data is modulated + as AFSK at 1200 baud using Bell 202 tones. + + Other modules that can be used for AX.25 + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - nRF24 + - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 +AFSKClient audio(&radio, 5); + +// create AX.25 client instance using the AFSK instance +AX25Client ax25(&audio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for AX.25 + // (RF69, CC1101,, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize AX.25 client + Serial.print(F("[AX.25] Initializing ... ")); + // source station callsign: "N7LEM" + // source station SSID: 0 + // preamble length: 8 bytes + state = ax25.begin("N7LEM"); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // Sometimes, it may be required to adjust audio + // frequencies to match the expected 1200/2200 Hz tones. + // The following method will offset mark frequency by + // 100 Hz up and space frequency by 100 Hz down + /* + Serial.print(F("[AX.25] Setting correction ... ")); + state = ax25.setCorrection(100, -100); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ +} + +void loop() { + // send AX.25 unnumbered information frame + Serial.print(F("[AX.25] Sending UI frame ... ")); + // destination station callsign: "NJ7P" + // destination station SSID: 0 + int state = ax25.transmit("Hello World!", "NJ7P"); + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else { + // some error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino b/lib/lib_rf/RadioLib/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino new file mode 100644 index 000000000..7ac4d5b3f --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino @@ -0,0 +1,116 @@ +/* + RadioLib Bell Modem Transmit Example + + This example shows how to transmit binary data + using audio Bell 202 tones. + + Other implemented Bell modems + - Bell 101 + - Bell 103 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create Bell modem instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 (only devices without TCXO!) +BellClient bell(&radio, 5); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for AFSK + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize Bell 202 modem + Serial.print(F("[Bell 202] Initializing ... ")); + state = bell.begin(Bell202); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[Bell 202] Sending data ... ")); + + // send out idle condition for 500 ms + bell.idle(); + delay(500); + + // BellClient supports all methods of the Serial class + + // Arduino String class + String aStr = "Arduino String"; + bell.println(aStr); + + // character array (C-String) + bell.println("C-String"); + + // string saved in flash + bell.println(F("Flash String")); + + // character + bell.println('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + bell.println(255, HEX); + + // integer number + int i = 1000; + bell.println(i); + + // floating point number + float f = -3.1415; + bell.println(f, 3); + + // ITA2-encoded string + ITA2String str("HELLO WORLD!"); + bell.print(str); + + // turn the transmitter off + bell.standby(); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino new file mode 100644 index 000000000..2f912f081 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino @@ -0,0 +1,120 @@ +/* + RadioLib CC1101 Receive with Address Example + + This example receives packets using CC1101 FSK radio + module. Packets can have 1-byte address of the + destination node. After setting node address, this node + will automatically filter out any packets that do not + contain either node address or broadcast addresses. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// CC1101 has the following connections: +// CS pin: 10 +// GDO0 pin: 2 +// RST pin: unused +// GDO2 pin: 3 (optional) +CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//CC1101 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize CC1101 with default settings + Serial.print(F("[CC1101] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set node address + // NOTE: Calling this method will automatically enable + // address filtering. CC1101 also allows to set + // number of broadcast address (0/1/2). + // The following sets one broadcast address 0x00. + // When setting two broadcast addresses, 0x00 and + // 0xFF will be used. + Serial.print(F("[CC1101] Setting node address ... ")); + state = radio.setNodeAddress(0x01, 1); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // address filtering can also be disabled + // NOTE: Calling this method will also erase previously + // set node address + /* + Serial.print(F("[CC1101] Disabling address filtering ... ")); + state == radio.disableAddressFiltering(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ +} + +void loop() { + Serial.print(F("[CC1101] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[CC1101] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[CC1101] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print LQI (Link Quality Indicator) + // of the last received packet, lower is better + Serial.print(F("[CC1101] LQI:\t\t")); + Serial.println(radio.getLQI()); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino new file mode 100644 index 000000000..32dbe6bf1 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino @@ -0,0 +1,99 @@ +/* + RadioLib CC1101 Blocking Receive Example + + This example receives packets using CC1101 FSK radio module. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bit rate + - frequency deviation + - sync word + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// CC1101 has the following connections: +// CS pin: 10 +// GDO0 pin: 2 +// RST pin: unused +// GDO2 pin: 3 (optional) +CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//CC1101 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize CC1101 with default settings + Serial.print(F("[CC1101] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[CC1101] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[CC1101] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[CC1101] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print LQI (Link Quality Indicator) + // of the last received packet, lower is better + Serial.print(F("[CC1101] LQI:\t\t")); + Serial.println(radio.getLQI()); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino new file mode 100644 index 000000000..4f3e69d8e --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino @@ -0,0 +1,141 @@ +/* + RadioLib CC1101 Receive with Interrupts Example + + This example listens for FSK transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. + + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bit rate + - frequency deviation + - sync word + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// CC1101 has the following connections: +// CS pin: 10 +// GDO0 pin: 2 +// RST pin: unused +// GDO2 pin: 3 (optional) +CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//CC1101 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize CC1101 with default settings + Serial.print(F("[CC1101] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + radio.setPacketReceivedAction(setFlag); + + // start listening for packets + Serial.print(F("[CC1101] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[CC1101] Received packet!")); + + // print data of the packet + Serial.print(F("[CC1101] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[CC1101] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print LQI (Link Quality Indicator) + // of the last received packet, lower is better + Serial.print(F("[CC1101] LQI:\t\t")); + Serial.println(radio.getLQI()); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // put module back to listen mode + radio.startReceive(); + } + +} diff --git a/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Settings/CC1101_Settings.ino b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Settings/CC1101_Settings.ino new file mode 100644 index 000000000..680c60d11 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Settings/CC1101_Settings.ino @@ -0,0 +1,121 @@ +/* + RadioLib CC1101 Settings Example + + This example shows how to change all the properties of RF69 radio. + RadioLib currently supports the following settings: + - pins (SPI slave select, digital IO 0, digital IO 1) + - carrier frequency + - bit rate + - receiver bandwidth + - allowed frequency deviation + - output power during transmission + - sync word + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// CC1101 has the following connections: +// CS pin: 10 +// GDO0 pin: 2 +// RST pin: unused +// GDO2 pin: 3 (optional) +CC1101 radio1 = new Module(10, 2, RADIOLIB_NC, 3); + +// second CC1101 has different connections: +// CS pin: 9 +// GDO0 pin: 4 +// RST pin: unused +// GDO2 pin: 5 (optional) +CC1101 radio2 = new Module(9, 4, RADIOLIB_NC, 5); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//CC1101 radio3 = RadioShield.ModuleB; + +void setup() { + Serial.begin(9600); + + // initialize CC1101 with default settings + Serial.print(F("[CC1101] Initializing ... ")); + int state = radio1.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // initialize CC1101 with non-default settings + Serial.print(F("[CC1101] Initializing ... ")); + // carrier frequency: 434.0 MHz + // bit rate: 32.0 kbps + // frequency deviation: 60.0 kHz + // Rx bandwidth: 250.0 kHz + // output power: 7 dBm + // preamble length: 32 bits + state = radio2.begin(434.0, 32.0, 60.0, 250.0, 7, 32); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // you can also change the settings at runtime + // and check if the configuration was changed successfully + + // set carrier frequency to 433.5 MHz + if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { + Serial.println(F("[CC1101] Selected frequency is invalid for this module!")); + while (true); + } + + // set bit rate to 100.0 kbps + state = radio1.setBitRate(100.0); + if (state == RADIOLIB_ERR_INVALID_BIT_RATE) { + Serial.println(F("[CC1101] Selected bit rate is invalid for this module!")); + while (true); + } else if (state == RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO) { + Serial.println(F("[CC1101] Selected bit rate to bandwidth ratio is invalid!")); + Serial.println(F("[CC1101] Increase receiver bandwidth to set this bit rate.")); + while (true); + } + + // set receiver bandwidth to 250.0 kHz + if (radio1.setRxBandwidth(250.0) == RADIOLIB_ERR_INVALID_RX_BANDWIDTH) { + Serial.println(F("[CC1101] Selected receiver bandwidth is invalid for this module!")); + while (true); + } + + // set allowed frequency deviation to 10.0 kHz + if (radio1.setFrequencyDeviation(10.0) == RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION) { + Serial.println(F("[CC1101] Selected frequency deviation is invalid for this module!")); + while (true); + } + + // set output power to 5 dBm + if (radio1.setOutputPower(5) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + Serial.println(F("[CC1101] Selected output power is invalid for this module!")); + while (true); + } + + // 2 bytes can be set as sync word + if (radio1.setSyncWord(0x01, 0x23) == RADIOLIB_ERR_INVALID_SYNC_WORD) { + Serial.println(F("[CC1101] Selected sync word is invalid for this module!")); + while (true); + } + +} + +void loop() { + // nothing here +} diff --git a/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino new file mode 100644 index 000000000..4aa219d33 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino @@ -0,0 +1,107 @@ +/* + RadioLib CC1101 Transmit to Address Example + + This example transmits packets using CC1101 FSK radio + module. Packets can have 1-byte address of the + destination node. After setting node address, this node + will automatically filter out any packets that do not + contain either node address or broadcast addresses. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// CC1101 has the following connections: +// CS pin: 10 +// GDO0 pin: 2 +// RST pin: unused +// GDO2 pin: 3 (optional) +CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//CC1101 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize CC1101 with default settings + Serial.print(F("[CC1101] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set node address + // NOTE: Calling this method will automatically enable + // address filtering. CC1101 also allows to set + // number of broadcast address (0/1/2). + // The following sets one broadcast address 0x00. + // When setting two broadcast addresses, 0x00 and + // 0xFF will be used. + Serial.print(F("[CC1101] Setting node address ... ")); + state = radio.setNodeAddress(0x01, 1); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // address filtering can also be disabled + // NOTE: Calling this method will also erase previously + // set node address + /* + Serial.print(F("[CC1101] Disabling address filtering ... ")); + state == radio.disableAddressFiltering(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ +} + +void loop() { + Serial.print(F("[CC1101] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to 63 characters long + int state = radio.transmit("Hello World!"); + + // you can also transmit byte array up to 63 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 255 bytes + Serial.println(F("too long!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino new file mode 100644 index 000000000..fc62ec636 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino @@ -0,0 +1,83 @@ +/* + RadioLib CC1101 Blocking Transmit Example + + This example transmits packets using CC1101 FSK radio module. + Each packet contains up to 64 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// CC1101 has the following connections: +// CS pin: 10 +// GDO0 pin: 2 +// RST pin: unused +// GDO2 pin: 3 +CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//CC1101 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize CC1101 with default settings + Serial.print(F("[CC1101] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + Serial.print(F("[CC1101] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to 63 characters long + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); + + // you can also transmit byte array up to 63 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 64 bytes + Serial.println(F("too long!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino new file mode 100644 index 000000000..455d83ddf --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -0,0 +1,129 @@ +/* + RadioLib CC1101 Transmit with Interrupts Example + + This example transmits packets using CC1101 FSK radio module. + Once a packet is transmitted, an interrupt is triggered. + Each packet contains up to 64 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// CC1101 has the following connections: +// CS pin: 10 +// GDO0 pin: 2 +// RST pin: unused +// GDO2 pin: 3 +CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//CC1101 radio = RadioShield.ModuleA; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +void setup() { + Serial.begin(9600); + + // initialize CC1101 with default settings + Serial.print(F("[CC1101] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when packet transmission is finished + radio.setPacketSentAction(setFlag); + + // start transmitting the first packet + Serial.print(F("[CC1101] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 64 characters long + transmissionState = radio.startTransmit("Hello World!"); + + // you can also transmit byte array up to 64 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x56, + 0x78, 0xAB, 0xCD, 0xEF}; + state = radio.startTransmit(byteArr, 8); + */ +} + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + // NOTE: when using interrupt-driven transmit method, + // it is not possible to automatically measure + // transmission data rate using getDataRate() + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[CC1101] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.startTransmit(byteArr, 8); + */ + } +} diff --git a/lib/lib_rf/RadioLib/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino b/lib/lib_rf/RadioLib/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino new file mode 100644 index 000000000..8a1153b05 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino @@ -0,0 +1,142 @@ +/* + RadioLib FSK4 Transmit Example + + This example sends an example FSK-4 'Horus Binary' message + using SX1278's FSK modem. + + This signal can be demodulated using a SSB demodulator (SDR or otherwise), + and horusdemodlib: https://github.com/projecthorus/horusdemodlib/wiki + + Other modules that can be used for FSK4: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - SX128x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create FSK4 client instance using the FSK module +FSK4Client fsk4(&radio); + +// An encoded Horus Binary telemetry packet. +// Refer here for packet format information: +// https://github.com/projecthorus/horusdemodlib/wiki/2---Modem-Details#horus-binary-v1-mode-4-fsk +// After demodulation, deinterleaving, and descrambling, this results in a packet: +// 00000001172D0000000000000000D20463010AFF2780 +// This decodes to the Habitat-compatible telemetry string: +// $$4FSKTEST,0,01:23:45,0.00000,0.00000,1234,99,1,10,5.00*ABCD +int horusPacketLen = 45; +byte horusPacket[] = { + 0x45, 0x24, 0x24, 0x48, 0x2F, 0x12, 0x16, 0x08, 0x15, 0xC1, + 0x49, 0xB2, 0x06, 0xFC, 0x92, 0xEB, 0x93, 0xD7, 0xEE, 0x5D, + 0x35, 0xA0, 0x91, 0xDA, 0x8D, 0x5F, 0x85, 0x6B, 0x63, 0x03, + 0x6B, 0x60, 0xEA, 0xFE, 0x55, 0x9D, 0xF1, 0xAB, 0xE5, 0x5E, + 0xDB, 0x7C, 0xDB, 0x21, 0x5A, 0x19 +}; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for FSK4 + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize FSK4 client + // NOTE: FSK4 frequency shift will be rounded + // to the nearest multiple of frequency step size. + // The exact value depends on the module: + // SX127x/RFM9x - 61 Hz + // RF69 - 61 Hz + // CC1101 - 397 Hz + // SX126x - 1 Hz + // nRF24 - 1000000 Hz + // Si443x/RFM2x - 156 Hz + // SX128x - 198 Hz + Serial.print(F("[FSK4] Initializing ... ")); + // low ("space") frequency: 434.0 MHz + // frequency shift: 270 Hz + // baud rate: 100 baud + state = fsk4.begin(434.0, 270, 100); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // sometimes, it may be needed to set some manual corrections + // this can be done for tone frequencies, + // as well as tone lengths + /* + // set frequency shift offsets to -120, 60, 0 and 60 Hz and decrease tone length to 95% + int offsets[4] = { -120, -60, 0, 60 }; + Serial.print(F("[FSK4] Setting corrections ... ")); + state = fsk4.setCorrection(offsets, 0.95); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ +} + +void loop() { + Serial.print(F("[FSK4] Sending FSK4 data packet ... ")); + + // send out idle condition for 1000 ms + fsk4.idle(); + delay(1000); + + // FSK4Client supports binary write methods + + // send some bytes as a preamble + for(int i = 0; i < 8; i++) { + fsk4.write(0x1B); + } + + // now send the encoded packet + fsk4.write(horusPacket, horusPacketLen); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino b/lib/lib_rf/RadioLib/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino new file mode 100644 index 000000000..9c3209181 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino @@ -0,0 +1,143 @@ +/* + RadioLib FSK4 Transmit AFSK Example + + This example sends an example FSK-4 'Horus Binary' message + using SX1278's FSK modem. The data is modulated as AFSK. + + This signal can be demodulated using an FM demodulator (SDR or otherwise), + and horusdemodlib: https://github.com/projecthorus/horusdemodlib/wiki + + Other modules that can be used for FSK4: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 +AFSKClient audio(&radio, 5); + +// create FSK4 client instance using the AFSK instance +FSK4Client fsk4(&audio); + +// An encoded Horus Binary telemetry packet. +// Refer here for packet format information: +// https://github.com/projecthorus/horusdemodlib/wiki/2---Modem-Details#horus-binary-v1-mode-4-fsk +// After demodulation, deinterleaving, and descrambling, this results in a packet: +// 00000001172D0000000000000000D20463010AFF2780 +// This decodes to the Habitat-compatible telemetry string: +// $$4FSKTEST,0,01:23:45,0.00000,0.00000,1234,99,1,10,5.00*ABCD +int horusPacketLen = 45; +byte horusPacket[] = { + 0x45, 0x24, 0x24, 0x48, 0x2F, 0x12, 0x16, 0x08, 0x15, 0xC1, + 0x49, 0xB2, 0x06, 0xFC, 0x92, 0xEB, 0x93, 0xD7, 0xEE, 0x5D, + 0x35, 0xA0, 0x91, 0xDA, 0x8D, 0x5F, 0x85, 0x6B, 0x63, 0x03, + 0x6B, 0x60, 0xEA, 0xFE, 0x55, 0x9D, 0xF1, 0xAB, 0xE5, 0x5E, + 0xDB, 0x7C, 0xDB, 0x21, 0x5A, 0x19 +}; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for RTTY + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize FSK4 client + // NOTE: Unlike FSK FSK4, AFSK requires no rounding of + // the frequency shift. + Serial.print(F("[FSK4] Initializing ... ")); + // lowest ("space") frequency: 400 Hz + // frequency shift: 270 Hz + // baud rate: 100 baud + state = fsk4.begin(400, 270, 100); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // sometimes, it may be needed to set some manual corrections + // this can be done for tone frequencies, + // as well as tone lengths + /* + // set audio tone offsets to -10, 20, 0 and 5 Hz and decrease tone length to 95% + int offsets[4] = { -10, 20, 0, 5 }; + Serial.print(F("[FSK4] Setting corrections ... ")); + state = fsk4.setCorrection(offsets, 0.95); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ +} + +void loop() { + Serial.print(F("[FSK4] Sending FSK4 data packet ... ")); + + // send out idle condition for 500 ms + fsk4.idle(); + delay(1000); + + // FSK4Client supports binary write methods + + // send some bytes as a preamble + for(int i = 0; i < 8; i++) { + fsk4.write(0x1B); + } + + // now send the encoded packet + fsk4.write(horusPacket, horusPacketLen); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino b/lib/lib_rf/RadioLib/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino new file mode 100644 index 000000000..8374da597 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino @@ -0,0 +1,116 @@ +/* + RadioLib Hellschreiber Transmit Example + + This example sends Hellschreiber message using + SX1278's FSK modem. + + Other modules that can be used for Hellschreiber: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - SX128x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create Hellschreiber client instance using the FSK module +HellClient hell(&radio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for Morse code + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize Hellschreiber client + Serial.print(F("[Hell] Initializing ... ")); + // base frequency: 434.0 MHz + // speed: 122.5 Baud ("Feld Hell") + state = hell.begin(434.0); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[Hell] Sending Hellschreiber data ... ")); + + // HellClient supports all methods of the Serial class + // NOTE: Lower case letter will be capitalized. + + // Arduino String class + String aStr = "Arduino String"; + hell.print(aStr); + + // character array (C-String) + hell.print("C-String"); + + // string saved in flash + hell.print(F("Flash String")); + + // character + hell.print('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + hell.print(255, HEX); + + // integer number + int i = 1000; + hell.print(i); + + // floating point number + // NOTE: println() has no effect on the transmission, + // and is only kept for compatibility reasons. + float f = -3.1415; + hell.println(f, 3); + + // custom glyph - must be a 7 byte array of rows 7 pixels long + uint8_t customGlyph[] = { 0b0000000, 0b0010100, 0b0010100, 0b0000000, 0b0100010, 0b0011100, 0b0000000 }; + hell.printGlyph(customGlyph); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino b/lib/lib_rf/RadioLib/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino new file mode 100644 index 000000000..dbe267a5a --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino @@ -0,0 +1,133 @@ +/* + RadioLib Hellschreiber Transmit AFSK Example + + This example sends Hellschreiber message using + SX1278's FSK modem. The data is modulated + as AFSK. + + Other modules that can be used for Hellschreiber + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 +AFSKClient audio(&radio, 5); + +// create Hellschreiber client instance using the AFSK instance +HellClient hell(&audio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for Morse code + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize Hellschreiber client + Serial.print(F("[Hell] Initializing ... ")); + // AFSK tone frequency: 400 Hz + // speed: 122.5 Baud ("Feld Hell") + state = hell.begin(400); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[Hell] Sending Hellschreiber data ... ")); + + // HellClient supports all methods of the Serial class + // NOTE: Lower case letter will be capitalized. + + // Arduino String class + String aStr = "Arduino String"; + hell.print(aStr); + + // character array (C-String) + hell.print("C-String"); + + // string saved in flash + hell.print(F("Flash String")); + + // in AFSK mode, it is possible to invert the text colors + // use white text on black background + hell.setInversion(true); + hell.print("Inverted String"); + hell.setInversion(false); + + // character + hell.print('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + hell.print(255, HEX); + + // integer number + int i = 1000; + hell.print(i); + + // floating point number + // NOTE: println() has no effect on the transmission, + // and is only kept for compatibility reasons. + float f = -3.1415; + hell.println(f, 3); + + // custom glyph - must be a 7 byte array of rows 7 pixels long + uint8_t customGlyph[] = { 0b0000000, 0b0010100, 0b0010100, 0b0000000, 0b0100010, 0b0011100, 0b0000000 }; + hell.printGlyph(customGlyph); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino new file mode 100644 index 000000000..d4ec506d1 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -0,0 +1,171 @@ +/* + RadioLib LoRaWAN End Device Example + + This example joins a LoRaWAN network and will send + uplink packets. Before you start, you will have to + register your device at https://www.thethingsnetwork.org/ + After your device is registered, you can run this example. + The device will join the network and start uploading data. + + NOTE: LoRaWAN v1.1 requires storing parameters persistently! + RadioLib does this by using EEPROM (persistent storage), + by default starting at address 0 and using 448 bytes. + If you already use EEPROM in your application, + you will have to either avoid this range, or change it + by setting a different start address by changing the value of + RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either + during build or in src/BuildOpt.h. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following pin order: +// Module(NSS/CS, DIO1, RESET, BUSY) +// SX1262 radio = new Module(8, 14, 12, 13); + +// SX1278 has the following pin order: +// Module(NSS/CS, DIO0, RESET, DIO1) +SX1278 radio = new Module(10, 2, 9, 3); + +// create the node instance on the EU-868 band +// using the radio module and the encryption key +// make sure you are using the correct band +// based on your geographical location! +LoRaWANNode node(&radio, &EU868); + +// for fixed bands with subband selection +// such as US915 and AU915, you must specify +// the subband that matches the Frequency Plan +// that you selected on your LoRaWAN console +/* + LoRaWANNode node(&radio, &US915, 2); +*/ + +void setup() { + Serial.begin(9600); + + // initialize radio (SX1262 / SX1278 / ... ) with default settings + Serial.print(F("[Radio] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // application identifier - pre-LoRaWAN 1.1.0, this was called appEUI + // when adding new end device in TTN, you will have to enter this number + // you can pick any number you want, but it has to be unique + uint64_t joinEUI = 0x12AD1011B0C0FFEE; + + // device identifier - this number can be anything + // when adding new end device in TTN, you can generate this number, + // or you can set any value you want, provided it is also unique + uint64_t devEUI = 0x70B3D57ED005E120; + + // select some encryption keys which will be used to secure the communication + // there are two of them - network key and application key + // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long + + // network key is the ASCII string "topSecretKey1234" + uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; + + // application key is the ASCII string "aDifferentKeyABC" + uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; + + // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used + // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded + // and can be set to NULL + + + // on EEPROM-enabled boards, after the device has been activated, + // the session can be restored without rejoining after device power cycle + // this is intrinsically done when calling `beginOTAA()` with the same keys + // in that case, the function will not need to transmit a JoinRequest + + // now we can start the activation + // this can take up to 10 seconds, and requires a LoRaWAN gateway in range + // a specific starting-datarate can be selected in dynamic bands (e.g. EU868): + /* + uint8_t joinDr = 4; + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDr); + */ + Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + + if(state >= RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + delay(2000); // small delay between joining and uplink + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // send uplink to port 10 + Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); + String strUp = "Hello!" + String(count++); + String strDown; + int state = node.sendReceive(strUp, 10, strDown); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("received a downlink!")); + + // print data of the packet (if there are any) + Serial.print(F("[LoRaWAN] Data:\t\t")); + if(strDown.length() > 0) { + Serial.println(strDown); + } else { + Serial.println(F("")); + } + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LoRaWAN] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LoRaWAN] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[LoRaWAN] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("no downlink!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // on EEPROM enabled boards, you should save the current session + // by calling "saveSession" which allows retrieving the session after reboot or deepsleep + node.saveSession(); + + // wait before sending another packet + uint32_t minimumDelay = 60000; // try to send once every minute + uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) + uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows + + delay(delayMs); +} diff --git a/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino b/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino new file mode 100644 index 000000000..02089e4bc --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino @@ -0,0 +1,178 @@ +/* + RadioLib LoRaWAN End Device ABP Example + + This example sets up a LoRaWAN node using ABP (activation + by personalization). Before you start, you will have to + register your device at https://www.thethingsnetwork.org/ + After your device is registered, you can run this example. + The device will start uploading data directly, + without having to join the network. + + NOTE: LoRaWAN v1.1 requires storing parameters persistently! + RadioLib does this by using EEPROM (persistent storage), + by default starting at address 0 and using 448 bytes. + If you already use EEPROM in your application, + you will have to either avoid this range, or change it + by setting a different start address by changing the value of + RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either + during build or in src/BuildOpt.h. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following pin order: +// Module(NSS/CS, DIO1, RESET, BUSY) +// SX1262 radio = new Module(8, 14, 12, 13); + +// SX1278 has the following pin order: +// Module(NSS/CS, DIO0, RESET, DIO1) +SX1278 radio = new Module(10, 2, 9, 3); + +// create the node instance on the EU-868 band +// using the radio module and the encryption key +// make sure you are using the correct band +// based on your geographical location! +LoRaWANNode node(&radio, &EU868); + +// for fixed bands with subband selection +// such as US915 and AU915, you must specify +// the subband that matches the Frequency Plan +// that you selected on your LoRaWAN console +/* + LoRaWANNode node(&radio, &US915, 2); +*/ + +void setup() { + Serial.begin(9600); + + // initialize radio (SX1262 / SX1278 / ... ) with default settings + Serial.print(F("[Radio] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // device address - this number can be anything + // when adding new end device in TTN, you can generate this number, + // or you can set any value you want, provided it is unique + uint32_t devAddr = 0x12345678; + + // select some encryption keys which will be used to secure the communication + // there are two of them - network key and application key + // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long + + // network key is the ASCII string "topSecretKey1234" + uint8_t nwkSKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; + + // application key is the ASCII string "aDifferentKeyABC" + uint8_t appSKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; + + // network key 2 is the ASCII string "topSecretKey5678" + uint8_t fNwkSIntKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x4B, 0x65, 0x35, 0x36, 0x37, 0x38 }; + + // network key 3 is the ASCII string "aDifferentKeyDEF" + uint8_t sNwkSIntKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x44, 0x45, 0x46 }; + + // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used + // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded + // and can be set to NULL + + + // if using EU868 on ABP in TTN, you need to set the SF for RX2 window manually + /* + node.rx2.drMax = 3; + */ + + // on EEPROM-enabled boards, after the device has been activated, + // the session can be restored without rejoining after device power cycle + // this is intrinsically done when calling `beginABP()` with the same keys + // in that case, the function will not need to transmit a JoinRequest + + // to start a LoRaWAN v1.0 session, + // the user can remove the fNwkSIntKey and sNwkSIntKey + /* + state = node.beginABP(devAddr, nwkSKey, appSKey); + */ + + // start the device by directly providing the encryption keys and device address + Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); + state = node.beginABP(devAddr, nwkSKey, appSKey, fNwkSIntKey, sNwkSIntKey); + if(state >= RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // send uplink to port 10 + Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); + String strUp = "Hello!" + String(count++); + String strDown; + int state = node.sendReceive(strUp, 10, strDown); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("received a downlink!")); + + // print data of the packet (if there are any) + Serial.print(F("[LoRaWAN] Data:\t\t")); + if(strDown.length() > 0) { + Serial.println(strDown); + } else { + Serial.println(F("")); + } + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LoRaWAN] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LoRaWAN] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[LoRaWAN] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("no downlink!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // on EEPROM enabled boards, you should save the current session + // by calling "saveSession" which allows retrieving the session after reboot or deepsleep + node.saveSession(); + + // wait before sending another packet + uint32_t minimumDelay = 60000; // try to send once every minute + uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) + uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows + + delay(delayMs); +} diff --git a/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino new file mode 100644 index 000000000..207dd356d --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -0,0 +1,296 @@ +/* + RadioLib LoRaWAN End Device Reference Example + + This example joins a LoRaWAN network and will send + uplink packets. Before you start, you will have to + register your device at https://www.thethingsnetwork.org/ + After your device is registered, you can run this example. + The device will join the network and start uploading data. + + Also, most of the possible and available functions are + shown here for reference. + + LoRaWAN v1.1 requires the use of EEPROM (persistent storage). + Please refer to the 'persistent' example once you are familiar + with LoRaWAN. + Running this examples REQUIRES you to check "Resets DevNonces" + on your LoRaWAN dashboard. Refer to the network's + documentation on how to do this. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following pin order: +// Module(NSS/CS, DIO1, RESET, BUSY) +// SX1262 radio = new Module(8, 14, 12, 13); + +// SX1278 has the following pin order: +// Module(NSS/CS, DIO0, RESET, DIO1) +SX1278 radio = new Module(10, 2, 9, 3); + +// create the node instance on the EU-868 band +// using the radio module and the encryption key +// make sure you are using the correct band +// based on your geographical location! +LoRaWANNode node(&radio, &EU868); + +// for fixed bands with subband selection +// such as US915 and AU915, you must specify +// the subband that matches the Frequency Plan +// that you selected on your LoRaWAN console +/* + LoRaWANNode node(&radio, &US915, 2); +*/ + +void setup() { + Serial.begin(9600); + + // initialize radio (SX1262 / SX1278 / ... ) with default settings + Serial.print(F("[Radio] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // application identifier - pre-LoRaWAN 1.1.0, this was called appEUI + // when adding new end device in TTN, you will have to enter this number + // you can pick any number you want, but it has to be unique + uint64_t joinEUI = 0x12AD1011B0C0FFEE; + + // device identifier - this number can be anything + // when adding new end device in TTN, you can generate this number, + // or you can set any value you want, provided it is also unique + uint64_t devEUI = 0x70B3D57ED005E120; + + // select some encryption keys which will be used to secure the communication + // there are two of them - network key and application key + // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long + + // network key is the ASCII string "topSecretKey1234" + uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; + + // application key is the ASCII string "aDifferentKeyABC" + uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; + + // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used + // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded + // and can be set to NULL + + + // now we can start the activation + // this can take up to 10 seconds, and requires a LoRaWAN gateway in range + // a specific starting-datarate can be selected in dynamic bands (e.g. EU868): + /* + uint8_t joinDr = 4; + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDr); + */ + Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + + if(state >= RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + delay(2000); // small delay between joining and uplink + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + Serial.print("[LoRaWAN] DevAddr: "); + Serial.println(node.getDevAddr(), HEX); + + // on EEPROM-enabled boards, after the device has been activated, + // the session can be restored without rejoining after device power cycle + // this is intrinsically done when calling `beginOTAA()` with the same keys + // or if you 'lost' the keys or don't want them included in your sketch + // you can call `restore()` + /* + Serial.print(F("[LoRaWAN] Resuming previous session ... ")); + state = node.restore(); + if(state >= RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ + + // disable the ADR algorithm + node.setADR(false); + + // set a fixed datarate + node.setDatarate(5); + // in order to set the datarate persistent across reboot/deepsleep, use the following: + /* + node.setDatarate(5, true); + */ + + // enable CSMA + // this tries to minimize packet loss by searching for a free channel + // before actually sending an uplink + node.setCSMA(6, 2, true); + + // enable or disable the dutycycle + // the second argument specific allowed airtime per hour in milliseconds + // 1250 = TTN FUP (30 seconds / 24 hours) + // if not called, this corresponds to setDutyCycle(true, 0) + // setting this to 0 corresponds to the band's maximum allowed dutycycle by law + node.setDutyCycle(true, 1250); + + // enable or disable the dwell time limits + // the second argument specifies the allowed airtime per uplink in milliseconds + // unless specified, this argument is set to 0 + // setting this to 0 corresponds to the band's maximum allowed dwell time by law + node.setDwellTime(true, 400); +} + +void loop() { + int state = RADIOLIB_ERR_NONE; + + // set battery fill level - the LoRaWAN network server + // may periodically request this information + // 0 = external power source + // 1 = lowest (empty battery) + // 254 = highest (full battery) + // 255 = unable to measure + uint8_t battLevel = 146; + node.setDeviceStatus(battLevel); + + // retrieve the last uplink frame counter + uint32_t fcntUp = node.getFcntUp(); + + Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); + String strUp = "Hello!" + String(fcntUp); + + // send a confirmed uplink to port 10 every 64th frame + // and also request the LinkCheck and DeviceTime MAC commands + if(fcntUp % 64 == 0) { + node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK); + node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME); + state = node.uplink(strUp, 10, true); + } else { + state = node.uplink(strUp, 10); + } + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // after uplink, you can call downlink(), + // to receive any possible reply from the server + // this function must be called within a few seconds + // after uplink to receive the downlink! + Serial.print(F("[LoRaWAN] Waiting for downlink ... ")); + String strDown; + + // you can also retrieve additional information about + // uplink or downlink by passing a reference to + // LoRaWANEvent_t structure + LoRaWANEvent_t event; + state = node.downlink(strDown, &event); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + + // print data of the packet (if there are any) + Serial.print(F("[LoRaWAN] Data:\t\t")); + if(strDown.length() > 0) { + Serial.println(strDown); + } else { + Serial.println(F("")); + } + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LoRaWAN] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LoRaWAN] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[LoRaWAN] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + // print extra information about the event + Serial.println(F("[LoRaWAN] Event information:")); + Serial.print(F("[LoRaWAN] Direction:\t")); + if(event.dir == RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK) { + Serial.println(F("uplink")); + } else { + Serial.println(F("downlink")); + } + Serial.print(F("[LoRaWAN] Confirmed:\t")); + Serial.println(event.confirmed); + Serial.print(F("[LoRaWAN] Confirming:\t")); + Serial.println(event.confirming); + Serial.print(F("[LoRaWAN] Datarate:\t")); + Serial.println(event.datarate); + Serial.print(F("[LoRaWAN] Frequency:\t")); + Serial.print(event.freq, 3); + Serial.println(F(" MHz")); + Serial.print(F("[LoRaWAN] Output power:\t")); + Serial.print(event.power); + Serial.println(F(" dBm")); + Serial.print(F("[LoRaWAN] Frame count:\t")); + Serial.println(event.fcnt); + Serial.print(F("[LoRaWAN] Port:\t\t")); + Serial.println(event.port); + + Serial.print(radio.getFrequencyError()); + + uint8_t margin = 0; + uint8_t gwCnt = 0; + if(node.getMacLinkCheckAns(&margin, &gwCnt) == RADIOLIB_ERR_NONE) { + Serial.print(F("[LoRaWAN] LinkCheck margin:\t")); + Serial.println(margin); + Serial.print(F("[LoRaWAN] LinkCheck count:\t")); + Serial.println(gwCnt); + } + + uint32_t networkTime = 0; + uint8_t fracSecond = 0; + if(node.getMacDeviceTimeAns(&networkTime, &fracSecond, true) == RADIOLIB_ERR_NONE) { + Serial.print(F("[LoRaWAN] DeviceTime Unix:\t")); + Serial.println(networkTime); + Serial.print(F("[LoRaWAN] DeviceTime second:\t1/")); + Serial.println(fracSecond); + } + + } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("timeout!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // on EEPROM enabled boards, you should save the current session + // by calling "saveSession" which allows retrieving the session after reboot or deepsleep + node.saveSession(); + + // wait before sending another packet + uint32_t minimumDelay = 60000; // try to send once every minute + uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) + uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows + + delay(delayMs); +} diff --git a/lib/lib_rf/RadioLib/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino b/lib/lib_rf/RadioLib/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino new file mode 100644 index 000000000..c078173f6 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino @@ -0,0 +1,115 @@ +/* + RadioLib SX127x Morse Receive AM Example + + This example receives Morse code message using + SX1278's FSK modem. The signal is expected to be + modulated as OOK, to be demodulated in AM mode. + + Other modules that can be used for Morse Code + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// pin 5 is connected to SX1278 DIO2 +AFSKClient audio(&radio, 5); + +// create Morse client instance using the AFSK instance +MorseClient morse(&audio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // when using one of the non-LoRa modules for Morse code + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + // initialize Morse client + Serial.print(F("[Morse] Initializing ... ")); + // AFSK tone frequency: 400 Hz + // speed: 20 words per minute + state = morse.begin(400); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // after that, set mode to OOK to emulate AM modulation + Serial.print(F("[SX1278] Switching to OOK ... ")); + state = radio.setOOK(true); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // start direct mode reception + radio.receiveDirect(); +} + +// save symbol and length between loops +byte symbol = 0; +byte len = 0; + +void loop() { + // try to read a new symbol + int state = morse.read(&symbol, &len); + + // check if we have something to decode + if(state != RADIOLIB_MORSE_INTER_SYMBOL) { + // decode and print + Serial.print(MorseClient::decode(symbol, len)); + + // reset the symbol buffer + symbol = 0; + len = 0; + + // check if we have a complete word + if(state == RADIOLIB_MORSE_WORD_COMPLETE) { + // inter-word space, interpret that as a new line + Serial.println(); + } + + } + +} diff --git a/lib/lib_rf/RadioLib/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino b/lib/lib_rf/RadioLib/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino new file mode 100644 index 000000000..6bedffa67 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino @@ -0,0 +1,131 @@ +/* + RadioLib Morse Transmit AM Example + + This example sends Morse code message using + SX1278's FSK modem. The signal is modulated + as OOK, and may be demodulated in AM mode. + + Other modules that can be used for Morse Code + with AM modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// pin 5 is connected to SX1278 DIO2 +AFSKClient audio(&radio, 5); + +// create Morse client instance using the AFSK instance +MorseClient morse(&audio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for Morse code + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize Morse client + Serial.print(F("[Morse] Initializing ... ")); + // tone frequency: 400 Hz + // speed: 20 words per minute + state = morse.begin(400); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // after that, set mode to OOK to emulate AM modulation + Serial.print(F("[SX1278] Switching to OOK ... ")); + state = radio.setOOK(true); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[Morse] Sending Morse data ... ")); + + // MorseClient supports all methods of the Serial class + // NOTE: Characters that do not have ITU-R M.1677-1 + // representation will not be sent! Lower case + // letters will be capitalized. + + // send start signal first + morse.startSignal(); + + // Arduino String class + String aStr = "Arduino String"; + morse.print(aStr); + + // character array (C-String) + morse.print("C-String"); + + // string saved in flash + morse.print(F("Flash String")); + + // character + morse.print('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + morse.print(255, HEX); + + // integer number + int i = 1000; + morse.print(i); + + // floating point number + // NOTE: When using println(), the transmission will be + // terminated with end-of-work signal (...-.-). + float f = -3.1415; + morse.println(f, 3); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino b/lib/lib_rf/RadioLib/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino new file mode 100644 index 000000000..3ab9d08df --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino @@ -0,0 +1,128 @@ +/* + RadioLib Morse Transmit AFSK Example + + This example sends Morse code message using + SX1278's FSK modem. The signal is modulated + as AFSK, and may be demodulated in FM mode. + + Other modules that can be used for Morse Code + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 +AFSKClient audio(&radio, 5); + +// create Morse client instance using the AFSK instance +MorseClient morse(&audio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for Morse code + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize Morse client + Serial.print(F("[Morse] Initializing ... ")); + // tone frequency: 400 Hz + // speed: 20 words per minute + state = morse.begin(400); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[Morse] Sending Morse data ... ")); + + // MorseClient supports all methods of the Serial class + // NOTE: Characters that do not have ITU-R M.1677-1 + // representation will not be sent! Lower case + // letters will be capitalized. + + // send start signal first + morse.startSignal(); + + // Arduino String class + String aStr = "Arduino String"; + morse.print(aStr); + + // character array (C-String) + morse.print("C-String"); + + // string saved in flash + morse.print(F("Flash String")); + + // character + morse.print('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + morse.print(255, HEX); + + // integer number + int i = 1000; + morse.print(i); + + // floating point number + // NOTE: When using println(), the transmission will be + // terminated with end-of-work signal (...-.-). + float f = -3.1415; + morse.println(f, 3); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino b/lib/lib_rf/RadioLib/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino new file mode 100644 index 000000000..61abde3a5 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino @@ -0,0 +1,118 @@ +/* + RadioLib Morse Transmit SSB Example + + This example sends Morse code message using + SX1278's FSK modem. The signal is an unmodulated + carrier wave, and may be demodulated in SSB mode. + + Other modules that can be used for Morse Code: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - SX128x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create Morse client instance using the FSK module +MorseClient morse(&radio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for Morse code + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize Morse client + Serial.print(F("[Morse] Initializing ... ")); + // carrier wave frequency: 434.0 MHz + // speed: 20 words per minute + state = morse.begin(434.0); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[Morse] Sending Morse data ... ")); + + // MorseClient supports all methods of the Serial class + // NOTE: Characters that do not have ITU-R M.1677-1 + // representation will not be sent! Lower case + // letters will be capitalized. + + // send start signal first + morse.startSignal(); + + // Arduino String class + String aStr = "Arduino String"; + morse.print(aStr); + + // character array (C-String) + morse.print("C-String"); + + // string saved in flash + morse.print(F("Flash String")); + + // character + morse.print('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + morse.print(255, HEX); + + // integer number + int i = 1000; + morse.print(i); + + // floating point number + // NOTE: When using println(), the transmission will be + // terminated with end-of-work signal (...-.-). + float f = -3.1415; + morse.println(f, 3); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/Pager/Pager_Receive/Pager_Receive.ino b/lib/lib_rf/RadioLib/examples/Pager/Pager_Receive/Pager_Receive.ino new file mode 100644 index 000000000..c8368930e --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Pager/Pager_Receive/Pager_Receive.ino @@ -0,0 +1,129 @@ +/* + RadioLib Pager (POCSAG) Receive Example + + This example shows how to receive FSK packets without using + SX127x packet engine. + + This example receives POCSAG messages using SX1278's + FSK modem in direct mode. + + Other modules that can be used to receive POCSAG: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// receiving packets requires connection +// to the module direct output pin, +// here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 +const int pin = 5; + +// create Pager client instance using the FSK module +PagerClient pager(&radio); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // initialize Pager client + Serial.print(F("[Pager] Initializing ... ")); + // base (center) frequency: 434.0 MHz + // speed: 1200 bps + state = pager.begin(434.0, 1200); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // start receiving POCSAG messages + Serial.print(F("[Pager] Starting to listen ... ")); + // address of this "pager": 1234567 + state = pager.startReceive(pin, 1234567); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + +} + +void loop() { + // the number of batches to wait for + // 2 batches will usually be enough to fit short and medium messages + if (pager.available() >= 2) { + Serial.print(F("[Pager] Received pager data, decoding ... ")); + + // you can read the data as an Arduino String + String str; + int state = pager.readData(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + size_t numBytes = 0; + int state = radio.receive(byteArr, &numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + + // print the received data + Serial.print(F("[Pager] Data:\t")); + Serial.println(str); + + } else { + // some error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + } +} diff --git a/lib/lib_rf/RadioLib/examples/Pager/Pager_Transmit/Pager_Transmit.ino b/lib/lib_rf/RadioLib/examples/Pager/Pager_Transmit/Pager_Transmit.ino new file mode 100644 index 000000000..d23452d41 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Pager/Pager_Transmit/Pager_Transmit.ino @@ -0,0 +1,102 @@ +/* + RadioLib Pager (POCSAG) Transmit Example + + This example sends POCSAG messages using SX1278's + FSK modem. + + Other modules that can be used to send POCSAG: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - SX128x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create Pager client instance using the FSK module +PagerClient pager(&radio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize Pager client + Serial.print(F("[Pager] Initializing ... ")); + // base (center) frequency: 434.0 MHz + // speed: 1200 bps + state = pager.begin(434.0, 1200); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[Pager] Transmitting messages ... ")); + + // the simples form of "message" is just a tone on the destination pager + int state = pager.sendTone(1234567); + delay(500); + + // next, transmit numeric (BCD) message to the destination pager + // NOTE: Only characters 0123456789*U-() and space + // can be sent in a BCD message! + state |= pager.transmit("0123456789*U -()", 1234567); + delay(500); + + // finally, let's transmit an ASCII message now + state |= pager.transmit("Hello World!", 1234567, RADIOLIB_PAGER_ASCII); + delay(500); + + // we can also send only a tone + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait for a second before transmitting again + delay(3000); +} diff --git a/lib/lib_rf/RadioLib/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino b/lib/lib_rf/RadioLib/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino new file mode 100644 index 000000000..58a95360f --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino @@ -0,0 +1,137 @@ +/* + RadioLib PhysicalLayer Interface Example + + This example shows how to use the common PhysicalLayer + to interface with different radio modules using the same + methods. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// select which radio to use +// this can be any radio supported by RadioLib! +#define RADIO_TYPE SX1278 + +// set the pinout depending on the wiring and module type +// SPI NSS pin: 10 +// interrupt pin: 2 +// reset pin: 9 (unused on some modules) +// extra GPIO/interrupt pin: 3 (unused on some modules) +RADIO_TYPE radio = new Module(10, 2, 9, 3); + +// get pointer to the common layer +PhysicalLayer* phy = (PhysicalLayer*)&radio; + +void dummyISR(void) { + // nothing here, this example is just a showcase +} + +void setup() { + Serial.begin(9600); + + // now we can use "radio" to access the features + // specific to that radio type, such as the begin() method + Serial.print(F("[Radio] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // or we can use the "phy" pointer to access the common layer + // PhysicalLayer has some common configuration + Serial.print(F("[PHY] Changing frequency ... ")); + state = phy->setFrequency(433.5); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // PhysicalLayer also contains basic functionality + // like transmitting and receiving packets + Serial.print(F("[PHY] Sending packet ... ")); + state = phy->transmit("Hello World!"); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // try to receive now - this will almost certainly timeout + // unless by chance there is a transmitter nearby, + // but the point of this example is to showcase the interface + String str; + Serial.print(F("[PHY] Listening for packets ... ")); + state = phy->receive(str); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("timeout!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // interrupt-driven versions of Rx/Tx are supported as well + // for these to work, you have to configure the interrupt actions + phy->setPacketReceivedAction(dummyISR); + phy->setPacketSentAction(dummyISR); + + // now you can use methods like startTransmit(), startReceive(), + // readData() etc. + + // interrupt actions can be cleared as well + phy->clearPacketReceivedAction(); + phy->clearPacketSentAction(); + + // PhysicalLayer supports basic mode changes like sleep ... + Serial.print(F("[PHY] Going to sleep ... ")); + state = phy->sleep(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // ... or standby + Serial.print(F("[PHY] Going to standby ... ")); + state = phy->standby(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // there are also common SNR/RSSI measurement functions + Serial.print(F("[PHY] Measured SNR = ")); + Serial.print(phy->getSNR()); + Serial.println(F(" dB")); + Serial.print(F("[PHY] Measured RSSI = ")); + Serial.print(phy->getRSSI()); + Serial.println(F(" dBm")); + + // and also a true random number generator + Serial.print(F("[PHY] Random number between 0 and 100 = ")); + Serial.println(phy->random(100)); +} + +void loop() { + // nothing here, the example is just a showcase +} diff --git a/lib/lib_rf/RadioLib/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino b/lib/lib_rf/RadioLib/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino new file mode 100644 index 000000000..8ca312129 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino @@ -0,0 +1,92 @@ +/* + RadioLib RF69 Receive with AES Example + + This example receives packets using RF69 FSK radio module. + Packets are decrypted using hardware AES. + NOTE: When using address filtering, the address byte is NOT encrypted! + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// RF69 has the following connections: +// CS pin: 10 +// DIO0 pin: 2 +// RESET pin: 3 +RF69 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//RF69 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize RF69 with default settings + Serial.print(F("[RF69] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set AES key that will be used to decrypt the packet + // NOTE: the key must be exactly 16 bytes long! + uint8_t key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; + radio.setAESKey(key); + + // enable AES encryption + radio.enableAES(); + + // AES encryption can also be disabled + /* + radio.disableAES(); + */ +} + +void loop() { + Serial.print(F("[RF69] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[RF69] Data:\t\t")); + Serial.println(str); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/lib/lib_rf/RadioLib/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino b/lib/lib_rf/RadioLib/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino new file mode 100644 index 000000000..c6127995b --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino @@ -0,0 +1,121 @@ +/* + RadioLib RF69 Receive with Address Example + + This example receives packets using RF69 FSK radio module. + Packets can have 1-byte address of the destination node. + After setting node (or broadcast) address, this node will + automatically filter out any packets that do not contain + either node address or broadcast address. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// RF69 has the following connections: +// CS pin: 10 +// DIO0 pin: 2 +// RESET pin: 3 +RF69 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//RF69 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize RF69 with default settings + Serial.print(F("[RF69] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set node address + // NOTE: calling this method will automatically enable + // address filtering (node address only) + Serial.print(F("[RF69] Setting node address ... ")); + state = radio.setNodeAddress(0x02); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set broadcast address + // NOTE: calling this method will automatically enable + // address filtering (node or broadcast address) + Serial.print(F("[RF69] Setting broadcast address ... ")); + state = radio.setBroadcastAddress(0xFF); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // address filtering can also be disabled + // NOTE: calling this method will also erase previously set + // node and broadcast address + /* + Serial.print(F("[RF69] Disabling address filtering ... ")); + state == radio.disableAddressFiltering(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ +} + +void loop() { + Serial.print(F("[RF69] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[RF69] Data:\t\t")); + Serial.println(str); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/lib/lib_rf/RadioLib/examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino b/lib/lib_rf/RadioLib/examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino new file mode 100644 index 000000000..a886b87dc --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino @@ -0,0 +1,93 @@ +/* + RadioLib RF69 Blocking Receive Example + + This example receives packets using RF69 FSK radio module. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bit rate + - frequency deviation + - sync word + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can miss some packets! + Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// RF69 has the following connections: +// CS pin: 10 +// DIO0 pin: 2 +// RESET pin: 3 +RF69 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//RF69 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize RF69 with default settings + Serial.print(F("[RF69] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[RF69] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[RF69] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[RF69] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/lib/lib_rf/RadioLib/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino b/lib/lib_rf/RadioLib/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino new file mode 100644 index 000000000..1bc87276b --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino @@ -0,0 +1,127 @@ +/* + RadioLib RF69 Receive with Interrupts Example + + This example listens for FSK transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// RF69 has the following connections: +// CS pin: 10 +// DIO0 pin: 2 +// RESET pin: 3 +RF69 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//RF69 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize RF69 with default settings + Serial.print(F("[RF69] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + radio.setPacketReceivedAction(setFlag); + + // start listening for packets + Serial.print(F("[RF69] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[RF69] Received packet!")); + + // print data of the packet + Serial.print(F("[RF69] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[RF69] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // put module back to listen mode + radio.startReceive(); + } +} diff --git a/lib/lib_rf/RadioLib/examples/RF69/RF69_Settings/RF69_Settings.ino b/lib/lib_rf/RadioLib/examples/RF69/RF69_Settings/RF69_Settings.ino new file mode 100644 index 000000000..23626c2df --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/RF69/RF69_Settings/RF69_Settings.ino @@ -0,0 +1,139 @@ +/* + RadioLib RF69 Settings Example + + This example shows how to change all the properties of RF69 radio. + RadioLib currently supports the following settings: + - pins (SPI slave select, digital IO 0, digital IO 1) + - carrier frequency + - bit rate + - receiver bandwidth + - allowed frequency deviation + - output power during transmission + - sync word + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// RF69 has the following connections: +// CS pin: 10 +// DIO0 pin: 2 +// RESET pin: 3 +RF69 radio1 = new Module(10, 2, 3); + +// second CC1101 has different connections: +// CS pin: 9 +// DIO0 pin: 4 +// RESET pin: 5 +RF69 radio2 = new Module(9, 4, 5); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//RF69 radio3 = RadioShield.ModuleB; + +void setup() { + Serial.begin(9600); + + // initialize RF69 with default settings + Serial.print(F("[RF69] Initializing ... ")); + int state = radio1.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // initialize RF69 with non-default settings + Serial.print(F("[RF69] Initializing ... ")); + // carrier frequency: 868.0 MHz + // bit rate: 300.0 kbps + // frequency deviation: 60.0 kHz + // Rx bandwidth: 250.0 kHz + // output power: 17 dBm + // preamble length: 32 bits + state = radio2.begin(868.0, 300.0, 60.0, 250.0, 17, 32); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // you can also change the settings at runtime + // and check if the configuration was changed successfully + + // set carrier frequency to 433.5 MHz + if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { + Serial.println(F("[RF69] Selected frequency is invalid for this module!")); + while (true); + } + + // set bit rate to 100.0 kbps + state = radio1.setBitRate(100.0); + if (state == RADIOLIB_ERR_INVALID_BIT_RATE) { + Serial.println(F("[RF69] Selected bit rate is invalid for this module!")); + while (true); + } else if (state == RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO) { + Serial.println(F("[RF69] Selected bit rate to bandwidth ratio is invalid!")); + Serial.println(F("[RF69] Increase receiver bandwidth to set this bit rate.")); + while (true); + } + + // set receiver bandwidth to 250.0 kHz + state = radio1.setRxBandwidth(250.0); + if (state == RADIOLIB_ERR_INVALID_RX_BANDWIDTH) { + Serial.println(F("[RF69] Selected receiver bandwidth is invalid for this module!")); + while (true); + } else if (state == RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO) { + Serial.println(F("[RF69] Selected bit rate to bandwidth ratio is invalid!")); + Serial.println(F("[RF69] Decrease bit rate to set this receiver bandwidth.")); + while (true); + } + + // set allowed frequency deviation to 10.0 kHz + if (radio1.setFrequencyDeviation(10.0) == RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION) { + Serial.println(F("[RF69] Selected frequency deviation is invalid for this module!")); + while (true); + } + + // set output power to 2 dBm + if (radio1.setOutputPower(2) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + Serial.println(F("[RF69] Selected output power is invalid for this module!")); + while (true); + } + + // up to 8 bytes can be set as sync word + // NOTE: sync word must not contain any zero bytes + // set sync word to 0x0123456789ABCDEF + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; + if (radio1.setSyncWord(syncWord, 8) == RADIOLIB_ERR_INVALID_SYNC_WORD) { + Serial.println(F("[RF69] Selected sync word is invalid for this module!")); + while (true); + } + + Serial.println(F("[RF69] All settings changed successfully!")); + + // RF69 can also measure temperature (roughly) + // to get correct temperature measurements, the sensor must be calibrated + // at ambient temperature + radio1.setAmbientTemperature(25); // replace 25 with your ambient temperature +} + +void loop() { + // measure temperature + Serial.print(F("[RF69] Measured temperature: ")); + Serial.print(radio1.getTemperature()); + Serial.println(F(" deg C")); + + // wait 100 ms before the next measurement + delay(100); +} diff --git a/lib/lib_rf/RadioLib/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino b/lib/lib_rf/RadioLib/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino new file mode 100644 index 000000000..48c905776 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino @@ -0,0 +1,86 @@ +/* + RadioLib RF69 Transmit with AES Example + + This example transmits packets using RF69 FSK radio module. + Packets are encrypted using hardware AES. + NOTE: When using address filtering, the address byte is NOT encrypted! + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// RF69 has the following connections: +// CS pin: 10 +// DIO0 pin: 2 +// RESET pin: 3 +RF69 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//RF69 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize RF69 with default settings + Serial.print(F("[RF69] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set AES key to encrypt the packet + // NOTE: the key must be exactly 16 bytes long! + uint8_t key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; + radio.setAESKey(key); + + // enable AES encryption + radio.enableAES(); + + // AES encryption can also be disabled + /* + radio.disableAES(); + */ +} + +void loop() { + Serial.print(F("[RF69] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to 64 characters long + int state = radio.transmit("Hello World!"); + + // you can also transmit byte array up to 64 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 64 bytes + Serial.println(F("too long!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino b/lib/lib_rf/RadioLib/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino new file mode 100644 index 000000000..e9b1fba16 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino @@ -0,0 +1,126 @@ +/* + RadioLib RF69 Transmit to Address Example + + This example transmits packets using RF69 FSK radio module. + Packets can have 1-byte address of the destination node. + After setting node (or broadcast) address, this node will + automatically filter out any packets that do not contain + either node address or broadcast address. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// RF69 has the following connections: +// CS pin: 10 +// DIO0 pin: 2 +// RESET pin: 3 +RF69 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//RF69 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize RF69 with default settings + Serial.print(F("[RF69] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set node address + // NOTE: calling this method will automatically enable + // address filtering (node address only) + Serial.print(F("[RF69] Setting node address ... ")); + state = radio.setNodeAddress(0x01); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set broadcast address + // NOTE: calling this method will automatically enable + // address filtering (node or broadcast address) + Serial.print(F("[RF69] Setting broadcast address ... ")); + state = radio.setBroadcastAddress(0xFF); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // address filtering can also be disabled + // NOTE: calling this method will also erase previously set + // node and broadcast address + /* + Serial.print(F("[RF69] Disabling address filtering ... ")); + state = radio.disableAddressFiltering(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ +} + +void loop() { + Serial.print(F("[RF69] Transmitting packet ... ")); + + // transmit C-string or Arduino string to node with address 0x02 + int state = radio.transmit("Hello World!", 0x02); + + // transmit byte array to node with address 0x02 + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8, 0x02); + */ + + // transmit C-string or Arduino string in broadcast mode + /* + int state = radio.transmit("Hello World!", 0xFF); + */ + + // transmit byte array in broadcast mode + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8, 0xFF); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 64 bytes + Serial.println(F("too long!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino b/lib/lib_rf/RadioLib/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino new file mode 100644 index 000000000..0a4897805 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino @@ -0,0 +1,99 @@ +/* + RadioLib RF69 Blocking Transmit Example + + This example transmits packets using RF69 FSK radio module. + Each packet contains up to 64 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// RF69 has the following connections: +// CS pin: 10 +// DIO0 pin: 2 +// RESET pin: 3 +RF69 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//RF69 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize RF69 with default settings + Serial.print(F("[RF69] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // NOTE: some RF69 modules use high power output, + // those are usually marked RF69H(C/CW). + // To configure RadioLib for these modules, + // you must call setOutputPower() with + // second argument set to true. + /* + Serial.print(F("[RF69] Setting high power module ... ")); + state = radio.setOutputPower(20, true); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + */ +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + Serial.print(F("[RF69] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to 64 characters long + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); + + // you can also transmit byte array up to 64 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 64 bytes + Serial.println(F("too long!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/lib/lib_rf/RadioLib/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino new file mode 100644 index 000000000..b168af730 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -0,0 +1,145 @@ +/* + RadioLib RF69 Transmit with Interrupts Example + + This example transmits FSK packets with one second delays + between them. Each packet contains up to 64 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// RF69 has the following connections: +// CS pin: 10 +// DIO0 pin: 2 +// RESET pin: 3 +RF69 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//RF69 radio = RadioShield.ModuleA; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +void setup() { + Serial.begin(9600); + + // initialize RF69 with default settings + Serial.print(F("[RF69] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when packet transmission is finished + radio.setPacketSentAction(setFlag); + + // NOTE: some RF69 modules use high power output, + // those are usually marked RF69H(C/CW). + // To configure RadioLib for these modules, + // you must call setOutputPower() with + // second argument set to true. + /* + Serial.print(F("[RF69] Setting high power module ... ")); + state = radio.setOutputPower(20, true); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + */ + + // start transmitting the first packet + Serial.print(F("[RF69] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 64 characters long + transmissionState = radio.startTransmit("Hello World!"); + + // you can also transmit byte array up to 64 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.startTransmit(byteArr, 8); + */ +} + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + // NOTE: when using interrupt-driven transmit method, + // it is not possible to automatically measure + // transmission data rate using getDataRate() + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[RF69] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 64 characters long + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); + + // you can also transmit byte array up to 64 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + transmissionState = radio.startTransmit(byteArr, 8); + */ + } +} diff --git a/lib/lib_rf/RadioLib/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino b/lib/lib_rf/RadioLib/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino new file mode 100644 index 000000000..e02ad3ca9 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino @@ -0,0 +1,140 @@ +/* + RadioLib RTTY Transmit Example + + This example sends RTTY message using SX1278's + FSK modem. + + Other modules that can be used for RTTY: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - SX128x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create RTTY client instance using the FSK module +RTTYClient rtty(&radio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for RTTY + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize RTTY client + // NOTE: RTTY frequency shift will be rounded + // to the nearest multiple of frequency step size. + // The exact value depends on the module: + // SX127x/RFM9x - 61 Hz + // RF69 - 61 Hz + // CC1101 - 397 Hz + // SX126x - 1 Hz + // nRF24 - 1000000 Hz + // Si443x/RFM2x - 156 Hz + // SX128x - 198 Hz + Serial.print(F("[RTTY] Initializing ... ")); + // low ("space") frequency: 434.0 MHz + // frequency shift: 183 Hz + // baud rate: 45 baud + // encoding: ASCII (7-bit) + // stop bits: 1 + state = rtty.begin(434.0, 183, 45); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + /* + // RadioLib also provides ITA2 ("Baudot") support + rtty.begin(434, 183, 45, ITA2); + + // All transmissions in loop() (strings and numbers) + // will now be encoded using ITA2 code + + // ASCII characters that do not have ITA2 equivalent + // will be sent as NUL (including lower case letters!) + */ +} + +void loop() { + Serial.print(F("[RTTY] Sending RTTY data ... ")); + + // send out idle condition for 500 ms + rtty.idle(); + delay(500); + + // RTTYClient supports all methods of the Serial class + + // Arduino String class + String aStr = "Arduino String"; + rtty.println(aStr); + + // character array (C-String) + rtty.println("C-String"); + + // string saved in flash + rtty.println(F("Flash String")); + + // character + rtty.println('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + rtty.println(255, HEX); + + // integer number + int i = 1000; + rtty.println(i); + + // floating point number + float f = -3.1415; + rtty.println(f, 3); + + // turn the transmitter off + rtty.standby(); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino b/lib/lib_rf/RadioLib/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino new file mode 100644 index 000000000..c9b268cdd --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino @@ -0,0 +1,141 @@ +/* + RadioLib RTTY Transmit AFSK Example + + This example sends RTTY message using SX1278's + FSK modem. The data is modulated as AFSK. + + Other modules that can be used for RTTY: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 +AFSKClient audio(&radio, 5); + +// create RTTY client instance using the AFSK instance +RTTYClient rtty(&audio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for RTTY + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize RTTY client + // NOTE: Unlike FSK RTTY, AFSK requires no rounding of + // the frequency shift. + Serial.print(F("[RTTY] Initializing ... ")); + // space frequency: 400 Hz + // frequency shift: 170 Hz + // baud rate: 45 baud + // encoding: ASCII (7-bit) + // stop bits: 1 + state = rtty.begin(400, 170, 45); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + /* + // RadioLib also provides ITA2 ("Baudot") support + rtty.begin(400, 170, 45, ITA2); + + // All transmissions in loop() (strings and numbers) + // will now be encoded using ITA2 code + + // ASCII characters that do not have ITA2 equivalent + // will be sent as NUL (including lower case letters!) + */ +} + +void loop() { + Serial.print(F("[RTTY] Sending RTTY data ... ")); + + // send out idle condition for 500 ms + rtty.idle(); + delay(500); + + // RTTYClient supports all methods of the Serial class + + // Arduino String class + String aStr = "Arduino String"; + rtty.println(aStr); + + // character array (C-String) + rtty.println("C-String"); + + // string saved in flash + rtty.println(F("Flash String")); + + // character + rtty.println('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + rtty.println(255, HEX); + + // integer number + int i = 1000; + rtty.println(i); + + // floating point number + float f = -3.1415; + rtty.println(f, 3); + + // turn the transmitter off + rtty.standby(); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino b/lib/lib_rf/RadioLib/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino new file mode 100644 index 000000000..e532e2d40 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino @@ -0,0 +1,166 @@ +/* + RadioLib SSTV Transmit Example + + The following example sends SSTV picture using + SX1278's FSK modem. + + Other modules that can be used for SSTV: + - SX127x/RFM9x + - RF69 + - SX1231 + - SX126x + + NOTE: SSTV is an analog modulation, and + requires precise frequency control. + Some of the above modules can only + set their frequency in rough steps, + so the result can be distorted. + Using high-precision radio with TCXO + (like SX126x) is recommended. + + NOTE: Some platforms (such as Arduino Uno) + might not be fast enough to correctly + send pictures via high-speed modes + like Scottie2 or Martin2. For those, + lower speed modes such as Wrasse, + Scottie1 or Martin1 are recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create SSTV client instance using the FSK module +SSTVClient sstv(&radio); + +// test "image" - actually just a single 320px line +// will be sent over and over again, to create vertical color stripes at the receiver +uint32_t line[320] = { + // black + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + + // blue + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + + // green + 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, + 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, + + // cyan + 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, + 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, + + // red + 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, + 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, + + // magenta + 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, + 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, + + // yellow + 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, + 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, + + // white + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF +}; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // when using one of the non-LoRa modules for SSTV + // (RF69, SX1231 etc.), use the basic begin() method + // int state = radio.begin(); + + // initialize SSTV client + Serial.print(F("[SSTV] Initializing ... ")); + // 0 Hz tone frequency: 434.0 MHz + // SSTV mode: Wrasse (SC2-180) + state = sstv.begin(434.0, Wrasse); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // set correction factor + // NOTE: Due to different speeds of various platforms + // supported by RadioLib (Arduino Uno, ESP32 etc), + // and because SSTV is analog protocol, incorrect + // timing of pulses can lead to distortions. + // To compensate, correction factor can be used + // to adjust the length of timing pulses + // (lower number = shorter pulses). + // The value is usually around 0.95 (95%). + Serial.print(F("[SSTV] Setting correction ... ")); + state = sstv.setCorrection(0.95); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // to help tune the receiver, SSTVClient can send + // continuous beep at the frequency corresponding to + // 1900 Hz in upper sideband (aka USB) modulation + // (SSTV header "leader tone") + /* + sstv.idle(); + while(true); + */ +} + +void loop() { + // send picture with 8 color stripes + Serial.print(F("[SSTV] Sending test picture ... ")); + + // send synchronization header first + sstv.sendHeader(); + + // send all picture lines + for(uint16_t i = 0; i < sstv.getPictureHeight(); i++) { + sstv.sendLine(line); + } + + // turn off transmitter + radio.standby(); + + Serial.println(F("done!")); + + delay(30000); +} diff --git a/lib/lib_rf/RadioLib/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino b/lib/lib_rf/RadioLib/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino new file mode 100644 index 000000000..924522b16 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino @@ -0,0 +1,170 @@ +/* + RadioLib SSTV Transmit AFSK Example + + The following example sends SSTV picture using + SX1278's FSK modem. The data is modulated + as AFSK. + + Other modules that can be used for SSTV: + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) + + NOTE: Some platforms (such as Arduino Uno) + might not be fast enough to correctly + send pictures via high-speed modes + like Scottie2 or Martin2. For those, + lower speed modes such as Wrasse, + Scottie1 or Martin1 are recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 +AFSKClient audio(&radio, 5); + +// create SSTV client instance using the AFSK instance +SSTVClient sstv(&audio); + +// test "image" - actually just a single 320px line +// will be sent over and over again, to create vertical color stripes at the receiver +uint32_t line[320] = { + // black + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + + // blue + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + + // green + 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, + 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, + + // cyan + 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, + 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, + + // red + 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, + 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, + + // magenta + 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, + 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, + + // yellow + 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, + 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, + + // white + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF +}; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // when using one of the non-LoRa modules for SSTV + // (RF69, SX1231 etc.), use the basic begin() method + // int state = radio.begin(); + + // initialize SSTV client + Serial.print(F("[SSTV] Initializing ... ")); + // SSTV mode: Wrasse (SC2-180) + state = sstv.begin(Wrasse); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // set correction factor + // NOTE: Due to different speeds of various platforms + // supported by RadioLib (Arduino Uno, ESP32 etc), + // and because SSTV is analog protocol, incorrect + // timing of pulses can lead to distortions. + // To compensate, correction factor can be used + // to adjust the length of timing pulses + // (lower number = shorter pulses). + // The value is usually around 0.95 (95%). + Serial.print(F("[SSTV] Setting correction ... ")); + state = sstv.setCorrection(0.95); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // to help tune the receiver, SSTVClient can send + // continuous 1900 Hz beep + /* + sstv.idle(); + while(true); + */ +} + +void loop() { + // send picture with 8 color stripes + Serial.print(F("[SSTV] Sending test picture ... ")); + + // send synchronization header first + sstv.sendHeader(); + + // send all picture lines + for(uint16_t i = 0; i < sstv.getPictureHeight(); i++) { + sstv.sendLine(line); + } + + // turn off transmitter + radio.standby(); + + Serial.println(F("done!")); + + delay(30000); +} diff --git a/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino b/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino new file mode 100644 index 000000000..da0707826 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino @@ -0,0 +1,78 @@ +/* + RadioLib STM32WLx Channel Activity Detection Example + + This example uses STM32WLx to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, SX126x/STM32WLx can detect any part + of LoRa transmission, not just the preamble. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// no need to configure pins, signals are routed to the radio internally +STM32WLx radio = new STM32WLx_Module(); + +// set RF switch configuration for Nucleo WL55JC1 +// NOTE: other boards may be different! +// Some boards may not have either LP or HP. +// For those, do not set the LP/HP entry in the table. +static const uint32_t rfswitch_pins[] = + {PC3, PC4, PC5}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, + {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, + END_OF_MODE_TABLE, +}; + +void setup() { + Serial.begin(9600); + + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + // initialize STM32WLx with default settings, except frequency + Serial.print(F("[STM32WLx] Initializing ... ")); + int state = radio.begin(868.0); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[STM32WLx] Scanning channel for LoRa transmission ... ")); + + // start scanning current channel + int state = radio.scanChannel(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa preamble was detected + Serial.println(F("detected!")); + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // no preamble was detected, channel is free + Serial.println(F("channel is free!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait 100 ms before new scan + delay(100); +} diff --git a/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino b/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino new file mode 100644 index 000000000..9c14329d2 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino @@ -0,0 +1,115 @@ +/* + RadioLib STM32WLx Channel Activity Detection Example + + This example uses STM32WLx to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, SX126x/STM32WLx can detect any part + of LoRa transmission, not just the preamble. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// no need to configure pins, signals are routed to the radio internally +STM32WLx radio = new STM32WLx_Module(); + +// set RF switch configuration for Nucleo WL55JC1 +// NOTE: other boards may be different! +// Some boards may not have either LP or HP. +// For those, do not set the LP/HP entry in the table. +static const uint32_t rfswitch_pins[] = + {PC3, PC4, PC5}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, + {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, + END_OF_MODE_TABLE, +}; + +void setup() { + Serial.begin(9600); + + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + // initialize STM32WLx with default settings, except frequency + Serial.print(F("[STM32WLx] Initializing ... ")); + int state = radio.begin(868.0); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when LoRa packet or timeout is detected + radio.setDio1Action(setFlag); + + // start scanning the channel + Serial.print(F("[STM32WLx] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // something happened, set the flag + scanFlag = true; +} + +void loop() { + // check if the flag is set + if(scanFlag) { + // reset flag + scanFlag = false; + + // check CAD result + int state = radio.getChannelScanResult(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa packet was detected + Serial.println(F("[STM32WLx] Packet detected!")); + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // channel is free + Serial.println(F("[STM32WLx] Channel is free!")); + + } else { + // some other error occurred + Serial.print(F("[STM32WLx] Failed, code ")); + Serial.println(state); + + } + + // start scanning the channel again + Serial.print(F("[STM32WLx] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + } +} diff --git a/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino b/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino new file mode 100644 index 000000000..e2e90d62b --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino @@ -0,0 +1,128 @@ +/* + RadioLib STM32WLx Blocking Receive Example + + This example listens for LoRa transmissions using STM32WL MCU with + integrated (SX126x) LoRa radio. + + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - preamble length + + This example assumes Nucleo WL55JC1 is used. For other Nucleo boards + or standalone STM32WL, some configuration such as TCXO voltage and + RF switch control may have to be adjusted. + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// no need to configure pins, signals are routed to the radio internally +STM32WLx radio = new STM32WLx_Module(); + +// set RF switch configuration for Nucleo WL55JC1 +// NOTE: other boards may be different! +// Some boards may not have either LP or HP. +// For those, do not set the LP/HP entry in the table. +static const uint32_t rfswitch_pins[] = + {PC3, PC4, PC5}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, + {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, + END_OF_MODE_TABLE, +}; + +void setup() { + Serial.begin(9600); + + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + // initialize STM32WL with default settings, except frequency + Serial.print(F("[STM32WL] Initializing ... ")); + int state = radio.begin(868.0); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set appropriate TCXO voltage for Nucleo WL55JC1 + state = radio.setTCXO(1.7); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[STM32WL] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[STM32WL] Data:\t\t")); + Serial.println(str); + + // print the RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[STM32WL] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print the SNR (Signal-to-Noise Ratio) + // of the last received packet + Serial.print(F("[STM32WL] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino b/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino new file mode 100644 index 000000000..6d91cea4b --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino @@ -0,0 +1,161 @@ +/* + RadioLib STM32WLx Receive with Interrupts Example + + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + + This example assumes Nucleo WL55JC1 is used. For other Nucleo boards + or standalone STM32WL, some configuration such as TCXO voltage and + RF switch control may have to be adjusted. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// no need to configure pins, signals are routed to the radio internally +STM32WLx radio = new STM32WLx_Module(); + +// set RF switch configuration for Nucleo WL55JC1 +// NOTE: other boards may be different! +// Some boards may not have either LP or HP. +// For those, do not set the LP/HP entry in the table. +static const uint32_t rfswitch_pins[] = + {PC3, PC4, PC5}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, + {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, + END_OF_MODE_TABLE, +}; + +void setup() { + Serial.begin(9600); + + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + // initialize STM32WL with default settings, except frequency + Serial.print(F("[STM32WL] Initializing ... ")); + int state = radio.begin(868.0); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set appropriate TCXO voltage for Nucleo WL55JC1 + state = radio.setTCXO(1.7); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + radio.setDio1Action(setFlag); + + // start listening for LoRa packets + Serial.print(F("[STM32WL] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); + // radio.scanChannel(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[STM32WL] Received packet!")); + + // print data of the packet + Serial.print(F("[STM32WL] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[STM32WL] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[STM32WL] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // put module back to listen mode + radio.startReceive(); + } +} diff --git a/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino b/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino new file mode 100644 index 000000000..d35680a3a --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino @@ -0,0 +1,119 @@ +/* + RadioLib STM32WLx Blocking Transmit Example + + This example transmits packets using STM32WL MCU with integrated + (SX126x) LoRa radio. + + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + This example assumes Nucleo WL55JC1 is used. For other Nucleo boards + or standalone STM32WL, some configuration such as TCXO voltage and + RF switch control may have to be adjusted. + + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// no need to configure pins, signals are routed to the radio internally +STM32WLx radio = new STM32WLx_Module(); + +// set RF switch configuration for Nucleo WL55JC1 +// NOTE: other boards may be different! +// Some boards may not have either LP or HP. +// For those, do not set the LP/HP entry in the table. +static const uint32_t rfswitch_pins[] = + {PC3, PC4, PC5}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, + {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, + END_OF_MODE_TABLE, +}; + +void setup() { + Serial.begin(9600); + + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + // initialize STM32WL with default settings, except frequency + Serial.print(F("[STM32WL] Initializing ... ")); + int state = radio.begin(868.0); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set appropriate TCXO voltage for Nucleo WL55JC1 + state = radio.setTCXO(1.7); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + Serial.print(F("[STM32WL] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + // print measured data rate + Serial.print(F("[STM32WL] Datarate:\t")); + Serial.print(radio.getDataRate()); + Serial.println(F(" bps")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F("too long!")); + + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + // timeout occured while transmitting packet + Serial.println(F("timeout!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino b/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino new file mode 100644 index 000000000..60777c028 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino @@ -0,0 +1,146 @@ +/* + RadioLib STM32WLx Transmit with Interrupts Example + + This example transmits LoRa packets with one second delays + between them. Each packet contains up to 256 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// no need to configure pins, signals are routed to the radio internally +STM32WLx radio = new STM32WLx_Module(); + +// set RF switch configuration for Nucleo WL55JC1 +// NOTE: other boards may be different! +// Some boards may not have either LP or HP. +// For those, do not set the LP/HP entry in the table. +static const uint32_t rfswitch_pins[] = + {PC3, PC4, PC5}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, + {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, + END_OF_MODE_TABLE, +}; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +void setup() { + Serial.begin(9600); + + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + // initialize STM32WL with default settings, except frequency + Serial.print(F("[STM32WL] Initializing ... ")); + int state = radio.begin(868.0); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set appropriate TCXO voltage for Nucleo WL55JC1 + state = radio.setTCXO(1.7); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when packet transmission is finished + radio.setDio1Action(setFlag); + + // start transmitting the first packet + Serial.print(F("[STM32WL] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + transmissionState = radio.startTransmit("Hello World!"); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.startTransmit(byteArr, 8); + */ +} + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + // NOTE: when using interrupt-driven transmit method, + // it is not possible to automatically measure + // transmission data rate using getDataRate() + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[STM32WL] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + transmissionState = radio.startTransmit(byteArr, 8); + */ + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino b/lib/lib_rf/RadioLib/examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino new file mode 100644 index 000000000..f79d35462 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino @@ -0,0 +1,86 @@ +/* + RadioLib SX123x Blocking Receive Example + + This example receives packets using SX1231 FSK radio module. + Other modules from SX123x family can also be used. + + NOTE: SX123x modules offer the same features as RF69 and have the same + interface. Please see RF69 examples for examples on AES, + address filtering, interrupts and settings. + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1231 has the following connections: +// CS pin: 10 +// DIO0 pin: 2 +// RESET pin: 3 +SX1231 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1231 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1231 with default settings + Serial.print(F("[SX1231] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[SX1231] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[SX1231] Data:\t\t")); + Serial.println(str); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino b/lib/lib_rf/RadioLib/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino new file mode 100644 index 000000000..e311737e5 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino @@ -0,0 +1,78 @@ +/* + RadioLib SX123x Blocking Transmit Example + + This example transmits packets using SX1231 FSK radio module. + Other modules from SX123x family can also be used. + + NOTE: SX123x modules offer the same features as RF69 and have the same + interface. Please see RF69 examples for examples on AES, + address filtering, interrupts and settings. + + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1231 has the following connections: +// CS pin: 10 +// DIO0 pin: 2 +// RESET pin: 3 +SX1231 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1231 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1231 with default settings + Serial.print(F("[SX1231] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + Serial.print(F("[SX1231] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to 256 characters long + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F("too long!")); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino new file mode 100644 index 000000000..0d2380dd7 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino @@ -0,0 +1,78 @@ +/* + RadioLib SX126x Blocking Channel Activity Detection Example + + This example uses SX1262 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, SX126x can detect any part + of LoRa transmission, not just the preamble. + + Other modules from SX126x family can also be used. + + Using blocking CAD is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt CAD is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 radio = RadioShield.ModuleA; + +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[SX1262] Scanning channel for LoRa transmission ... ")); + + // start scanning current channel + int state = radio.scanChannel(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa preamble was detected + Serial.println(F("detected!")); + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // no preamble was detected, channel is free + Serial.println(F("channel is free!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait 100 ms before new scan + delay(100); +} diff --git a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino new file mode 100644 index 000000000..651da66b9 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino @@ -0,0 +1,113 @@ +/* + RadioLib SX126x Channel Activity Detection Example + + This example uses SX1262 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, SX126x can detect any part + of LoRa transmission, not just the preamble. + + Other modules from SX126x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 radio = RadioShield.ModuleA; + +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when LoRa packet or timeout is detected + radio.setDio1Action(setFlag); + + // start scanning the channel + Serial.print(F("[SX1262] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // something happened, set the flag + scanFlag = true; +} + +void loop() { + // check if the flag is set + if(scanFlag) { + // reset flag + scanFlag = false; + + // check CAD result + int state = radio.getChannelScanResult(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa packet was detected + Serial.println(F("[SX1262] Packet detected!")); + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // channel is free + Serial.println(F("[SX1262] Channel is free!")); + + } else { + // some other error occurred + Serial.print(F("[SX1262] Failed, code ")); + Serial.println(state); + + } + + // start scanning the channel again + Serial.print(F("[SX1262] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino new file mode 100644 index 000000000..20b0ae92d --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino @@ -0,0 +1,185 @@ +/* + RadioLib SX126x Receive after Channel Activity Detection Example + + This example uses SX1262 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, SX126x can detect any part + of LoRa transmission, not just the preamble. + If a packet is detected, the module will switch + to receive mode and receive the packet. + + Other modules from SX126x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 radio = RadioShield.ModuleA; + +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when LoRa packet or timeout is detected + radio.setDio1Action(setFlag); + + // start scanning the channel + Serial.print(F("[SX1262] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +bool receiving = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // something happened, set the flag + scanFlag = true; +} + +void loop() { + // check if the flag is set + if(scanFlag) { + int state = RADIOLIB_ERR_NONE; + + // reset flag + scanFlag = false; + + // check ongoing reception + if(receiving) { + // DIO triggered while reception is ongoing + // that means we got a packet + + // you can read received data as an Arduino String + String str; + state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + state = radio.readData(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1262] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1262] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[SX1262] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[SX1262] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[SX1262] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else { + // some other error occurred + Serial.print(F("[SX1262] Failed, code ")); + Serial.println(state); + + } + + // reception is done now + receiving = false; + + } else { + // check CAD result + state = radio.getChannelScanResult(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa packet was detected + Serial.print(F("[SX1262] Packet detected, starting reception ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // set the flag for ongoing reception + receiving = true; + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // channel is free + Serial.println(F("[SX1262] Channel is free!")); + + } else { + // some other error occurred + Serial.print(F("[SX1262] Failed, code ")); + Serial.println(state); + + } + + } + + // if we're not receiving, start scanning again + if(!receiving) { + Serial.print(F("[SX1262] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + } + + } + +} diff --git a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino new file mode 100644 index 000000000..2c394c5cc --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino @@ -0,0 +1,157 @@ +/* + RadioLib SX126x FSK Modem Example + + This example shows how to use FSK modem in SX126x chips. + + NOTE: The sketch below is just a guide on how to use + FSK modem, so this code should not be run directly! + Instead, modify the other examples to use FSK + modem and use the appropriate configuration + methods. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---fsk-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 radio = RadioShield.ModuleA; + +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +void setup() { + Serial.begin(9600); + + // initialize SX1262 FSK modem with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.beginFSK(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, you can switch between LoRa and FSK modes + // + // radio.begin() start LoRa mode (and disable FSK) + // radio.beginFSK() start FSK mode (and disable LoRa) + + // the following settings can also + // be modified at run-time + state = radio.setFrequency(433.5); + state = radio.setBitRate(100.0); + state = radio.setFrequencyDeviation(10.0); + state = radio.setRxBandwidth(250.0); + state = radio.setOutputPower(10.0); + state = radio.setCurrentLimit(100.0); + state = radio.setDataShaping(RADIOLIB_SHAPING_1_0); + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.setSyncWord(syncWord, 8); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Unable to set configuration, code ")); + Serial.println(state); + while (true); + } + + // FSK modem on SX126x can handle the sync word setting in bits, not just + // whole bytes. The value used is left-justified. + // This makes same result as radio.setSyncWord(syncWord, 8): + state = radio.setSyncBits(syncWord, 64); + // This will use 0x012 as sync word (12 bits only): + state = radio.setSyncBits(syncWord, 12); + + // FSK modem allows advanced CRC configuration + // Default is CCIT CRC16 (2 bytes, initial 0x1D0F, polynomial 0x1021, inverted) + // Set CRC to IBM CRC (2 bytes, initial 0xFFFF, polynomial 0x8005, non-inverted) + state = radio.setCRC(2, 0xFFFF, 0x8005, false); + // set CRC length to 0 to disable CRC + + #warning "This sketch is just an API guide! Read the note at line 6." +} + +void loop() { + // FSK modem can use the same transmit/receive methods + // as the LoRa modem, even their interrupt-driven versions + + // transmit FSK packet + int state = radio.transmit("Hello World!"); + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1262] Packet transmitted successfully!")); + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + Serial.println(F("[SX1262] Packet too long!")); + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + Serial.println(F("[SX1262] Timed out while transmitting!")); + } else { + Serial.println(F("[SX1262] Failed to transmit packet, code ")); + Serial.println(state); + } + + // receive FSK packet + String str; + state = radio.receive(str); + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1262] Received packet!")); + Serial.print(F("[SX1262] Data:\t")); + Serial.println(str); + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("[SX1262] Timed out while waiting for packet!")); + } else { + Serial.println(F("[SX1262] Failed to receive packet, code ")); + Serial.println(state); + } + + // FSK modem has built-in address filtering system + // it can be enabled by setting node address, broadcast + // address, or both + // + // to transmit packet to a particular address, + // use the following methods: + // + // radio.transmit("Hello World!", address); + // radio.startTransmit("Hello World!", address); + + // set node address to 0x02 + state = radio.setNodeAddress(0x02); + // set broadcast address to 0xFF + state = radio.setBroadcastAddress(0xFF); + if (state != RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1262] Unable to set address filter, code ")); + Serial.println(state); + } + + // address filtering can also be disabled + // NOTE: calling this method will also erase previously set + // node and broadcast address + /* + state = radio.disableAddressFiltering(); + if (state != RADIOLIB_ERR_NONE) { + Serial.println(F("Unable to remove address filter, code ")); + } + */ +} diff --git a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino new file mode 100644 index 000000000..99a962b27 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino @@ -0,0 +1,149 @@ +/* + RadioLib SX126x Ping-Pong Example + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// uncomment the following only on one +// of the nodes to initiate the pings +//#define INITIATING_NODE + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 radio = RadioShield.ModuleA; + +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +// save transmission states between loops +int transmissionState = RADIOLIB_ERR_NONE; + +// flag to indicate transmission or reception state +bool transmitFlag = false; + +// flag to indicate that a packet was sent or received +volatile bool operationDone = false; + +// this function is called when a complete packet +// is transmitted or received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent or received a packet, set the flag + operationDone = true; +} + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + radio.setDio1Action(setFlag); + + #if defined(INITIATING_NODE) + // send the first packet on this node + Serial.print(F("[SX1262] Sending first packet ... ")); + transmissionState = radio.startTransmit("Hello World!"); + transmitFlag = true; + #else + // start listening for LoRa packets on this node + Serial.print(F("[SX1262] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + #endif +} + +void loop() { + // check if the previous operation finished + if(operationDone) { + // reset flag + operationDone = false; + + if(transmitFlag) { + // the previous operation was transmission, listen for response + // print the result + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // listen for response + radio.startReceive(); + transmitFlag = false; + + } else { + // the previous operation was reception + // print data and send another packet + String str; + int state = radio.readData(str); + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1262] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1262] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[SX1262] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[SX1262] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[SX1262] Sending another packet ... ")); + transmissionState = radio.startTransmit("Hello World!"); + transmitFlag = true; + } + + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino new file mode 100644 index 000000000..75fda8f65 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino @@ -0,0 +1,112 @@ +/* + RadioLib SX126x Blocking Receive Example + + This example listens for LoRa transmissions using SX126x Lora modules. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - preamble length + + Other modules from SX126x family can also be used. + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 radio = RadioShield.ModuleA; + +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[SX1262] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[SX1262] Data:\t\t")); + Serial.println(str); + + // print the RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[SX1262] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print the SNR (Signal-to-Noise Ratio) + // of the last received packet + Serial.print(F("[SX1262] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[SX1262] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino new file mode 100644 index 000000000..11d6ea81e --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -0,0 +1,146 @@ +/* + RadioLib SX126x Receive with Interrupts Example + + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + + Other modules from SX126x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 radio = RadioShield.ModuleA; + +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + radio.setPacketReceivedAction(setFlag); + + // start listening for LoRa packets + Serial.print(F("[SX1262] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.scanChannel(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1262] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1262] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[SX1262] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[SX1262] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[SX1262] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Settings/SX126x_Settings.ino b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Settings/SX126x_Settings.ino new file mode 100644 index 000000000..530c49ab1 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Settings/SX126x_Settings.ino @@ -0,0 +1,166 @@ +/* + RadioLib SX126x Settings Example + + This example shows how to change all the properties of LoRa transmission. + RadioLib currently supports the following settings: + - pins (SPI slave select, DIO1, DIO2, BUSY pin) + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - output power during transmission + - CRC + - preamble length + - TCXO voltage + - DIO2 RF switch control + + Other modules from SX126x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio1 = new Module(10, 2, 3, 9); + +// SX12628 has different connections: +// NSS pin: 8 +// DIO1 pin: 4 +// NRST pin: 5 +// BUSY pin: 6 +SX1268 radio2 = new Module(8, 4, 5, 6); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1261 radio3 = RadioShield.ModuleB; + +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +void setup() { + Serial.begin(9600); + + // initialize SX1268 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio1.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // initialize the second LoRa instance with + // non-default settings + // this LoRa link will have high data rate, + // but lower range + Serial.print(F("[SX1268] Initializing ... ")); + // carrier frequency: 915.0 MHz + // bandwidth: 500.0 kHz + // spreading factor: 6 + // coding rate: 5 + // sync word: 0x34 (public network/LoRaWAN) + // output power: 2 dBm + // preamble length: 20 symbols + state = radio2.begin(915.0, 500.0, 6, 5, 0x34, 2, 20); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // you can also change the settings at runtime + // and check if the configuration was changed successfully + + // set carrier frequency to 433.5 MHz + if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { + Serial.println(F("Selected frequency is invalid for this module!")); + while (true); + } + + // set bandwidth to 250 kHz + if (radio1.setBandwidth(250.0) == RADIOLIB_ERR_INVALID_BANDWIDTH) { + Serial.println(F("Selected bandwidth is invalid for this module!")); + while (true); + } + + // set spreading factor to 10 + if (radio1.setSpreadingFactor(10) == RADIOLIB_ERR_INVALID_SPREADING_FACTOR) { + Serial.println(F("Selected spreading factor is invalid for this module!")); + while (true); + } + + // set coding rate to 6 + if (radio1.setCodingRate(6) == RADIOLIB_ERR_INVALID_CODING_RATE) { + Serial.println(F("Selected coding rate is invalid for this module!")); + while (true); + } + + // set LoRa sync word to 0xAB + if (radio1.setSyncWord(0xAB) != RADIOLIB_ERR_NONE) { + Serial.println(F("Unable to set sync word!")); + while (true); + } + + // set output power to 10 dBm (accepted range is -17 - 22 dBm) + if (radio1.setOutputPower(10) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + Serial.println(F("Selected output power is invalid for this module!")); + while (true); + } + + // set over current protection limit to 80 mA (accepted range is 45 - 240 mA) + // NOTE: set value to 0 to disable overcurrent protection + if (radio1.setCurrentLimit(80) == RADIOLIB_ERR_INVALID_CURRENT_LIMIT) { + Serial.println(F("Selected current limit is invalid for this module!")); + while (true); + } + + // set LoRa preamble length to 15 symbols (accepted range is 0 - 65535) + if (radio1.setPreambleLength(15) == RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH) { + Serial.println(F("Selected preamble length is invalid for this module!")); + while (true); + } + + // disable CRC + if (radio1.setCRC(false) == RADIOLIB_ERR_INVALID_CRC_CONFIGURATION) { + Serial.println(F("Selected CRC is invalid for this module!")); + while (true); + } + + // Some SX126x modules have TCXO (temperature compensated crystal + // oscillator). To configure TCXO reference voltage, + // the following method can be used. + if (radio1.setTCXO(2.4) == RADIOLIB_ERR_INVALID_TCXO_VOLTAGE) { + Serial.println(F("Selected TCXO voltage is invalid for this module!")); + while (true); + } + + // Some SX126x modules use DIO2 as RF switch. To enable + // this feature, the following method can be used. + // NOTE: As long as DIO2 is configured to control RF switch, + // it can't be used as interrupt pin! + if (radio1.setDio2AsRfSwitch() != RADIOLIB_ERR_NONE) { + Serial.println(F("Failed to set DIO2 as RF switch!")); + while (true); + } + + Serial.println(F("All settings succesfully changed!")); +} + +void loop() { + // nothing here +} diff --git a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino new file mode 100644 index 000000000..dbf4a9d25 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino @@ -0,0 +1,113 @@ +/* + RadioLib SX126x Spectrum Scan Example + + This example shows how to perform a spectrum power scan using SX126x. + The output is in the form of scan lines, each line has 33 power bins. + First power bin corresponds to -11 dBm, the second to -15 dBm and so on. + Higher number of samples in a bin corresponds to more power received + at that level. + + To show the results in a plot, run the Python script + RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py + + WARNING: This functionality is experimental and requires a binary patch + to be uploaded to the SX126x device. There may be some undocumented + side effects! + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// this file contains binary patch for the SX1262 +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +void setup() { + Serial.begin(115200); + + // initialize SX1262 FSK modem with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.beginFSK(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // upload a patch to the SX1262 to enable spectral scan + // NOTE: this patch is uploaded into volatile memory, + // and must be re-uploaded on every power up + Serial.print(F("[SX1262] Uploading patch ... ")); + state = radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan)); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // configure scan bandwidth to 234.4 kHz + // and disable the data shaping + Serial.print(F("[SX1262] Setting scan parameters ... ")); + state = radio.setRxBandwidth(234.3); + state |= radio.setDataShaping(RADIOLIB_SHAPING_NONE); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[SX1262] Starting spectral scan ... ")); + + // start spectral scan + // number of scans in each line is 2048 + // number of samples: 2048 (fewer samples = better temporal resolution) + int state = radio.spectralScanStart(2048); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // wait for spectral scan to finish + while(radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) { + delay(10); + } + + // read the results + uint16_t results[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; + state = radio.spectralScanGetResult(results); + if(state == RADIOLIB_ERR_NONE) { + // we have some results, print it + Serial.print("SCAN "); + for(uint8_t i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) { + Serial.print(results[i]); + Serial.print(','); + } + Serial.println(" END"); + } + + // wait a little bit before the next scan + delay(5); +} \ No newline at end of file diff --git a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino new file mode 100644 index 000000000..e7d6b33a3 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino @@ -0,0 +1,129 @@ +/* + RadioLib SX126x Spectrum Scan Example + + This example shows how to perform a spectrum power scan using SX126x. + The output is in the form of scan lines, each line has 33 power bins. + First power bin corresponds to -11 dBm, the second to -15 dBm and so on. + Higher number of samples in a bin corresponds to more power received + at that level. The example performs frequency sweep over a given range. + + To show the results in a plot, run the Python script + RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py + + WARNING: This functionality is experimental and requires a binary patch + to be uploaded to the SX126x device. There may be some undocumented + side effects! + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// this file contains binary patch for the SX1262 +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// frequency range in MHz to scan +const float freqStart = 431; +const float freqEnd = 435; + +void setup() { + Serial.begin(115200); + + // initialize SX1262 FSK modem at the initial frequency + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.beginFSK(freqStart); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // upload a patch to the SX1262 to enable spectral scan + // NOTE: this patch is uploaded into volatile memory, + // and must be re-uploaded on every power up + Serial.print(F("[SX1262] Uploading patch ... ")); + state = radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan)); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // configure scan bandwidth to 234.4 kHz + // and disable the data shaping + Serial.print(F("[SX1262] Setting scan parameters ... ")); + state = radio.setRxBandwidth(234.3); + state |= radio.setDataShaping(RADIOLIB_SHAPING_NONE); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + // perform scan over the entire frequency range + float freq = freqStart; + while(freq <= freqEnd) { + Serial.print("FREQ "); + Serial.println(freq, 2); + + // start spectral scan + // number of samples: 2048 (fewer samples = better temporal resolution) + Serial.print(F("[SX1262] Starting spectral scan ... ")); + int state = radio.spectralScanStart(2048); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // wait for spectral scan to finish + while(radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) { + delay(10); + } + + // read the results + uint16_t results[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; + state = radio.spectralScanGetResult(results); + if(state == RADIOLIB_ERR_NONE) { + // we have some results, print it + Serial.print("SCAN "); + for(uint8_t i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) { + Serial.print(results[i]); + Serial.print(','); + } + Serial.println(" END"); + } + + // wait a little bit before the next scan + delay(5); + + // set the next frequency + // the frequency step should be slightly smaller + // or the same as the Rx bandwidth set in setup + freq += 0.2; + radio.setFrequency(freq); + } + +} diff --git a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino new file mode 100644 index 000000000..8cf890eb5 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino @@ -0,0 +1,108 @@ +/* + RadioLib SX126x Blocking Transmit Example + + This example transmits packets using SX1262 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX126x family can also be used. + + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 radio = RadioShield.ModuleA; + +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // some modules have an external RF switch + // controlled via two pins (RX enable, TX enable) + // to enable automatic control of the switch, + // call the following method + // RX enable: 4 + // TX enable: 5 + /* + radio.setRfSwitchPins(4, 5); + */ +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + Serial.print(F("[SX1262] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + // print measured data rate + Serial.print(F("[SX1262] Datarate:\t")); + Serial.print(radio.getDataRate()); + Serial.println(F(" bps")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F("too long!")); + + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + // timeout occured while transmitting packet + Serial.println(F("timeout!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino new file mode 100644 index 000000000..be281597a --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -0,0 +1,134 @@ +/* + RadioLib SX126x Transmit with Interrupts Example + + This example transmits LoRa packets with one second delays + between them. Each packet contains up to 256 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX126x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 radio = RadioShield.ModuleA; + +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when packet transmission is finished + radio.setPacketSentAction(setFlag); + + // start transmitting the first packet + Serial.print(F("[SX1262] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + transmissionState = radio.startTransmit("Hello World!"); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.startTransmit(byteArr, 8); + */ +} + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + // NOTE: when using interrupt-driven transmit method, + // it is not possible to automatically measure + // transmission data rate using getDataRate() + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[SX1262] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + transmissionState = radio.startTransmit(byteArr, 8); + */ + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino new file mode 100644 index 000000000..6a23001aa --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino @@ -0,0 +1,71 @@ +/* + RadioLib SX127x Blocking Channel Activity Detection Example + + This example scans the current LoRa channel and detects + valid LoRa preambles. Preamble is the first part of + LoRa transmission, so this can be used to check + if the LoRa channel is free, or if you should start + receiving a message. + + Other modules from SX127x/RFM9x family can also be used. + + Using blocking CAD is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt CAD is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[SX1278] Scanning channel for LoRa preamble ... ")); + + // start scanning current channel + int state = radio.scanChannel(); + + if (state == RADIOLIB_PREAMBLE_DETECTED) { + // LoRa preamble was detected + Serial.println(F("detected preamble!")); + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // no preamble was detected, channel is free + Serial.println(F("channel is free!")); + + } + + // wait 100 ms before new scan + delay(100); +} diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino new file mode 100644 index 000000000..631ae909b --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino @@ -0,0 +1,125 @@ +/* + RadioLib SX127x Channel Activity Detection with Interrupts Example + + This example scans the current LoRa channel and detects + valid LoRa preambles. Preamble is the first part of + LoRa transmission, so this can be used to check + if the LoRa channel is free, or if you should start + receiving a message. + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +void setup() { + // Serial port speed must be high enough for this example + Serial.begin(115200); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when LoRa preamble is not detected within CAD timeout period + radio.setDio0Action(setFlagTimeout, RISING); + + // set the function that will be called + // when LoRa preamble is detected + radio.setDio1Action(setFlagDetected, RISING); + + // start scanning the channel + Serial.print(F("[SX1278] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +// flag to indicate that a preamble was not detected +volatile bool timeoutFlag = false; + +// flag to indicate that a preamble was detected +volatile bool detectedFlag = false; + +// this function is called when no preamble +// is detected within timeout period +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlagTimeout(void) { + // we timed out, set the flag + timeoutFlag = true; +} + +// this function is called when LoRa preamble +// is detected within timeout period +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlagDetected(void) { + // we got a preamble, set the flag + detectedFlag = true; +} + +void loop() { + // check if we need to restart channel activity detection + if(detectedFlag || timeoutFlag) { + // check if we got a preamble + if(detectedFlag) { + // LoRa preamble was detected + Serial.println(F("[SX1278] Preamble detected!")); + } else { + // nothing was detected + Serial.println(F("[SX1278] Channel free!")); + } + + // start scanning the channel + Serial.print(F("[SX1278] Starting scan for LoRa preamble ... ")); + + // start scanning current channel + int state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // reset flags + timeoutFlag = false; + detectedFlag = false; + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino new file mode 100644 index 000000000..945ded9fc --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino @@ -0,0 +1,204 @@ +/* + RadioLib SX127x Receive after Channel Activity Detection Example + + This example scans the current LoRa channel and detects + valid LoRa preambles. Preamble is the first part of + LoRa transmission, so this can be used to check + if the LoRa channel is free, or if you should start + receiving a message. If a preamble is detected, + the module will switch to receive mode and receive the packet. + + For most use-cases, it should be enough to just use the + interrupt-driven reception described in the example + "SX127x_Receive_Interrupt". + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +void setup() { + // Serial port speed must be high enough for this example + Serial.begin(115200); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when LoRa preamble is not detected within CAD timeout period + // or when a packet is received + radio.setDio0Action(setFlagTimeout, RISING); + + // set the function that will be called + // when LoRa preamble is detected + radio.setDio1Action(setFlagDetected, RISING); + + // start scanning the channel + Serial.print(F("[SX1278] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +// flag to indicate that a preamble was not detected +volatile bool timeoutFlag = false; + +// flag to indicate that a preamble was detected +volatile bool detectedFlag = false; + +// flag to indicate if we are currently receiving +bool receiving = false; + +// this function is called when no preamble +// is detected within timeout period +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlagTimeout(void) { + // we timed out, set the flag + timeoutFlag = true; +} + +// this function is called when LoRa preamble +// is detected within timeout period +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlagDetected(void) { + // we got a preamble, set the flag + detectedFlag = true; +} + +void loop() { + // check if we need to restart channel activity detection + if(detectedFlag || timeoutFlag) { + int state = RADIOLIB_ERR_NONE; + + // check ongoing reception + if(receiving) { + // DIO triggered while reception is ongoing + // that means we got a packet + + // reset flags first + detectedFlag = false; + timeoutFlag = false; + + // you can read received data as an Arduino String + String str; + state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + state = radio.readData(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1278] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1278] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[SX1278] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[SX1278] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[SX1278] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("[SX1278] CRC error!")); + + } else { + // some other error occurred + Serial.print(F("[SX1278] Failed, code ")); + Serial.println(state); + + } + + // reception is done now + receiving = false; + + } + + // check if we got a preamble + if(detectedFlag) { + // LoRa preamble was detected + Serial.print(F("[SX1278] Preamble detected, starting reception ... ")); + state = radio.startReceive(0, RADIOLIB_SX127X_RXSINGLE); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // set the flag for ongoing reception + receiving = true; + + } else if(!receiving) { + // nothing was detected + // do not print anything, it just spams the console + + } + + // if we're not receiving, start scanning again + if(!receiving) { + int state = radio.startChannelScan(); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("[SX1278] Starting new scan failed, code ")); + Serial.println(state); + } + + } + + // reset flags + timeoutFlag = false; + detectedFlag = false; + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino new file mode 100644 index 000000000..aa2b2127f --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino @@ -0,0 +1,206 @@ +/* + RadioLib SX127x FSK Modem Example + + This example shows how to use FSK modem in SX127x chips. + + NOTE: The sketch below is just a guide on how to use + FSK modem, so this code should not be run directly! + Instead, modify the other examples to use FSK + modem and use the appropriate configuration + methods. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---fsk-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 FSK modem with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, you can switch between LoRa and FSK modes + // + // radio.begin() start LoRa mode (and disable FSK) + // radio.beginFSK() start FSK mode (and disable LoRa) + + // the following settings can also + // be modified at run-time + state = radio.setFrequency(433.5); + state = radio.setBitRate(100.0); + state = radio.setFrequencyDeviation(10.0); + state = radio.setRxBandwidth(250.0); + state = radio.setOutputPower(10.0); + state = radio.setCurrentLimit(100); + state = radio.setDataShaping(RADIOLIB_SHAPING_0_5); + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.setSyncWord(syncWord, 8); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Unable to set configuration, code ")); + Serial.println(state); + while (true); + } + + // FSK modulation can be changed to OOK + // NOTE: When using OOK, the maximum bit rate is only 32.768 kbps! + // Also, data shaping changes from Gaussian filter to + // simple filter with cutoff frequency. Make sure to call + // setDataShapingOOK() to set the correct shaping! + state = radio.setOOK(true); + state = radio.setDataShapingOOK(1); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Unable to change modulation, code ")); + Serial.println(state); + while (true); + } + + #warning "This sketch is just an API guide! Read the note at line 6." +} + +void loop() { + // FSK modem can use the same transmit/receive methods + // as the LoRa modem, even their interrupt-driven versions + // NOTE: FSK modem maximum packet length is 63 bytes! + + // transmit FSK packet + int state = radio.transmit("Hello World!"); + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1278] Packet transmitted successfully!")); + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + Serial.println(F("[SX1278] Packet too long!")); + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + Serial.println(F("[SX1278] Timed out while transmitting!")); + } else { + Serial.println(F("[SX1278] Failed to transmit packet, code ")); + Serial.println(state); + } + + // receive FSK packet + String str; + state = radio.receive(str); + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1278] Received packet!")); + Serial.print(F("[SX1278] Data:\t")); + Serial.println(str); + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("[SX1278] Timed out while waiting for packet!")); + } else { + Serial.println(F("[SX1278] Failed to receive packet, code ")); + Serial.println(state); + } + + // FSK modem has built-in address filtering system + // it can be enabled by setting node address, broadcast + // address, or both + // + // to transmit packet to a particular address, + // use the following methods: + // + // radio.transmit("Hello World!", address); + // radio.startTransmit("Hello World!", address); + + // set node address to 0x02 + state = radio.setNodeAddress(0x02); + // set broadcast address to 0xFF + state = radio.setBroadcastAddress(0xFF); + if (state != RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1278] Unable to set address filter, code ")); + Serial.println(state); + } + + // address filtering can also be disabled + // NOTE: calling this method will also erase previously set + // node and broadcast address + /* + state = radio.disableAddressFiltering(); + if (state != RADIOLIB_ERR_NONE) { + Serial.println(F("Unable to remove address filter, code ")); + } + */ + + // FSK modem supports direct data transmission + // in this mode, SX127x directly transmits any data + // sent to DIO1 (data) and DIO2 (clock) + + // activate direct mode transmitter + state = radio.transmitDirect(); + if (state != RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1278] Unable to start direct transmission mode, code ")); + Serial.println(state); + } + + // using the direct mode, it is possible to transmit + // FM notes with Arduino tone() function + + // it is recommended to set data shaping to 0 + // (no shaping) when transmitting audio + state = radio.setDataShaping(0.0); + if (state != RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1278] Unable to set data shaping, code ")); + Serial.println(state); + } + + // transmit FM tone at 1000 Hz for 1 second, then 500 Hz for 1 second + // (DIO2 is connected to Arduino pin 4) + // Note: tone() function is not available on Arduino Due and CubeCell + // on these platforms, the following will do nothing + #if !defined(RADIOLIB_TONE_UNSUPPORTED) + tone(4, 1000); + delay(1000); + tone(4, 500); + delay(1000); + noTone(4); + #endif + + // NOTE: after calling transmitDirect(), SX127x will start + // transmitting immediately! This signal can jam other + // devices at the same frequency, it is up to the user + // to disable it with standby() method! + + // direct mode transmissions can also be received + // as bit stream on DIO1 (data) and DIO2 (clock) + state = radio.receiveDirect(); + if (state != RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1278] Unable to start direct reception mode, code ")); + Serial.println(state); + } + + // NOTE: you will not be able to send or receive packets + // while direct mode is active! to deactivate it, call method + // radio.packetMode() +} diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino new file mode 100644 index 000000000..df025bc99 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino @@ -0,0 +1,145 @@ +/* + RadioLib SX127x Ping-Pong Example + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// uncomment the following only on one +// of the nodes to initiate the pings +//#define INITIATING_NODE + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// NRST pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// save transmission states between loops +int transmissionState = RADIOLIB_ERR_NONE; + +// flag to indicate transmission or reception state +bool transmitFlag = false; + +// flag to indicate that a packet was sent or received +volatile bool operationDone = false; + +// this function is called when a complete packet +// is transmitted or received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent or received packet, set the flag + operationDone = true; +} + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + radio.setDio0Action(setFlag, RISING); + + #if defined(INITIATING_NODE) + // send the first packet on this node + Serial.print(F("[SX1278] Sending first packet ... ")); + transmissionState = radio.startTransmit("Hello World!"); + transmitFlag = true; + #else + // start listening for LoRa packets on this node + Serial.print(F("[SX1278] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + #endif +} + +void loop() { + // check if the previous operation finished + if(operationDone) { + // reset flag + operationDone = false; + + if(transmitFlag) { + // the previous operation was transmission, listen for response + // print the result + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // listen for response + radio.startReceive(); + transmitFlag = false; + + } else { + // the previous operation was reception + // print data and send another packet + String str; + int state = radio.readData(str); + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1278] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1278] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[SX1278] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[SX1278] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[SX1278] Sending another packet ... ")); + transmissionState = radio.startTransmit("Hello World!"); + transmitFlag = true; + } + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino new file mode 100644 index 000000000..bdfae6d5e --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino @@ -0,0 +1,110 @@ +/* + RadioLib SX127x Blocking Receive Example + + This example listens for LoRa transmissions using SX127x Lora modules. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - preamble length + + Other modules from SX127x/RFM9x family can also be used. + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[SX1278] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[SX1278] Data:\t\t\t")); + Serial.println(str); + + // print the RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[SX1278] RSSI:\t\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print the SNR (Signal-to-Noise Ratio) + // of the last received packet + Serial.print(F("[SX1278] SNR:\t\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + // of the last received packet + Serial.print(F("[SX1278] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino new file mode 100644 index 000000000..dee4214f5 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino @@ -0,0 +1,80 @@ +/* + RadioLib SX127x Direct Receive Example + + This example shows how to receive FSK packets without using + SX127x packet engine. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// DIO2 pin: 5 +const int pin = 5; + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with FSK modem at 9600 bps + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(434.0, 9.6, 20.0); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the direct mode sync word + // the default RadioLib FSK sync word is 0x12AD + // we can add in some preamble bits, to lower the chance + // of false detection + radio.setDirectSyncWord(0x555512AD, 32); + + // set function that will be called each time a bit is received + radio.setDirectAction(readBit); + + // start direct mode reception + radio.receiveDirect(); +} + +// this function is called when a new bit is received +void readBit(void) { + // read the data bit + radio.readBit(pin); +} + +void loop() { + // we expect the packet to contain the string "Hello World!", + // a length byte and 2 CRC bytes, that's 15 bytes in total + if(radio.available() >= 15) { + Serial.println("[SX1278] Received packet in direct mode!"); + while(radio.available()) { + // read a byte + byte b = radio.read(); + + // print it + Serial.print(b, HEX); + Serial.print('\t'); + Serial.write(b); + Serial.println(); + } + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino new file mode 100644 index 000000000..d3423b9e5 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino @@ -0,0 +1,181 @@ +/* + RadioLib SX127x Transmit with Frequency Hopping Example + + This example transmits packets using SX1278 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ + + SX127x supports FHSS or Frequency Hopping Spread Spectrum. + Once a hopping period is set and a transmission is started, the radio + will begin triggering interrupts every hop period where the radio frequency + is changed to the next channel. +*/ + +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// flag to indicate frequency must be changed +volatile bool fhssChangeFlag = false; + +// the channel frequencies can be generated randomly or hard coded +// NOTE: The frequency list MUST be the same on both sides! +float channels[] = { 433.0, 433.4, 433.2, 433.6, 434.0, 433.8 }; +int numberOfChannels = sizeof(channels) / sizeof(float); + +// counter to keep track of how many frequency hops were performed +int hopsCompleted = 0; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setRxFlag(void) { + receivedFlag = true; +} + +// this function is called when FhssChangeChannel interrupt occurs +// (at the beginning of each transmission) +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFHSSFlag(void) { + fhssChangeFlag = true; +} + +void setup() { + Serial.begin(9600); + + // begin radio on home channel + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(channels[0]); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set hop period in symbols + // this will also enable FHSS + state = radio.setFHSSHoppingPeriod(9); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function to call when reception is finished + radio.setDio0Action(setRxFlag, RISING); + + // set the function to call when we need to change frequency + radio.setDio1Action(setFHSSFlag, RISING); + + // start listening for LoRa packets + Serial.print(F("[SX1278] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + // check if the reception flag is set + if (receivedFlag == true) { + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1278] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1278] Data:\t\t")); + Serial.println(str); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("[SX1278] CRC error!")); + + } else { + // some other error occurred + Serial.print(F("[SX1278] Failed, code ")); + Serial.println(state); + + } + + // print the number of hops it took + Serial.print(F("[SX1278] Hops completed: ")); + Serial.println(hopsCompleted); + + // reset the counter + hopsCompleted = 0; + + // put the module back to listen mode + radio.startReceive(); + + // we're ready to receive more packets, clear the flag + receivedFlag = false; + } + + // check if we need to do another frequency hop + if (fhssChangeFlag == true) { + // we do, change it now + int state = radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("[SX1278] Failed to change frequency, code ")); + Serial.println(state); + } + + // increment the counter + hopsCompleted++; + + // clear the FHSS interrupt + radio.clearFHSSInt(); + + // we're ready to do another hop, clear the flag + fhssChangeFlag = false; + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino new file mode 100644 index 000000000..0e833e0d9 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -0,0 +1,143 @@ +/* + RadioLib SX127x Receive with Interrupts Example + + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + radio.setPacketReceivedAction(setFlag); + + // start listening for LoRa packets + Serial.print(F("[SX1278] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.scanChannel(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1278] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1278] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[SX1278] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[SX1278] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[SX1278] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("[SX1278] CRC error!")); + + } else { + // some other error occurred + Serial.print(F("[SX1278] Failed, code ")); + Serial.println(state); + + } + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Settings/SX127x_Settings.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Settings/SX127x_Settings.ino new file mode 100644 index 000000000..007a49fbb --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Settings/SX127x_Settings.ino @@ -0,0 +1,152 @@ +/* + RadioLib SX127x Settings Example + + This example shows how to change all the properties of LoRa transmission. + RadioLib currently supports the following settings: + - pins (SPI slave select, digital IO 0, digital IO 1) + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - output power during transmission + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio1 = new Module(10, 2, 9, 3); + +// SX1272 has different connections: +// NSS pin: 9 +// DIO0 pin: 4 +// RESET pin: 5 +// DIO1 pin: 6 +SX1272 radio2 = new Module(9, 4, 5, 6); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1276 radio3 = RadioShield.ModuleB; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio1.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // initialize the second LoRa instance with + // non-default settings + // this LoRa link will have high data rate, + // but lower range + // NOTE: when using spreading factor 6, the total packet + // length has to be known in advance! + // you have to pass the number of expected bytes + // to the receive() method + Serial.print(F("[SX1272] Initializing ... ")); + // carrier frequency: 915.0 MHz + // bandwidth: 500.0 kHz + // spreading factor: 6 + // coding rate: 5 + // sync word: 0x34 + // output power: 2 dBm + // preamble length: 20 symbols + // amplifier gain: 1 (maximum gain) + state = radio2.begin(915.0, 500.0, 6, 5, 0x34, 2, 20, 1); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // you can also change the settings at runtime + // and check if the configuration was changed successfully + + // set carrier frequency to 433.5 MHz + if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { + Serial.println(F("Selected frequency is invalid for this module!")); + while (true); + } + + // set bandwidth to 250 kHz + if (radio1.setBandwidth(250.0) == RADIOLIB_ERR_INVALID_BANDWIDTH) { + Serial.println(F("Selected bandwidth is invalid for this module!")); + while (true); + } + + // set spreading factor to 10 + if (radio1.setSpreadingFactor(10) == RADIOLIB_ERR_INVALID_SPREADING_FACTOR) { + Serial.println(F("Selected spreading factor is invalid for this module!")); + while (true); + } + + // set coding rate to 6 + if (radio1.setCodingRate(6) == RADIOLIB_ERR_INVALID_CODING_RATE) { + Serial.println(F("Selected coding rate is invalid for this module!")); + while (true); + } + + // set LoRa sync word to 0x14 + // NOTE: value 0x34 is reserved for LoRaWAN networks and should not be used + if (radio1.setSyncWord(0x14) != RADIOLIB_ERR_NONE) { + Serial.println(F("Unable to set sync word!")); + while (true); + } + + // set output power to 10 dBm (accepted range is -3 - 17 dBm) + // NOTE: 20 dBm value allows high power operation, but transmission + // duty cycle MUST NOT exceed 1% + if (radio1.setOutputPower(10) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + Serial.println(F("Selected output power is invalid for this module!")); + while (true); + } + + // set over current protection limit to 80 mA (accepted range is 45 - 240 mA) + // NOTE: set value to 0 to disable overcurrent protection + if (radio1.setCurrentLimit(80) == RADIOLIB_ERR_INVALID_CURRENT_LIMIT) { + Serial.println(F("Selected current limit is invalid for this module!")); + while (true); + } + + // set LoRa preamble length to 15 symbols (accepted range is 6 - 65535) + if (radio1.setPreambleLength(15) == RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH) { + Serial.println(F("Selected preamble length is invalid for this module!")); + while (true); + } + + // set amplifier gain to 1 (accepted range is 1 - 6, where 1 is maximum gain) + // NOTE: set value to 0 to enable automatic gain control + // leave at 0 unless you know what you're doing + if (radio1.setGain(1) == RADIOLIB_ERR_INVALID_GAIN) { + Serial.println(F("Selected gain is invalid for this module!")); + while (true); + } + + Serial.println(F("All settings successfully changed!")); +} + +void loop() { + // nothing here +} diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino new file mode 100644 index 000000000..2298ac2cb --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino @@ -0,0 +1,105 @@ +/* + RadioLib SX127x Blocking Transmit Example + + This example transmits packets using SX1278 LoRa radio module. + Each packet contains up to 255 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX127x/RFM9x family can also be used. + + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // some modules have an external RF switch + // controlled via two pins (RX enable, TX enable) + // to enable automatic control of the switch, + // call the following method + // RX enable: 4 + // TX enable: 5 + /* + radio.setRfSwitchPins(4, 5); + */ +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + Serial.print(F("[SX1278] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 255 characters long + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F(" success!")); + + // print measured data rate + Serial.print(F("[SX1278] Datarate:\t")); + Serial.print(radio.getDataRate()); + Serial.println(F(" bps")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F("too long!")); + + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + // timeout occurred while transmitting packet + Serial.println(F("timeout!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino new file mode 100644 index 000000000..15ef3ae81 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -0,0 +1,182 @@ +/* + RadioLib SX127x Transmit with Frequency Hopping Example + + This example transmits packets using SX1278 LoRa radio module. + Each packet contains up to 255 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ + + SX127x supports FHSS or Frequency Hopping Spread Spectrum. + Once a hopping period is set and a transmission is started, the radio + will begin triggering interrupts every hop period where the radio frequency + is changed to the next channel. +*/ + +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// flag to indicate that a packet was received +volatile bool transmittedFlag = false; + +// flag to indicate frequency must be changed +volatile bool fhssChangeFlag = false; + +// the channel frequencies can be generated randomly or hard coded +// NOTE: The frequency list MUST be the same on both sides! +float channels[] = { 433.0, 433.4, 433.2, 433.6, 434.0, 433.8 }; +int numberOfChannels = sizeof(channels) / sizeof(float); + +// counter to keep track of how many frequency hops were performed +int hopsCompleted = 0; + +// counter that increments with each sent packet +int packetCounter = 0; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +// this is the packet that will be sent +String longPacket = "Let's create a really long packet to trigger \ +lots of hop interrupts. A packet can be up to 255 bytes long. \ +This packet is 222 bytes so using sf = 9, bw = 125, timeOnAir is \ +1488ms. 1488ms / (9*4.10ms) = 40 hops. Counter: "; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setTxFlag(void) { + transmittedFlag = true; +} + +// this function is called when FhssChangeChannel interrupt occurs +// (at the beginning of each transmission) +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFHSSFlag(void) { + fhssChangeFlag = true; +} + +void setup() { + Serial.begin(9600); + + // begin radio on home channel + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(channels[0]); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set hop period in symbols + // this will also enable FHSS + state = radio.setFHSSHoppingPeriod(9); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function to call when transmission is finished + radio.setDio0Action(setTxFlag, RISING); + + // set the function to call when we need to change frequency + radio.setDio1Action(setFHSSFlag, RISING); + + // start transmitting the first packet + Serial.print(F("[SX1278] Sending first packet ... ")); + String packet = longPacket + packetCounter; + transmissionState = radio.startTransmit(packet); +} + +void loop() { + // check if the transmission flag is set + if (transmittedFlag == true) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // The channel is automatically reset to 0 upon completion + Serial.print(F("[SX1278] Radio is on channel: ")); + Serial.println(radio.getFHSSChannel()); + + // print the number of hops it took + Serial.print(F("[SX1278] Hops completed: ")); + Serial.println(hopsCompleted); + + // reset the counter + hopsCompleted = 0; + + // return to home channel before the next transaction + radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + + // wait a second before transmitting again + delay(1000); + + // increment the packet counter + packetCounter++; + + // send another packet + Serial.print(F("[SX1278] Sending another packet ... ")); + String packet = longPacket + packetCounter; + transmissionState = radio.startTransmit(packet); + } + + // check if we need to do another frequency hop + if (fhssChangeFlag == true) { + // we do, change it now + int state = radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("[SX1278] Failed to change frequency, code ")); + Serial.println(state); + } + + // increment the counter + hopsCompleted++; + + // clear the FHSS interrupt + radio.clearFHSSInt(); + + // we're ready to do another hop, clear the flag + fhssChangeFlag = false; + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino new file mode 100644 index 000000000..7cdce5937 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -0,0 +1,131 @@ +/* + RadioLib SX127x Transmit with Interrupts Example + + This example transmits LoRa packets with one second delays + between them. Each packet contains up to 255 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when packet transmission is finished + radio.setPacketSentAction(setFlag); + + // start transmitting the first packet + Serial.print(F("[SX1278] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 255 characters long + transmissionState = radio.startTransmit("Hello World!"); + + // you can also transmit byte array up to 255 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + transmissionState = radio.startTransmit(byteArr, 8); + */ +} + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + // NOTE: when using interrupt-driven transmit method, + // it is not possible to automatically measure + // transmission data rate using getDataRate() + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[SX1278] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 255 characters long + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); + + // you can also transmit byte array up to 255 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + transmissionState = radio.startTransmit(byteArr, 8); + */ + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino new file mode 100644 index 000000000..5b7a1ffd0 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino @@ -0,0 +1,110 @@ +/* + RadioLib SX128x BLE Modem Example + + This example shows how to use BLE modem in SX128x chips. + RadioLib does not provide BLE protocol support (yet), + only compatibility with the physical layer. + + NOTE: The sketch below is just a guide on how to use + BLE modem, so this code should not be run directly! + Instead, modify the other examples to use BLE + modem and use the appropriate configuration + methods. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---ble-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + int state = radio.beginBLE(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, you can switch between any of the modems + // + // radio.begin() start LoRa modem (and disable BLE) + // radio.beginBLE() start BLE modem (and disable LoRa) + + // the following settings can also + // be modified at run-time + state = radio.setFrequency(2410.5); + state = radio.setBitRate(250); + state = radio.setFrequencyDeviation(100.0); + state = radio.setOutputPower(5); + state = radio.setDataShaping(1.0); + state = radio.setAccessAddress(0x12345678); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Unable to set configuration, code ")); + Serial.println(state); + while (true); + } + + #warning "This sketch is just an API guide! Read the note at line 8." +} + +void loop() { + // BLE modem can use the same transmit/receive methods + // as the LoRa modem, even their interrupt-driven versions + + // transmit BLE packet + int state = radio.transmit("Hello World!"); + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1280] Packet transmitted successfully!")); + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + Serial.println(F("[SX1280] Packet too long!")); + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + Serial.println(F("[SX1280] Timed out while transmitting!")); + } else { + Serial.print(F("[SX1280] Failed to transmit packet, code ")); + Serial.println(state); + } + + // receive BLE packet + String str; + state = radio.receive(str); + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1280] Received packet!")); + Serial.print(F("[SX1280] Data:\t")); + Serial.println(str); + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("[SX1280] Timed out while waiting for packet!")); + } else { + Serial.print(F("[SX1280] Failed to receive packet, code ")); + Serial.println(state); + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino new file mode 100644 index 000000000..fef3ccc0e --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino @@ -0,0 +1,73 @@ +/* + RadioLib SX128x Blocking Channel Activity Detection Example + + This example uses SX1280 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + + Other modules from SX128x family can also be used. + + Using blocking CAD is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt CAD is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[SX1280] Scanning channel for LoRa transmission ... ")); + + // start scanning current channel + int state = radio.scanChannel(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa preamble was detected + Serial.println(F("detected!")); + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // no preamble was detected, channel is free + Serial.println(F("channel is free!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait 100 ms before new scan + delay(100); +} diff --git a/lib/lib_rf/RadioLib/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino new file mode 100644 index 000000000..168ab510a --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino @@ -0,0 +1,109 @@ +/* + RadioLib SX128x FLRC Modem Example + + This example shows how to use FLRC modem in SX128x chips. + + NOTE: The sketch below is just a guide on how to use + FLRC modem, so this code should not be run directly! + Instead, modify the other examples to use FLRC + modem and use the appropriate configuration + methods. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---flrc-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + int state = radio.beginFLRC(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, you can switch between any of the modems + // + // radio.begin() start LoRa modem (and disable FLRC) + // radio.beginFLRC() start FLRC modem (and disable LoRa) + + // the following settings can also + // be modified at run-time + state = radio.setFrequency(2410.5); + state = radio.setBitRate(520); + state = radio.setCodingRate(2); + state = radio.setOutputPower(5); + state = radio.setDataShaping(1.0); + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; + state = radio.setSyncWord(syncWord, 4); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Unable to set configuration, code ")); + Serial.println(state); + while (true); + } + + #warning "This sketch is just an API guide! Read the note at line 6." +} + +void loop() { + // FLRC modem can use the same transmit/receive methods + // as the LoRa modem, even their interrupt-driven versions + + // transmit FLRC packet + int state = radio.transmit("Hello World!"); + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1280] Packet transmitted successfully!")); + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + Serial.println(F("[SX1280] Packet too long!")); + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + Serial.println(F("[SX1280] Timed out while transmitting!")); + } else { + Serial.println(F("[SX1280] Failed to transmit packet, code ")); + Serial.println(state); + } + + // receive FLRC packet + String str; + state = radio.receive(str); + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1280] Received packet!")); + Serial.print(F("[SX1280] Data:\t")); + Serial.println(str); + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("[SX1280] Timed out while waiting for packet!")); + } else { + Serial.print(F("[SX1280] Failed to receive packet, code ")); + Serial.println(state); + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino new file mode 100644 index 000000000..13412b493 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino @@ -0,0 +1,109 @@ +/* + RadioLib SX128x GFSK Modem Example + + This example shows how to use GFSK modem in SX128x chips. + + NOTE: The sketch below is just a guide on how to use + GFSK modem, so this code should not be run directly! + Instead, modify the other examples to use GFSK + modem and use the appropriate configuration + methods. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---gfsk-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + int state = radio.beginGFSK(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, you can switch between any of the modems + // + // radio.begin() start LoRa modem (and disable GFSK) + // radio.beginGFSK() start GFSK modem (and disable LoRa) + + // the following settings can also + // be modified at run-time + state = radio.setFrequency(2410.5); + state = radio.setBitRate(200); + state = radio.setFrequencyDeviation(100.0); + state = radio.setOutputPower(5); + state = radio.setDataShaping(RADIOLIB_SHAPING_1_0); + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 0x89}; + state = radio.setSyncWord(syncWord, 5); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Unable to set configuration, code ")); + Serial.println(state); + while (true); + } + + #warning "This sketch is just an API guide! Read the note at line 6." +} + +void loop() { + // GFSK modem can use the same transmit/receive methods + // as the LoRa modem, even their interrupt-driven versions + + // transmit GFSK packet + int state = radio.transmit("Hello World!"); + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1280] Packet transmitted successfully!")); + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + Serial.println(F("[SX1280] Packet too long!")); + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + Serial.println(F("[SX1280] Timed out while transmitting!")); + } else { + Serial.println(F("[SX1280] Failed to transmit packet, code ")); + Serial.println(state); + } + + // receive GFSK packet + String str; + state = radio.receive(str); + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1280] Received packet!")); + Serial.print(F("[SX1280] Data:\t")); + Serial.println(str); + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("[SX1280] Timed out while waiting for packet!")); + } else { + Serial.print(F("[SX1280] Failed to receive packet, code ")); + Serial.println(state); + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino new file mode 100644 index 000000000..d7427880b --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino @@ -0,0 +1,95 @@ +/* + RadioLib SX128x Ranging Example + + This example performs ranging exchange between two + SX1280 LoRa radio modules. Ranging allows to measure + distance between the modules using time-of-flight + measurement. + + Only SX1280 and SX1282 without external RF switch support ranging! + + Note that to get accurate ranging results, calibration is needed! + The process is described in Semtech SX1280 Application Note AN1200.29 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[SX1280] Ranging ... ")); + + // start ranging exchange + // range as master: true + // slave address: 0x12345678 + int state = radio.range(true, 0x12345678); + + // the other module must be configured as slave with the same address + /* + int state = radio.range(false, 0x12345678); + */ + + // if ranging calibration is known, it can be provided + // this should improve the accuracy and precision + /* + uint16_t calibration[3][6] = { + { 10299, 10271, 10244, 10242, 10230, 10246 }, + { 11486, 11474, 11453, 11426, 11417, 11401 }, + { 13308, 13493, 13528, 13515, 13430, 13376 } + }; + + int state = radio.range(true, 0x12345678, calibration); + */ + + if (state == RADIOLIB_ERR_NONE) { + // ranging finished successfully + Serial.println(F("success!")); + Serial.print(F("[SX1280] Distance:\t\t\t")); + Serial.print(radio.getRangingResult()); + Serial.println(F(" meters (raw)")); + + } else if (state == RADIOLIB_ERR_RANGING_TIMEOUT) { + // timed out waiting for ranging packet + Serial.println(F("timed out!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before ranging again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino new file mode 100644 index 000000000..2ba27130a --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino @@ -0,0 +1,110 @@ +/* + RadioLib SX128x Blocking Receive Example + + This example listens for LoRa transmissions using SX126x Lora modules. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - preamble length + + Other modules from SX128x family can also be used. + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[SX1280] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[SX1280] Data:\t\t")); + Serial.println(str); + + // print the RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[SX1280] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print the SNR (Signal-to-Noise Ratio) + // of the last received packet + Serial.print(F("[SX1280] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print the Frequency Error + // of the last received packet + Serial.print(F("[SX1280] Frequency Error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino new file mode 100644 index 000000000..01ec27f3a --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino @@ -0,0 +1,148 @@ +/* + RadioLib SX128x Receive with Interrupts Example + + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + + Other modules from SX128x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + radio.setPacketReceivedAction(setFlag); + + // start listening for LoRa packets + Serial.print(F("[SX1280] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); + // radio.scanChannel(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1280] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1280] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[SX1280] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[SX1280] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print the Frequency Error + // of the last received packet + Serial.print(F("[SX1280] Frequency Error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // put module back to listen mode + radio.startReceive(); + } +} diff --git a/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Settings/SX128x_Settings.ino b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Settings/SX128x_Settings.ino new file mode 100644 index 000000000..1bd5f8fc4 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Settings/SX128x_Settings.ino @@ -0,0 +1,130 @@ +/* + RadioLib SX128x Settings Example + + This example shows how to change all the properties of LoRa transmission. + RadioLib currently supports the following settings: + - pins (SPI slave select, DIO1, DIO2, BUSY pin) + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - output power during transmission + - CRC + - preamble length + + Other modules from SX128x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 radio1 = new Module(10, 2, 3, 9); + +// SX1280 has the following connections: +// NSS pin: 8 +// DIO1 pin: 4 +// NRST pin: 5 +// BUSY pin: 6 +SX1281 radio2 = new Module(8, 4, 5, 6); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1282 radio3 = RadioShield.ModuleB; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + int state = radio1.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // initialize the second LoRa instance with + // non-default settings + // this LoRa link will have high data rate, + // but lower range + Serial.print(F("[SX1281] Initializing ... ")); + // carrier frequency: 2450.0 MHz + // bandwidth: 1625.0 kHz + // spreading factor: 7 + // coding rate: 5 + // sync word: 0x12 (private network) + // output power: 2 dBm + // preamble length: 20 symbols + state = radio2.begin(2450.0, 1625.0, 7, 5, 0x12, 2, 20); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // you can also change the settings at runtime + // and check if the configuration was changed successfully + + // set carrier frequency to 2410.5 MHz + if (radio1.setFrequency(2410.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { + Serial.println(F("Selected frequency is invalid for this module!")); + while (true); + } + + // set bandwidth to 203.125 kHz + if (radio1.setBandwidth(203.125) == RADIOLIB_ERR_INVALID_BANDWIDTH) { + Serial.println(F("Selected bandwidth is invalid for this module!")); + while (true); + } + + // set spreading factor to 10 + if (radio1.setSpreadingFactor(10) == RADIOLIB_ERR_INVALID_SPREADING_FACTOR) { + Serial.println(F("Selected spreading factor is invalid for this module!")); + while (true); + } + + // set coding rate to 6 + if (radio1.setCodingRate(6) == RADIOLIB_ERR_INVALID_CODING_RATE) { + Serial.println(F("Selected coding rate is invalid for this module!")); + while (true); + } + + // set output power to -2 dBm + if (radio1.setOutputPower(-2) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + Serial.println(F("Selected output power is invalid for this module!")); + while (true); + } + + // set LoRa preamble length to 16 symbols (accepted range is 2 - 65535) + if (radio1.setPreambleLength(16) == RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH) { + Serial.println(F("Selected preamble length is invalid for this module!")); + while (true); + } + + // disable CRC + if (radio1.setCRC(false) == RADIOLIB_ERR_INVALID_CRC_CONFIGURATION) { + Serial.println(F("Selected CRC is invalid for this module!")); + while (true); + } + + Serial.println(F("All settings succesfully changed!")); +} + +void loop() { + // nothing here +} diff --git a/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino new file mode 100644 index 000000000..18a26c979 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino @@ -0,0 +1,103 @@ +/* + RadioLib SX128x Blocking Transmit Example + + This example transmits packets using SX1280 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX128x family can also be used. + + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + // carrier frequency: 2400.0 MHz + // bandwidth: 812.5 kHz + // spreading factor: 9 + // coding rate: 7 + // output power: 10 dBm + // preamble length: 12 symbols + // CRC: enabled + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // some modules have an external RF switch + // controlled via two pins (RX enable, TX enable) + // to enable automatic control of the switch, + // call the following method + // RX enable: 4 + // TX enable: 5 + /* + radio.setRfSwitchPins(4, 5); + */ +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + Serial.print(F("[SX1280] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F("too long!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino new file mode 100644 index 000000000..811743da2 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -0,0 +1,127 @@ +/* + RadioLib SX128x Transmit with Interrupts Example + + This example transmits LoRa packets with one second delays + between them. Each packet contains up to 256 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX128x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 radio = RadioShield.ModuleA; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when packet transmission is finished + radio.setPacketSentAction(setFlag); + + // start transmitting the first packet + Serial.print(F("[SX1280] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + transmissionState = radio.startTransmit("Hello World!"); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.startTransmit(byteArr, 8); + */ +} + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[SX1280] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + transmissionState = radio.startTransmit(byteArr, 8); + */ + } +} diff --git a/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino b/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino new file mode 100644 index 000000000..54715ffa8 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino @@ -0,0 +1,89 @@ +/* + RadioLib Si443x Blocking Receive Example + + This example receives packets using Si443x FSK radio module. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bit rate + - frequency deviation + - sync word + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. + + Other modules from Si443x/RFM2x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// Si4432 has the following connections: +// nSEL pin: 10 +// nIRQ pin: 2 +// SDN pin: 9 +Si4432 radio = new Module(10, 2, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//Si4432 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize Si4432 with default settings + Serial.print(F("[Si4432] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[Si4432] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[Si4432] Data:\t\t")); + Serial.println(str); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino b/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino new file mode 100644 index 000000000..a12d2ee39 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino @@ -0,0 +1,123 @@ +/* + RadioLib Si443x Receive with Interrupts Example + + This example listens for FSK transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. + + Other modules from Si443x/RFM2x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// Si4432 has the following connections: +// nSEL pin: 10 +// nIRQ pin: 2 +// SDN pin: 9 +Si4432 radio = new Module(10, 2, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//Si4432 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize Si4432 with default settings + Serial.print(F("[Si4432] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + radio.setPacketReceivedAction(setFlag); + + // start listening for packets + Serial.print(F("[Si4432] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[Si4432] Received packet!")); + + // print data of the packet + Serial.print(F("[Si4432] Data:\t\t\t")); + Serial.println(str); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // put module back to listen mode + radio.startReceive(); + } +} diff --git a/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Settings/Si443x_Settings.ino b/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Settings/Si443x_Settings.ino new file mode 100644 index 000000000..9823e97d0 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Settings/Si443x_Settings.ino @@ -0,0 +1,123 @@ +/* + RadioLib Si443x Settings Example + + This example shows how to change all the properties of RF69 radio. + RadioLib currently supports the following settings: + - pins (SPI slave select, nIRQ, shutdown) + - carrier frequency + - bit rate + - receiver bandwidth + - frequency deviation + - output power during transmission + - sync word + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// Si4432 has the following connections: +// nSEL pin: 10 +// nIRQ pin: 2 +// SDN pin: 9 +Si4432 radio1 = new Module(10, 2, 9); + +// Si4432 has the following connections: +// nSEL pin: 8 +// nIRQ pin: 3 +// SDN pin: 7 +Si4432 radio2 = new Module(8, 3, 7); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//Si4432 radio3 = RadioShield.ModuleB; + +void setup() { + Serial.begin(9600); + + // initialize Si4432 with default settings + Serial.print(F("[Si4432] Initializing ... ")); + int state = radio1.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // initialize Si4432 with non-default settings + Serial.print(F("[Si4432] Initializing ... ")); + // carrier frequency: 868.0 MHz + // bit rate: 200.0 kbps + // frequency deviation: 60.0 kHz + // Rx bandwidth: 335.5 kHz + // output power: 17 dBm + // preamble length: 32 bits + state = radio2.begin(868.0, 200.0, 60.0, 335.5, 17, 32); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // you can also change the settings at runtime + // and check if the configuration was changed successfully + + // set carrier frequency to 433.5 MHz + if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { + Serial.println(F("[Si4432] Selected frequency is invalid for this module!")); + while (true); + } + + // set bit rate to 100.0 kbps + state = radio1.setBitRate(100.0); + if (state == RADIOLIB_ERR_INVALID_BIT_RATE) { + Serial.println(F("[Si4432] Selected bit rate is invalid for this module!")); + while (true); + } else if (state == RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO) { + Serial.println(F("[Si4432] Selected bit rate to bandwidth ratio is invalid!")); + Serial.println(F("[Si4432] Increase receiver bandwidth to set this bit rate.")); + while (true); + } + + // set receiver bandwidth to 284.8 kHz + state = radio1.setRxBandwidth(284.8); + if (state == RADIOLIB_ERR_INVALID_RX_BANDWIDTH) { + Serial.println(F("[Si4432] Selected receiver bandwidth is invalid for this module!")); + while (true); + } + + // set frequency deviation to 10.0 kHz + if (radio1.setFrequencyDeviation(10.0) == RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION) { + Serial.println(F("[Si4432] Selected frequency deviation is invalid for this module!")); + while (true); + } + + // set output power to 2 dBm + if (radio1.setOutputPower(2) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + Serial.println(F("[Si4432] Selected output power is invalid for this module!")); + while (true); + } + + // up to 4 bytes can be set as sync word + // set sync word to 0x01234567 + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; + if (radio1.setSyncWord(syncWord, 4) == RADIOLIB_ERR_INVALID_SYNC_WORD) { + Serial.println(F("[Si4432] Selected sync word is invalid for this module!")); + while (true); + } + + Serial.println(F("[Si4432] All settings changed successfully!")); +} + +void loop() { + // nothing here +} diff --git a/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino b/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino new file mode 100644 index 000000000..7197281a9 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino @@ -0,0 +1,89 @@ +/* + RadioLib Si443x Blocking Transmit Example + + This example transmits packets using Si4432 FSK radio module. + Each packet contains up to 64 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from Si443x/RFM2x family can also be used. + + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// Si4432 has the following connections: +// nSEL pin: 10 +// nIRQ pin: 2 +// SDN pin: 9 +Si4432 radio = new Module(10, 2, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//Si4432 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize Si4432 with default settings + Serial.print(F("[Si4432] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + Serial.print(F("[Si4432] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 64 characters long + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); + + // you can also transmit byte array up to 64 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F(" success!")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F(" too long!")); + + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + // timeout occured while transmitting packet + Serial.println(F(" timeout!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino new file mode 100644 index 000000000..685574746 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -0,0 +1,125 @@ +/* + RadioLib Si443x Transmit with Interrupts Example + + This example transmits packets using Si4432 FSK radio module. + Each packet contains up to 64 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from Si443x/RFM2x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// Si4432 has the following connections: +// nSEL pin: 10 +// nIRQ pin: 2 +// SDN pin: 9 +Si4432 radio = new Module(10, 2, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//Si4432 radio = RadioShield.ModuleA; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +void setup() { + Serial.begin(9600); + + // initialize Si4432 with default settings + Serial.print(F("[Si4432] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when packet transmission is finished + radio.setPacketSentAction(setFlag); + + // start transmitting the first packet + Serial.print(F("[Si4432] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 64 characters long + transmissionState = radio.startTransmit("Hello World!"); + + // you can also transmit byte array up to 64 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.startTransmit(byteArr, 8); + */ +} + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[Si4432] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); + + // you can also transmit byte array up to 64 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + transmissionState = radio.startTransmit(byteArr, 8); + */ + } +} diff --git a/lib/lib_rf/RadioLib/examples/Stream/Stream_Receive/Stream_Receive.ino b/lib/lib_rf/RadioLib/examples/Stream/Stream_Receive/Stream_Receive.ino new file mode 100644 index 000000000..39fc1bb63 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Stream/Stream_Receive/Stream_Receive.ino @@ -0,0 +1,127 @@ +/* + RadioLib Stream Receive Example + + This example shows how to receive data in "Stream" mode. + In this mode, arbitrary length of data may be sent, up to + "infinite" continuous transmission between two devices. + + Caveats: + - CRC of the payload is not supported + - the length of the payload must be known in advance + + Modules that can be used for Stream are: + - SX127x/RFM9x (FSK mode only) + - RF69 + - SX1231 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for Stream transmit + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when receive buffer is full + radio.setFifoFullAction(fifoGet); + + // fixed packet length mode is required + radio.fixedPacketLengthMode(0); + + // start listening for packets + Serial.print(F("[SX1278] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); + // radio.scanChannel(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// how many bytes are there in total +const int totalLength = 512; + +// counter to keep track of how many bytes have been received so far +volatile int receivedLength = 0; + +// buffer to save the received data into +volatile uint8_t rxBuffer[totalLength + 1]; + +// this function is called when the radio receive buffer +// is full and ready to be read +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void fifoGet(void) { + // set the flag when we receive the full packet + receivedFlag = radio.fifoGet(rxBuffer, totalLength, &receivedLength); +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // packet was successfully received + Serial.println(F("[SX1278] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1278] Data:\t\t")); + Serial.println((char*)rxBuffer); + + // reset flag + receivedFlag = false; + receivedLength = 0; + + // put module back to listen mode + radio.startReceive(); + } +} diff --git a/lib/lib_rf/RadioLib/examples/Stream/Stream_Transmit/Stream_Transmit.ino b/lib/lib_rf/RadioLib/examples/Stream/Stream_Transmit/Stream_Transmit.ino new file mode 100644 index 000000000..4789a6ebe --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/Stream/Stream_Transmit/Stream_Transmit.ino @@ -0,0 +1,151 @@ +/* + RadioLib Stream Transmit Example + + This example shows how to transmit data in "Stream" mode. + In this mode, arbitrary length of data may be sent, up to + "infinite" continuous transmission between two devices. + + Caveats: + - CRC of the payload is not supported + - the length of the payload must be known in advance + + Modules that can be used for Stream are: + - SX127x/RFM9x (FSK mode only) + - RF69 + - SX1231 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +// this packet is much longer than would normally fit +// into SX1278's internal buffer +String longPacket = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\ + Maecenas at urna ut nunc imperdiet laoreet. Aliquam erat volutpat.\ + Etiam mattis mauris vitae posuere tincidunt. In sit amet bibendum nisl,\ + a ultrices lorem. Duis hendrerit ultricies condimentum. Phasellus eget nisi\ + eget massa aliquam bibendum. Pellentesque ante neque, aliquam non diam non,\ + fringilla facilisis ipsum. Morbi in molestie orci. Vestibulum luctus\ + venenatis arcu sit amet pellentesque. Nulla posuere sit amet turpis\ + id pharetra. Curabitur nec."; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for Stream transmit + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when transmit buffer is empty + radio.setFifoEmptyAction(fifoAdd); + + // fixed packet length mode is required + radio.fixedPacketLengthMode(0); + + // start transmitting the long packet + Serial.print(F("[SX1278] Sending a very long packet ... ")); + transmissionState = radio.startTransmit(longPacket); +} + +// flag to indicate we can keep adding more bytes to FIFO +volatile bool fifoEmpty = false; + +// flag to indicate that a packet was sent +bool transmittedFlag = false; + +// how many bytes are there in total +int totalLength = longPacket.length(); + +// counter to keep track of how many bytes still need to be sent +int remLength = totalLength; + +// this function is called when the radio transmit buffer +// is empty and ready to be refilled +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void fifoAdd(void) { + // we can send more bytes + fifoEmpty = true; +} + +void loop() { + if(fifoEmpty) { + // reset flag + fifoEmpty = false; + + // add more bytes to the transmit buffer + uint8_t* txBuffPtr = (uint8_t*)longPacket.c_str(); + transmittedFlag = radio.fifoAdd(txBuffPtr, totalLength, &remLength); + } + + // check if the previous transmission finished + if(transmittedFlag) { + // reset flag + transmittedFlag = false; + + // reset the counter + remLength = totalLength; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + // NOTE: when using interrupt-driven transmit method, + // it is not possible to automatically measure + // transmission data rate using getDataRate() + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // NOTE: in FSK mode, SX127x will not automatically + // turn transmitter off after sending a packet + // set mode to standby to ensure we don't jam others + radio.standby(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[SX1278] Sending another long packet ... ")); + transmissionState = radio.startTransmit(longPacket); + } +} diff --git a/lib/lib_rf/RadioLib/examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino b/lib/lib_rf/RadioLib/examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino new file mode 100644 index 000000000..6ae29bbaf --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino @@ -0,0 +1,100 @@ +/* + RadioLib nRF24 Blocking Receive Example + + This example listens for FSK transmissions using nRF24 2.4 GHz radio module. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - data rate + - transmit pipe on transmitter must match receive pipe on receiver + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// nRF24 has the following connections: +// CS pin: 10 +// IRQ pin: 2 +// CE pin: 3 +nRF24 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//nRF24 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize nRF24 with default settings + Serial.print(F("[nRF24] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // set receive pipe 0 address + // NOTE: address width in bytes MUST be equal to the + // width set in begin() or setAddressWidth() + // methods (5 by default) + Serial.print(F("[nRF24] Setting address for receive pipe 0 ... ")); + byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89}; + state = radio.setReceivePipe(0, addr); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[nRF24] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + // NOTE: receive() is a blocking method! + // See example ReceiveInterrupt for details + // on non-blocking reception method. + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[nRF24] Data:\t\t")); + Serial.println(str); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/lib/lib_rf/RadioLib/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino b/lib/lib_rf/RadioLib/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino new file mode 100644 index 000000000..1535bc661 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino @@ -0,0 +1,137 @@ +/* + RadioLib nRF24 Receive Example + + This example listens for FSK transmissions using nRF24 2.4 GHz radio module. + Once a packet is received, an interrupt is triggered. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - data rate + - transmit pipe on transmitter must match receive pipe + on receiver + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// nRF24 has the following connections: +// CS pin: 10 +// IRQ pin: 2 +// CE pin: 3 +nRF24 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//nRF24 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize nRF24 with default settings + Serial.print(F("[nRF24] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // set receive pipe 0 address + // NOTE: address width in bytes MUST be equal to the + // width set in begin() or setAddressWidth() + // methods (5 by default) + Serial.print(F("[nRF24] Setting address for receive pipe 0 ... ")); + byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89}; + state = radio.setReceivePipe(0, addr); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // set the function that will be called + // when new packet is received + radio.setPacketReceivedAction(setFlag); + + // start listening + Serial.print(F("[nRF24] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[nRF24] Received packet!")); + + // print data of the packet + Serial.print(F("[nRF24] Data:\t\t")); + Serial.println(str); + + } else { + // some other error occurred + Serial.print(F("[nRF24] Failed, code ")); + Serial.println(state); + + } + + // put module back to listen mode + radio.startReceive(); + } +} diff --git a/lib/lib_rf/RadioLib/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino b/lib/lib_rf/RadioLib/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino new file mode 100644 index 000000000..402a3cffc --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino @@ -0,0 +1,99 @@ +/* + RadioLib nRF24 Transmit Example + + This example transmits packets using nRF24 2.4 GHz radio module. + Each packet contains up to 32 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Packet delivery is automatically acknowledged by the receiver. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// nRF24 has the following connections: +// CS pin: 10 +// IRQ pin: 2 +// CE pin: 3 +nRF24 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//nRF24 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize nRF24 with default settings + Serial.print(F("[nRF24] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // set transmit address + // NOTE: address width in bytes MUST be equal to the + // width set in begin() or setAddressWidth() + // methods (5 by default) + byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89}; + Serial.print(F("[nRF24] Setting transmit pipe ... ")); + state = radio.setTransmitPipe(addr); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + Serial.print(F("[nRF24] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 32 characters long + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 32 bytes + Serial.println(F("too long!")); + + } else if (state == RADIOLIB_ERR_ACK_NOT_RECEIVED) { + // acknowledge from destination module + // was not received within 15 retries + Serial.println(F("ACK not received!")); + + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + // timed out while transmitting + Serial.println(F("timeout!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/lib/lib_rf/RadioLib/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/lib/lib_rf/RadioLib/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino new file mode 100644 index 000000000..55834b8d7 --- /dev/null +++ b/lib/lib_rf/RadioLib/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino @@ -0,0 +1,144 @@ +/* + RadioLib nRF24 Transmit with Interrupts Example + + This example transmits packets using nRF24 2.4 GHz radio module. + Each packet contains up to 32 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Packet delivery is automatically acknowledged by the receiver. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// nRF24 has the following connections: +// CS pin: 10 +// IRQ pin: 2 +// CE pin: 3 +nRF24 radio = new Module(10, 2, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//nRF24 radio = RadioShield.ModuleA; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +void setup() { + Serial.begin(9600); + + // initialize nRF24 with default settings + Serial.print(F("[nRF24] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // set transmit address + // NOTE: address width in bytes MUST be equal to the + // width set in begin() or setAddressWidth() + // methods (5 by default) + byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89}; + Serial.print(F("[nRF24] Setting transmit pipe ... ")); + state = radio.setTransmitPipe(addr); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // set the function that will be called + // when packet transmission is finished + radio.setPacketSentAction(setFlag); + + // start transmitting the first packet + Serial.print(F("[nRF24] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + transmissionState = radio.startTransmit("Hello World!"); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.startTransmit(byteArr, 8); + */ +} + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + // NOTE: when using interrupt-driven transmit method, + // it is not possible to automatically measure + // transmission data rate using getDataRate() + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[nRF24] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 32 characters long + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.startTransmit(byteArr, 8); + */ + } +} diff --git a/lib/lib_rf/RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py b/lib/lib_rf/RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py new file mode 100644 index 000000000..435a27a81 --- /dev/null +++ b/lib/lib_rf/RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py @@ -0,0 +1,176 @@ +#!/usr/bin/python3 +# -*- encoding: utf-8 -*- + +import argparse +import serial +import sys +import numpy as np +import matplotlib as mpl +import matplotlib.pyplot as plt + +from datetime import datetime +from argparse import RawTextHelpFormatter + +# number of samples in each scanline +SCAN_WIDTH = 33 + +# scanline Serial start/end markers +SCAN_MARK_START = 'SCAN ' +SCAN_MARK_FREQ = 'FREQ ' +SCAN_MARK_END = ' END' + +# output path +OUT_PATH = 'out' + +# default settings +DEFAULT_BAUDRATE = 115200 +DEFAULT_COLOR_MAP = 'viridis' +DEFAULT_SCAN_LEN = 200 +DEFAULT_RSSI_OFFSET = -11 + +# Print iterations progress +# from https://stackoverflow.com/questions/3173320/text-progress-bar-in-terminal-with-block-characters +def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 50, fill = '█', printEnd = "\r"): + """ + Call in a loop to create terminal progress bar + @params: + iteration - Required : current iteration (Int) + total - Required : total iterations (Int) + prefix - Optional : prefix string (Str) + suffix - Optional : suffix string (Str) + decimals - Optional : positive number of decimals in percent complete (Int) + length - Optional : character length of bar (Int) + fill - Optional : bar fill character (Str) + printEnd - Optional : end character (e.g. "\r", "\r\n") (Str) + """ + percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) + filledLength = int(length * iteration // total) + bar = fill * filledLength + '-' * (length - filledLength) + print(f'\r{prefix} |{bar}| {percent}% {suffix}', end = printEnd) + if iteration == total: + print() + + +def main(): + parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description=''' + RadioLib SX126x_Spectrum_Scan plotter script. Displays output from SX126x_Spectrum_Scan example + as grayscale and + + Depends on pyserial and matplotlib, install by: + 'python3 -m pip install pyserial matplotlib' + + Step-by-step guide on how to use the script: + 1. Upload the SX126x_Spectrum_Scan example to your Arduino board with SX1262 connected. + 2. Run the script with appropriate arguments. + 3. Once the scan is complete, output files will be saved to out/ + ''') + parser.add_argument('port', + type=str, + help='COM port to connect to the device') + parser.add_argument('--speed', + default=DEFAULT_BAUDRATE, + type=int, + help=f'COM port baudrate (defaults to {DEFAULT_BAUDRATE})') + parser.add_argument('--map', + default=DEFAULT_COLOR_MAP, + type=str, + help=f'Matplotlib color map to use for the output (defaults to "{DEFAULT_COLOR_MAP}")') + parser.add_argument('--len', + default=DEFAULT_SCAN_LEN, + type=int, + help=f'Number of scanlines to record (defaults to {DEFAULT_SCAN_LEN})') + parser.add_argument('--offset', + default=DEFAULT_RSSI_OFFSET, + type=int, + help=f'Default RSSI offset in dBm (defaults to {DEFAULT_RSSI_OFFSET})') + parser.add_argument('--freq', + default=-1, + type=float, + help=f'Default starting frequency in MHz') + args = parser.parse_args() + + freq_mode = False + scan_len = args.len + if (args.freq != -1): + freq_mode = True + scan_len = 1000 + + # create the color map and the result array + arr = np.zeros((SCAN_WIDTH, scan_len)) + + # scanline counter + row = 0 + + # list of frequencies in frequency mode + freq_list = [] + + # open the COM port + with serial.Serial(args.port, args.speed, timeout=None) as com: + while(True): + # update the progress bar + if not freq_mode: + printProgressBar(row, scan_len) + + # read a single line + try: + line = com.readline().decode('utf-8') + except: + continue + + if SCAN_MARK_FREQ in line: + new_freq = float(line.split(' ')[1]) + if (len(freq_list) > 1) and (new_freq < freq_list[-1]): + break + + freq_list.append(new_freq) + print('{:.3f}'.format(new_freq), end = '\r') + continue + + # check the markers + if (SCAN_MARK_START in line) and (SCAN_MARK_END in line): + # get the values + scanline = line[len(SCAN_MARK_START):-len(SCAN_MARK_END)].split(',') + for col in range(SCAN_WIDTH): + arr[col][row] = int(scanline[col]) + + # increment the row counter + row = row + 1 + + # check if we're done + if (not freq_mode) and (row >= scan_len): + break + + # scale to the number of scans (sum of any given scanline) + num_samples = arr.sum(axis=0)[0] + arr *= (num_samples/arr.max()) + + if freq_mode: + scan_len = len(freq_list) + + # create the figure + fig, ax = plt.subplots() + + # display the result as heatmap + extent = [0, scan_len, -4*(SCAN_WIDTH + 1), args.offset] + if freq_mode: + extent[0] = freq_list[0] + extent[1] = freq_list[-1] + im = ax.imshow(arr[:,:scan_len], cmap=args.map, extent=extent) + fig.colorbar(im) + + # set some properites and show + timestamp = datetime.now().strftime('%y-%m-%d %H-%M-%S') + title = f'RadioLib SX126x Spectral Scan {timestamp}' + if freq_mode: + plt.xlabel("Frequency [Hz]") + else: + plt.xlabel("Time [sample]") + plt.ylabel("RSSI [dBm]") + ax.set_aspect('auto') + fig.suptitle(title) + fig.canvas.manager.set_window_title(title) + plt.savefig(f'{OUT_PATH}/{title.replace(" ", "_")}.png', dpi=300) + plt.show() + +if __name__ == "__main__": + main() diff --git a/lib/lib_rf/RadioLib/extras/decoder/DebugDecoder.py b/lib/lib_rf/RadioLib/extras/decoder/DebugDecoder.py new file mode 100644 index 000000000..c5c9b3713 --- /dev/null +++ b/lib/lib_rf/RadioLib/extras/decoder/DebugDecoder.py @@ -0,0 +1,111 @@ +import re, sys, argparse +from pathlib import Path +from argparse import RawTextHelpFormatter + + +''' +TODO list: + 1. Parse macro values (the names of bits in all registers in header file) + 2. Failed SPI write handling + 3. SX126x/SX128x handling +''' + + +def get_macro_name(value, macros): + for macro in macros: + if macro[1] == value: + return macro[0] + return 'UNKNOWN_VALUE' + + +def get_macro_value(value): + return ' 0x{0:02X}\n'.format(int(value, 16)) + + +parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description=''' + RadioLib debug output decoder script. Turns RadioLib Serial dumps into readable text. + + Step-by-step guid on how to use the decoder: + 1. Uncomment lines 312 (#define RADIOLIB_DEBUG) and 313 (#define RADIOLIB_VERBOSE) in RadioLib/src/BuildOpt.h + 2. Recompile and upload the failing Arduino sketch + 3. Open Arduino IDE Serial Monitor and enable timestamps + 4. Copy the Serial output and save it into a .txt file + 5. Run this script + + Output will be saved in the file specified by --out and printed to the terminal +''') +parser.add_argument('file', metavar='file', type=str, help='Text file of the debug output') +parser.add_argument('--out', metavar='out', default='./out.txt', type=str, help='Where to save the decoded file (defaults to ./out.txt)') +args = parser.parse_args() + +# open the log file +log = open(args.file, 'r').readlines() + +# find modules that are in use +used_modules = [] +pattern_module = re.compile('(([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?.[0-9]{3} -> )?M\t') +for entry in log: + m = pattern_module.search(entry) + if m != None: + used_modules.append(entry[m.end():].rstrip()) + +# get paths to all relevant header files +header_files = [] +for path in Path('../../src').rglob('*.h'): + for module in used_modules: + if module in path.name: + header_files.append(path) + +# extract names of address macros from the header files +macro_addresses = [] +pattern_define = re.compile('#define \w* +\w*(\n| +\/\/){1}') +for path in header_files: + file = open(path, 'r').readlines() + for line in file: + m = pattern_define.search(line) + if m != None: + s = re.split(' +', m.group().rstrip()) + if (s.__len__() > 1) and ('_REG' in s[1]): + macro_addresses.append([s[1], int(s[2], 0)]) + +''' +# extract names of value macros for each adddress macro +macro_values = [] +for path in header_files: + file = open(path, 'r').readlines() + for line in file: + for module in used_modules: + pattern_addr_macro = re.compile('\/\/ SI443X_REG_\w+'.format(module.capitalize())) +''' + +# parse every line in the log file +out = [] +pattern_debug = re.compile('(([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?.[0-9]{3} -> )?[RWM]\t.+') +for entry in log: + m = pattern_debug.search(entry) + if m != None: + s = re.split('( |\t)+', entry.rstrip()) + cmd_len = int((s.__len__() - 7)/2) + new_entry = s[0] + s[1] + s[2] + s[3] + if s[4] == 'W': + macro_address = int(s[6], 16) + new_entry += 'write {0:>2} 0x{1:02X} {2}\n'.format(cmd_len, macro_address, get_macro_name(macro_address, macro_addresses)) + for i in range(cmd_len): + new_entry += get_macro_value(s[8 + 2*i]); + elif s[4] == 'R': + macro_address = int(s[6], 16) + new_entry += 'read {0:>2} 0x{1:02X} {2}\n'.format(cmd_len, macro_address, get_macro_name(macro_address, macro_addresses)) + for i in range(cmd_len): + new_entry += get_macro_value(s[8 + 2*i]); + elif s[4] == 'M': + new_entry += 'module {}\n'.format(s[6]) + out.append(new_entry) + else: + out.append(entry) + +# write the output file +out_file = open(args.out, 'w') +for line in out: + print(line, end='') + out_file.write(line) +out_file.close() diff --git a/lib/lib_rf/RadioLib/extras/template/ModuleTemplate.cpp b/lib/lib_rf/RadioLib/extras/template/ModuleTemplate.cpp new file mode 100644 index 000000000..1efb1fc06 --- /dev/null +++ b/lib/lib_rf/RadioLib/extras/template/ModuleTemplate.cpp @@ -0,0 +1,22 @@ +#include ".h" +#if !defined(RADIOLIB_EXCLUDE_) + +::(Module* mod) { + /* + Constructor implementation MUST assign the provided "mod" pointer to the private "_mod" pointer. + */ + _mod = mod; +} + +int16_t ::begin() { + /* + "begin" method implementation MUST call the "init" method with appropriate settings. + */ + _mod->init(); + + /* + "begin" method SHOULD implement some sort of mechanism to verify the connection between Arduino and the module. + + For example, reading a version register + */ +} diff --git a/lib/lib_rf/RadioLib/extras/template/ModuleTemplate.h b/lib/lib_rf/RadioLib/extras/template/ModuleTemplate.h new file mode 100644 index 000000000..ee121942f --- /dev/null +++ b/lib/lib_rf/RadioLib/extras/template/ModuleTemplate.h @@ -0,0 +1,99 @@ +/* + RadioLib Module Template header file + + Before opening pull request, please make sure that: + 1. All files MUST be compiled without errors using default Arduino IDE settings. + 2. All files SHOULD be compiled without warnings with compiler warnings set to "All". + 3. Example sketches MUST be working correctly and MUST be stable enough to run for prolonged periods of time. + 4. Writing style SHOULD be consistent. + 5. Comments SHOULD be in place for the most important chunks of code and SHOULD be free of typos. + 6. To indent, 2 spaces MUST be used. + + If at any point you are unsure about the required style, please refer to the rest of the modules. +*/ + +#if !defined(_RADIOLIB__H) && !defined(RADIOLIB_EXCLUDE_) +#if !defined(_RADIOLIB__H) +#define _RADIOLIB__H + +/* + Header file for each module MUST include Module.h and TypeDef.h in the src folder. + The header file MAY include additional header files. +*/ +#include "../../Module.h" +#include "../../TypeDef.h" + +/* + Only use the following include if the module implements methods for OSI physical layer control. + This concerns only modules similar to SX127x/RF69/CC1101 etc. + + In this case, your class MUST implement all virtual methods of PhysicalLayer class. +*/ +//#include "../../protocols/PhysicalLayer/PhysicalLayer.h" + +/* + Register map + Definition of SPI register map SHOULD be placed here. The register map SHOULD have two parts: + + 1 - Address map: only defines register names and addresses. Register names MUST match names in + official documentation (datasheets etc.). + 2 - Variable map: defines variables inside register. This functions as a bit range map for a specific register. + Bit range (MSB and LSB) as well as short description for each variable MUST be provided in a comment. + + See RF69 and SX127x header files for examples of register maps. +*/ +// register map | spaces up to this point +#define RADIOLIB__REG_ 0x00 + +// _REG_ MSB LSB DESCRIPTION +#define RADIOLIB__ 0b00000000 // 7 0 + + +/* + Module class definition + + The module class MAY inherit from the following classes: + + 1 - PhysicalLayer: In case the module implements methods for OSI physical layer control (e.g. SX127x). + 2 - Common class: In case the module further specifies some more generic class (e.g. SX127x/SX1278) +*/ +class { + public: + /* + Constructor MUST have only one parameter "Module* mod". + The class MAY implement additional overloaded constructors. + */ + // constructor + (Module* mod); + + /* + The class MUST implement at least one basic method called "begin". + The "begin" method MUST initialize the module and return the status as int16_t type. + */ + // basic methods + int16_t begin(); + + /* + The class MAY implement additional methods. + All implemented methods SHOULD return the status as int16_t type. + */ + +#if !defined(RADIOLIB_GODMODE) + private: +#endif + /* + The class MUST contain private member "Module* _mod" + */ + Module* _mod; + + /* + The class MAY contain additional private variables and/or methods. + Private member variables MUST have a name prefixed with "_" (underscore, ASCII 0x5F) + + Usually, these are variables for saving module configuration, or methods that do not have to be exposed to the end user. + */ +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/extras/test/SX126x/.gitignore b/lib/lib_rf/RadioLib/extras/test/SX126x/.gitignore new file mode 100644 index 000000000..567609b12 --- /dev/null +++ b/lib/lib_rf/RadioLib/extras/test/SX126x/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/lib/lib_rf/RadioLib/extras/test/SX126x/CMakeLists.txt b/lib/lib_rf/RadioLib/extras/test/SX126x/CMakeLists.txt new file mode 100644 index 000000000..e708c0a3a --- /dev/null +++ b/lib/lib_rf/RadioLib/extras/test/SX126x/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.18) + +# create the project +project(rpi-sx1261) + +# when using debuggers such as gdb, the following line can be used +#set(CMAKE_BUILD_TYPE Debug) + +# if you did not build RadioLib as shared library (see README), +# you will have to add it as source directory +# the following is just an example, yours will likely be different +#add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") + +# add the executable +add_executable(${PROJECT_NAME} main.cpp) + +# link both libraries +target_link_libraries(${PROJECT_NAME} RadioLib pigpio) + +# you can also specify RadioLib compile-time flags here +#target_compile_definitions(${PROJECT_NAME} PUBLIC RADIOLIB_DEBUG RADIOLIB_VERBOSE) diff --git a/lib/lib_rf/RadioLib/extras/test/SX126x/PiHal.h b/lib/lib_rf/RadioLib/extras/test/SX126x/PiHal.h new file mode 100644 index 000000000..9bf4f8f18 --- /dev/null +++ b/lib/lib_rf/RadioLib/extras/test/SX126x/PiHal.h @@ -0,0 +1,151 @@ +#ifndef PI_HAL_H +#define PI_HAL_H + +// include RadioLib +#include + +// include the library for Raspberry GPIO pins +#include "pigpio.h" + +// create a new Raspberry Pi hardware abstraction layer +// using the pigpio library +// the HAL must inherit from the base RadioLibHal class +// and implement all of its virtual methods +class PiHal : public RadioLibHal { + public: + // default constructor - initializes the base HAL and any needed private members + PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000) + : RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE), + _spiChannel(spiChannel), + _spiSpeed(spiSpeed) { + } + + void init() override { + // first initialise pigpio library + gpioInitialise(); + + // now the SPI + spiBegin(); + + // Waveshare LoRaWAN Hat also needs pin 18 to be pulled high to enable the radio + gpioSetMode(18, PI_OUTPUT); + gpioWrite(18, PI_HIGH); + } + + void term() override { + // stop the SPI + spiEnd(); + + // pull the enable pin low + gpioSetMode(18, PI_OUTPUT); + gpioWrite(18, PI_LOW); + + // finally, stop the pigpio library + gpioTerminate(); + } + + // GPIO-related methods (pinMode, digitalWrite etc.) should check + // RADIOLIB_NC as an alias for non-connected pins + void pinMode(uint32_t pin, uint32_t mode) override { + if(pin == RADIOLIB_NC) { + return; + } + + gpioSetMode(pin, mode); + } + + void digitalWrite(uint32_t pin, uint32_t value) override { + if(pin == RADIOLIB_NC) { + return; + } + + gpioWrite(pin, value); + } + + uint32_t digitalRead(uint32_t pin) override { + if(pin == RADIOLIB_NC) { + return(0); + } + + return(gpioRead(pin)); + } + + void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override { + if(interruptNum == RADIOLIB_NC) { + return; + } + + gpioSetISRFunc(interruptNum, mode, 0, (gpioISRFunc_t)interruptCb); + } + + void detachInterrupt(uint32_t interruptNum) override { + if(interruptNum == RADIOLIB_NC) { + return; + } + + gpioSetISRFunc(interruptNum, 0, 0, NULL); + } + + void delay(unsigned long ms) override { + gpioDelay(ms * 1000); + } + + void delayMicroseconds(unsigned long us) override { + gpioDelay(us); + } + + unsigned long millis() override { + return(gpioTick() / 1000); + } + + unsigned long micros() override { + return(gpioTick()); + } + + long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { + if(pin == RADIOLIB_NC) { + return(0); + } + + this->pinMode(pin, PI_INPUT); + uint32_t start = this->micros(); + uint32_t curtick = this->micros(); + + while(this->digitalRead(pin) == state) { + if((this->micros() - curtick) > timeout) { + return(0); + } + } + + return(this->micros() - start); + } + + void spiBegin() { + if(_spiHandle < 0) { + _spiHandle = spiOpen(_spiChannel, _spiSpeed, 0); + } + } + + void spiBeginTransaction() {} + + void spiTransfer(uint8_t* out, size_t len, uint8_t* in) { + spiXfer(_spiHandle, (char*)out, (char*)in, len); + } + + void spiEndTransaction() {} + + void spiEnd() { + if(_spiHandle >= 0) { + spiClose(_spiHandle); + _spiHandle = -1; + } + } + + private: + // the HAL can contain any additional private members + const unsigned int _spiSpeed; + const uint8_t _spiChannel; + int _spiHandle = -1; +}; + +#endif diff --git a/lib/lib_rf/RadioLib/extras/test/SX126x/build.sh b/lib/lib_rf/RadioLib/extras/test/SX126x/build.sh new file mode 100644 index 000000000..a46bbdf4f --- /dev/null +++ b/lib/lib_rf/RadioLib/extras/test/SX126x/build.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -e +mkdir -p build +cd build +cmake -G "CodeBlocks - Unix Makefiles" .. +make -j4 +cd .. diff --git a/lib/lib_rf/RadioLib/extras/test/SX126x/clean.sh b/lib/lib_rf/RadioLib/extras/test/SX126x/clean.sh new file mode 100644 index 000000000..27cfe2641 --- /dev/null +++ b/lib/lib_rf/RadioLib/extras/test/SX126x/clean.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +rm -rf ./build diff --git a/lib/lib_rf/RadioLib/extras/test/SX126x/main.cpp b/lib/lib_rf/RadioLib/extras/test/SX126x/main.cpp new file mode 100644 index 000000000..4b88d4438 --- /dev/null +++ b/lib/lib_rf/RadioLib/extras/test/SX126x/main.cpp @@ -0,0 +1,26 @@ +// this is an autotest file for the SX126x +// runs on Raspberry Pi with Waveshare LoRaWAN hat + +#include +#include "PiHal.h" + +#define RADIOLIB_TEST_ASSERT(STATEVAR) { if((STATEVAR) != RADIOLIB_ERR_NONE) { return(-1*(STATEVAR)); } } + +PiHal* hal = new PiHal(1); +SX1261 radio = new Module(hal, 7, 17, 22, RADIOLIB_NC); + +// the entry point for the program +int main(int argc, char** argv) { + int state = RADIOLIB_ERR_UNKNOWN; + + state = radio.begin(); + printf("[SX1261] Test:begin() = %d\n", state); + RADIOLIB_TEST_ASSERT(state); + + state = radio.transmit("Hello World!"); + printf("[SX1261] Test:transmit() = %d\n", state); + RADIOLIB_TEST_ASSERT(state); + + hal->term(); + return(0); +} diff --git a/lib/lib_rf/RadioLib/idf_component.yml b/lib/lib_rf/RadioLib/idf_component.yml new file mode 100644 index 000000000..09f82ad98 --- /dev/null +++ b/lib/lib_rf/RadioLib/idf_component.yml @@ -0,0 +1,11 @@ +version: "6.4.2" +description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." +tags: "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan" +url: "https://github.com/jgromes/RadioLib" +repository: "https://github.com/jgromes/RadioLib.git" +license: "MIT" +dependencies: + # Required IDF version + idf: ">=4.1" +maintainers: + "Jan Gromeš " diff --git a/lib/lib_rf/RadioLib/keywords.txt b/lib/lib_rf/RadioLib/keywords.txt new file mode 100644 index 000000000..48efe6325 --- /dev/null +++ b/lib/lib_rf/RadioLib/keywords.txt @@ -0,0 +1,439 @@ +####################################### +# Syntax Coloring Map For RadioLib +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +RadioLib KEYWORD1 +RadioShield KEYWORD1 +Module KEYWORD1 +RadioLibHal KEYWORD1 +ArduinoHal KEYWORD1 + +# modules +CC1101 KEYWORD1 +LLCC68 KEYWORD1 +nRF24 KEYWORD1 +RF69 KEYWORD1 +RFM22 KEYWORD1 +RFM23 KEYWORD1 +RFM95 KEYWORD1 +RFM96 KEYWORD1 +RFM97 KEYWORD1 +RFM98 KEYWORD1 +Si4430 KEYWORD1 +Si4431 KEYWORD1 +Si4432 KEYWORD1 +SIM800 KEYWORD1 +SX1231 KEYWORD1 +SX1233 KEYWORD1 +SX1261 KEYWORD1 +SX1262 KEYWORD1 +SX1268 KEYWORD1 +SX1272 KEYWORD1 +SX1273 KEYWORD1 +SX1276 KEYWORD1 +SX1277 KEYWORD1 +SX1278 KEYWORD1 +SX1279 KEYWORD1 +SX1280 KEYWORD1 +SX1281 KEYWORD1 +SX1282 KEYWORD1 +STM32WLx KEYWORD1 +STM32WLx_Module KEYWORD1 + +# protocols +RTTYClient KEYWORD1 +MorseClient KEYWORD1 +AX25Client KEYWORD1 +AX25Frame KEYWORD1 +SSTVClient KEYWORD1 +HellClient KEYWORD1 +AFSKClient KEYWORD1 +FSK4Client KEYWORD1 +APRSClient KEYWORD1 +PagerClient KEYWORD1 +ExternalRadio KEYWORD1 +BellClient KEYWORD1 +LoRaWANNode KEYWORD1 +LoRaWANBand_t KEYWORD1 +LoRaWANEvent_t KEYWORD1 + +# SSTV modes +Scottie1 KEYWORD1 +Scottie2 KEYWORD1 +ScottieDX KEYWORD1 +Martin1 KEYWORD1 +Martin2 KEYWORD1 +Wrasse KEYWORD1 +PasokonP3 KEYWORD1 +PasokonP5 KEYWORD1 +PasokonP7 KEYWORD1 + +# Bell Modems +Bell101 KEYWORD1 +Bell103 KEYWORD1 +Bell202 KEYWORD1 + +# LoRaWAN bands +EU868 KEYWORD1 +US915 KEYWORD1 +CN780 KEYWORD1 +EU433 KEYWORD1 +AU915 KEYWORD1 +CN500 KEYWORD1 +AS923 KEYWORD1 +KR920 KEYWORD1 +IN865 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +# RadioLib +ModuleA KEYWORD2 +ModuleB KEYWORD2 +setRfSwitchTable KEYWORD2 + +# SX127x/RFM9x + RF69 + CC1101 +begin KEYWORD2 +beginFSK KEYWORD2 +transmit KEYWORD2 +receive KEYWORD2 +scanChannel KEYWORD2 +sleep KEYWORD2 +standby KEYWORD2 +transmitDirect KEYWORD2 +receiveDirect KEYWORD2 +packetMode KEYWORD2 +setDio0Action KEYWORD2 +setDio1Action KEYWORD2 +clearDio0Action KEYWORD2 +clearDio1Action KEYWORD2 +startTransmit KEYWORD2 +finishTransmit KEYWORD2 +startReceive KEYWORD2 +readData KEYWORD2 +startChannelScan KEYWORD2 +getChannelScanResult KEYWORD2 +setBandwidth KEYWORD2 +setSpreadingFactor KEYWORD2 +setCodingRate KEYWORD2 +setFrequency KEYWORD2 +setSyncWord KEYWORD2 +setOutputPower KEYWORD2 +setCurrentLimit KEYWORD2 +setPreambleLength KEYWORD2 +setGain KEYWORD2 +getFrequencyError KEYWORD2 +getRSSI KEYWORD2 +getAFCError KEYWORD2 +getSNR KEYWORD2 +getDataRate KEYWORD2 +setBitRate KEYWORD2 +setRxBandwidth KEYWORD2 +setAFCBandwidth KEYWORD2 +setAFC KEYWORD2 +setAFCAGCTrigger KEYWORD2 +setFrequencyDeviation KEYWORD2 +setNodeAddress KEYWORD2 +setBroadcastAddress KEYWORD2 +disableAddressFiltering KEYWORD2 +setDataShaping KEYWORD2 +setOOK KEYWORD2 +setDataShapingOOK KEYWORD2 +setCRC KEYWORD2 +variablePacketLengthMode KEYWORD2 +fixedPacketLengthMode KEYWORD2 +setCrcFiltering KEYWORD2 +enableSyncWordFiltering KEYWORD2 +disableSyncWordFiltering KEYWORD2 +setPromiscuous KEYWORD2 +setRSSIConfig KEYWORD2 +setEncoding KEYWORD2 +getIRQFlags KEYWORD2 +getModemStatus KEYWORD2 +getTempRaw KEYWORD2 +setRfSwitchPins KEYWORD2 +forceLDRO KEYWORD2 +autoLDRO KEYWORD2 +getChipVersion KEYWORD2 +invertIQ KEYWORD2 +setOokThresholdType KEYWORD2 +setOokPeakThresholdDecrement KEYWORD2 +setOokFixedOrFloorThreshold KEYWORD2 +setOokPeakThresholdStep KEYWORD2 +setDirectSyncWord KEYWORD2 +setDirectAction KEYWORD2 +readBit KEYWORD2 +enableBitSync KEYWORD2 +disableBitSync KEYWORD2 +setFHSSHoppingPeriod KEYWORD2 +getFHSSHoppingPeriod KEYWORD2 +getFHSSChannel KEYWORD2 +clearFHSSInt KEYWORD2 +randomByte KEYWORD2 +getPacketLength KEYWORD2 +setFifoEmptyAction KEYWORD2 +clearFifoEmptyAction KEYWORD2 +setFifoFullAction KEYWORD2 +clearFifoFullAction KEYWORD2 +fifoAdd KEYWORD2 +fifoGet KEYWORD2 +setLowBatteryThreshold KEYWORD2 + +# RF69-specific +setAESKey KEYWORD2 +enableAES KEYWORD2 +disableAES KEYWORD2 +getTemperature KEYWORD2 +setAmbientTemperature KEYWORD2 +setLnaTestBoost KEYWORD2 +setOokFixedThreshold KEYWORD2 +enableContinuousModeBitSync KEYWORD2 +disableContinuousModeBitSync KEYWORD2 + +# CC1101-specific +getLQI KEYWORD2 +setGdo0Action KEYWORD2 +setGdo2Action KEYWORD2 +clearGdo0Action KEYWORD2 +clearGdo2Action KEYWORD2 +setCrcFiltering KEYWORD2 + +# SX126x-specific +setTCXO KEYWORD2 +setDio2AsRfSwitch KEYWORD2 +getTimeOnAir KEYWORD2 +implicitHeader KEYWORD2 +explicitHeader KEYWORD2 +setSyncBits KEYWORD2 +setWhitening KEYWORD2 +startReceiveDutyCycle KEYWORD2 +startReceiveDutyCycleAuto KEYWORD2 +setRegulatorLDO KEYWORD2 +setRegulatorDCDC KEYWORD2 +getCurrentLimit KEYWORD2 +getIrqStatus KEYWORD2 +getLastError KEYWORD2 +setRxBoostedGainMode KEYWORD2 +uploadPatch KEYWORD2 +spectralScanStart KEYWORD2 +spectralScanAbort KEYWORD2 +spectralScanGetStatus KEYWORD2 +spectralScanGetResult KEYWORD2 + +# nRF24 +setIrqAction KEYWORD2 +setAddressWidth KEYWORD2 +setTransmitPipe KEYWORD2 +setReceivePipe KEYWORD2 +disablePipe KEYWORD2 +getStatus KEYWORD2 +setAutoAck KEYWORD2 + +# RTTY +idle KEYWORD2 +byteArr KEYWORD2 + +# Morse +startSignal KEYWORD2 + +# AX.25 +setRepeaters KEYWORD2 +setRecvSequence KEYWORD2 +setSendSequence KEYWORD2 +sendFrame KEYWORD2 +setCorrection KEYWORD2 + +# SSTV +sendHeader KEYWORD2 +sendLine KEYWORD2 +getPictureHeight KEYWORD2 + +# SX128x +beginGFSK KEYWORD2 +beginFLRC KEYWORD2 +beginBLE KEYWORD2 +setAccessAddress KEYWORD2 +range KEYWORD2 +startRanging KEYWORD2 +getRangingResult KEYWORD2 + +# Hellschreiber +printGlyph KEYWORD2 +setInversion KEYWORD2 + +# AFSK +tone KEYWORD2 +noTone KEYWORD2 + +# APRS +sendPosition KEYWORD2 +sendMicE KEYWORD2 + +# Pager +sendTone KEYWORD2 + +# PhysicalLayer +dropSync KEYWORD2 +setTimerFlag KEYWORD2 +setInterruptSetup KEYWORD2 +setPacketReceivedAction KEYWORD2 +clearPacketReceivedAction KEYWORD2 +setPacketSentAction KEYWORD2 +clearPacketSentAction KEYWORD2 +setDataRate KEYWORD2 +checkDataRate KEYWORD2 + +# BellModem +setModem KEYWORD2 + +# LoRaWAN +wipe KEYWORD2 +getBufferNonces KEYWORD2 +setBufferNonces KEYWORD2 +getBufferSession KEYWORD2 +setBufferSession KEYWORD2 +restore KEYWORD2 +beginOTAA KEYWORD2 +beginABP KEYWORD2 +isJoined KEYWORD2 +saveSession KEYWORD2 +sendMacCommandReq KEYWORD2 +uplink KEYWORD2 +downlink KEYWORD2 +sendReceive KEYWORD2 +setDeviceStatus KEYWORD2 +getFcntUp KEYWORD2 +getNFcntDown KEYWORD2 +getAFcntDown KEYWORD2 +resetFcntDown KEYWORD2 +setDatarate KEYWORD2 +setADR KEYWORD2 +setDutyCycle KEYWORD2 +dutyCycleInterval KEYWORD2 +timeUntilUplink KEYWORD2 +setDwellTime KEYWORD2 +maxPayloadDwellTime KEYWORD2 +setTxPower KEYWORD2 +setCSMA KEYWORD2 +getMacLinkCheckAns KEYWORD2 +getMacDeviceTimeAns KEYWORD2 +getDevAddr KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +RADIOLIB_NC LITERAL1 +RADIOLIB_VERSION LITERAL1 +RADIOLIB_PIN_TYPE LITERAL1 + +RADIOLIB_SHAPING_NONE LITERAL1 +RADIOLIB_SHAPING_0_3 LITERAL1 +RADIOLIB_SHAPING_0_5 LITERAL1 +RADIOLIB_SHAPING_0_7 LITERAL1 +RADIOLIB_SHAPING_1_0 LITERAL1 + +RADIOLIB_ENCODING_NRZ LITERAL1 +RADIOLIB_ENCODING_MANCHESTER LITERAL1 +RADIOLIB_ENCODING_WHITENING LITERAL1 + +RADIOLIB_BUILTIN_MODULE LITERAL1 + +RADIOLIB_MORSE_INTER_SYMBOL LITERAL1 +RADIOLIB_MORSE_CHAR_COMPLETE LITERAL1 +RADIOLIB_MORSE_WORD_COMPLETE LITERAL1 + +RADIOLIB_ERR_NONE LITERAL1 +RADIOLIB_ERR_UNKNOWN LITERAL1 + +RADIOLIB_ERR_CHIP_NOT_FOUND LITERAL1 +RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED LITERAL1 +RADIOLIB_ERR_PACKET_TOO_LONG LITERAL1 +RADIOLIB_ERR_TX_TIMEOUT LITERAL1 +RADIOLIB_ERR_RX_TIMEOUT LITERAL1 +RADIOLIB_ERR_CRC_MISMATCH LITERAL1 +RADIOLIB_ERR_INVALID_BANDWIDTH LITERAL1 +RADIOLIB_ERR_INVALID_SPREADING_FACTOR LITERAL1 +RADIOLIB_ERR_INVALID_CODING_RATE LITERAL1 +RADIOLIB_ERR_INVALID_BIT_RANGE LITERAL1 +RADIOLIB_ERR_INVALID_FREQUENCY LITERAL1 +RADIOLIB_ERR_INVALID_OUTPUT_POWER LITERAL1 +RADIOLIB_PREAMBLE_DETECTED LITERAL1 +RADIOLIB_CHANNEL_FREE LITERAL1 +RADIOLIB_ERR_SPI_WRITE_FAILED LITERAL1 +RADIOLIB_ERR_INVALID_CURRENT_LIMIT LITERAL1 +RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH LITERAL1 +RADIOLIB_ERR_INVALID_GAIN LITERAL1 +RADIOLIB_ERR_WRONG_MODEM LITERAL1 +RADIOLIB_ERR_INVALID_NUM_SAMPLES LITERAL1 +RADIOLIB_ERR_INVALID_RSSI_OFFSET LITERAL1 +RADIOLIB_ERR_INVALID_ENCODING LITERAL1 + +RADIOLIB_ERR_INVALID_BIT_RATE LITERAL1 +RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION LITERAL1 +RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO LITERAL1 +RADIOLIB_ERR_INVALID_RX_BANDWIDTH LITERAL1 +RADIOLIB_ERR_INVALID_SYNC_WORD LITERAL1 +RADIOLIB_ERR_INVALID_DATA_SHAPING LITERAL1 +RADIOLIB_ERR_INVALID_MODULATION LITERAL1 +RADIOLIB_ERR_INVALID_OOK_RSSI_PEAK_TYPE LITERAL1 + +RADIOLIB_ERR_INVALID_SYMBOL LITERAL1 +RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY LITERAL1 +RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY_LENGTH LITERAL1 +RADIOLIB_ERR_MIC_E_TELEMETRY_STATUS LITERAL1 + +RADIOLIB_ASCII LITERAL1 +RADIOLIB_ASCII_EXTENDED LITERAL1 +RADIOLIB_ITA2 LITERAL1 +RADIOLIB_ERR_INVALID_RTTY_SHIFT LITERAL1 +RADIOLIB_ERR_UNSUPPORTED_ENCODING LITERAL1 + +RADIOLIB_ERR_INVALID_DATA_RATE LITERAL1 +RADIOLIB_ERR_INVALID_ADDRESS_WIDTH LITERAL1 +RADIOLIB_ERR_INVALID_PIPE_NUMBER LITERAL1 +RADIOLIB_ERR_ACK_NOT_RECEIVED LITERAL1 + +RADIOLIB_ERR_INVALID_NUM_BROAD_ADDRS LITERAL1 + +RADIOLIB_ERR_INVALID_CRC_CONFIGURATION LITERAL1 +RADIOLIB_LORA_DETECTED LITERAL1 +RADIOLIB_ERR_INVALID_TCXO_VOLTAGE LITERAL1 +RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS LITERAL1 +RADIOLIB_ERR_SPI_CMD_TIMEOUT LITERAL1 +RADIOLIB_ERR_SPI_CMD_INVALID LITERAL1 +RADIOLIB_ERR_SPI_CMD_FAILED LITERAL1 +RADIOLIB_ERR_INVALID_SLEEP_PERIOD LITERAL1 +RADIOLIB_ERR_INVALID_RX_PERIOD LITERAL1 + +RADIOLIB_ERR_INVALID_CALLSIGN LITERAL1 +RADIOLIB_ERR_INVALID_NUM_REPEATERS LITERAL1 +RADIOLIB_ERR_INVALID_REPEATER_CALLSIGN LITERAL1 + +RADIOLIB_ERR_RANGING_TIMEOUT LITERAL1 + +RADIOLIB_ERR_INVALID_PAYLOAD LITERAL1 +RADIOLIB_ERR_ADDRESS_NOT_FOUND LITERAL1 +RADIOLIB_ERR_INVALID_FUNCTION LITERAL1 + +RADIOLIB_ERR_NETWORK_NOT_JOINED LITERAL1 +RADIOLIB_ERR_DOWNLINK_MALFORMED LITERAL1 +RADIOLIB_ERR_INVALID_REVISION LITERAL1 +RADIOLIB_ERR_INVALID_PORT LITERAL1 +RADIOLIB_ERR_NO_RX_WINDOW LITERAL1 +RADIOLIB_ERR_INVALID_CHANNEL LITERAL1 +RADIOLIB_ERR_INVALID_CID LITERAL1 +RADIOLIB_ERR_UPLINK_UNAVAILABLE LITERAL1 +RADIOLIB_ERR_COMMAND_QUEUE_FULL LITERAL1 +RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND LITERAL1 +RADIOLIB_ERR_JOIN_NONCE_INVALID LITERAL1 +RADIOLIB_ERR_N_FCNT_DOWN_INVALID LITERAL1 +RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1 +RADIOLIB_ERR_DATA_RATE_INVALID LITERAL1 +RADIOLIB_ERR_DWELL_TIME_EXCEEDED LITERAL1 +RADIOLIB_ERR_CHECKSUM_MISMATCH LITERAL1 \ No newline at end of file diff --git a/lib/lib_rf/RadioLib/library.json b/lib/lib_rf/RadioLib/library.json new file mode 100644 index 000000000..2927c2f6d --- /dev/null +++ b/lib/lib_rf/RadioLib/library.json @@ -0,0 +1,26 @@ +{ + "name": "RadioLib", + "version": "6.4.2", + "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", + "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan", + "homepage": "https://github.com/jgromes/RadioLib", + "repository": + { + "type": "git", + "url": "https://github.com/jgromes/RadioLib.git" + }, + "authors": + { + "name": "Jan Gromeš", + "email": "gromes.jan@gmail.com", + "maintainer": true + }, + "license": "MIT", + "frameworks": "*", + "platforms": "*", + "headers": "RadioLib.h", + "build": + { + "libLDFMode": "chain+" + } +} \ No newline at end of file diff --git a/lib/lib_rf/RadioLib/library.properties b/lib/lib_rf/RadioLib/library.properties new file mode 100644 index 000000000..9fd734b10 --- /dev/null +++ b/lib/lib_rf/RadioLib/library.properties @@ -0,0 +1,10 @@ +name=RadioLib +version=6.4.2 +author=Jan Gromes +maintainer=Jan Gromes +sentence=Universal wireless communication library +paragraph=User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN). +category=Communication +url=https://github.com/jgromes/RadioLib +architectures=* +includes=RadioLib.h diff --git a/lib/lib_rf/RadioLib/license.txt b/lib/lib_rf/RadioLib/license.txt new file mode 100644 index 000000000..201215f25 --- /dev/null +++ b/lib/lib_rf/RadioLib/license.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Jan Gromeš + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/lib_rf/RadioLib/src/ArduinoHal.cpp b/lib/lib_rf/RadioLib/src/ArduinoHal.cpp new file mode 100644 index 000000000..3f7c0c9de --- /dev/null +++ b/lib/lib_rf/RadioLib/src/ArduinoHal.cpp @@ -0,0 +1,201 @@ +#include "ArduinoHal.h" + +#if defined(RADIOLIB_BUILD_ARDUINO) + +ArduinoHal::ArduinoHal(): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), spi(&RADIOLIB_DEFAULT_SPI), initInterface(true) {} + +ArduinoHal::ArduinoHal(SPIClass& spi, SPISettings spiSettings): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), spi(&spi), spiSettings(spiSettings) {} + +void ArduinoHal::init() { + if(initInterface) { + spiBegin(); + } +} + +void ArduinoHal::term() { + if(initInterface) { + spiEnd(); + } +} + +void inline ArduinoHal::pinMode(uint32_t pin, uint32_t mode) { + if(pin == RADIOLIB_NC) { + return; + } + ::pinMode(pin, RADIOLIB_ARDUINOHAL_PIN_MODE_CAST mode); +} + +void inline ArduinoHal::digitalWrite(uint32_t pin, uint32_t value) { + if(pin == RADIOLIB_NC) { + return; + } + ::digitalWrite(pin, RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST value); +} + +uint32_t inline ArduinoHal::digitalRead(uint32_t pin) { + if(pin == RADIOLIB_NC) { + return 0; + } + return(::digitalRead(pin)); +} + +void inline ArduinoHal::attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) { + if(interruptNum == RADIOLIB_NC) { + return; + } + ::attachInterrupt(interruptNum, interruptCb, RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST mode); +} + +void inline ArduinoHal::detachInterrupt(uint32_t interruptNum) { + if(interruptNum == RADIOLIB_NC) { + return; + } + ::detachInterrupt(interruptNum); +} + +void inline ArduinoHal::delay(unsigned long ms) { +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) + ::delay(ms); +#else + ::delay(ms * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); +#endif +} + +void inline ArduinoHal::delayMicroseconds(unsigned long us) { +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) + ::delayMicroseconds(us); +#else + ::delayMicroseconds(us * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); +#endif +} + +unsigned long inline ArduinoHal::millis() { +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) + return(::millis()); +#else + return(::millis() * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); +#endif +} + +unsigned long inline ArduinoHal::micros() { +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) + return(::micros()); +#else + return(::micros() * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); +#endif +} + +long inline ArduinoHal::pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) { + if(pin == RADIOLIB_NC) { + return 0; + } + return(::pulseIn(pin, state, timeout)); +} + +void inline ArduinoHal::spiBegin() { + spi->begin(); +} + +void inline ArduinoHal::spiBeginTransaction() { + spi->beginTransaction(spiSettings); +} + +void ArduinoHal::spiTransfer(uint8_t* out, size_t len, uint8_t* in) { + for(size_t i = 0; i < len; i++) { + in[i] = spi->transfer(out[i]); + } +} + +void inline ArduinoHal::spiEndTransaction() { + spi->endTransaction(); +} + +void inline ArduinoHal::spiEnd() { + spi->end(); +} + +void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) { + #if !defined(RADIOLIB_TONE_UNSUPPORTED) + if(pin == RADIOLIB_NC) { + return; + } + ::tone(pin, frequency, duration); + #elif defined(RADIOLIB_ESP32) + // ESP32 tone() emulation + (void)duration; + if(prev == -1) { + #if !defined(ESP_IDF_VERSION) || (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0)) + ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); + #endif + } + if(prev != frequency) { + #if !defined(ESP_IDF_VERSION) || (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0)) + ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, frequency); + #else + ledcWriteTone(pin, frequency); + #endif + } + prev = frequency; + #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) + // better tone for mbed OS boards + (void)duration; + if(!pwmPin) { + pwmPin = new mbed::PwmOut(digitalPinToPinName(pin)); + } + pwmPin->period(1.0 / frequency); + pwmPin->write(0.5); + #else + (void)pin; + (void)frequency; + (void)duration; + #endif +} + +void inline ArduinoHal::noTone(uint32_t pin) { + #if !defined(RADIOLIB_TONE_UNSUPPORTED) and defined(ARDUINO_ARCH_STM32) + if(pin == RADIOLIB_NC) { + return; + } + ::noTone(pin, false); + #elif !defined(RADIOLIB_TONE_UNSUPPORTED) + if(pin == RADIOLIB_NC) { + return; + } + ::noTone(pin); + #elif defined(RADIOLIB_ESP32) + if(pin == RADIOLIB_NC) { + return; + } + // ESP32 tone() emulation + #if !defined(ESP_IDF_VERSION) || (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0)) + ledcDetachPin(pin); + ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); + #else + ledcDetach(pin); + ledcWrite(pin, 0); + #endif + prev = -1; + #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) + if(pin == RADIOLIB_NC) { + return; + } + // better tone for mbed OS boards + (void)pin; + pwmPin->suspend(); + #else + (void)pin; + #endif +} + +void inline ArduinoHal::yield() { + #if !defined(RADIOLIB_YIELD_UNSUPPORTED) +// ::yield(); + ::delay(0); + #endif +} + +uint32_t inline ArduinoHal::pinToInterrupt(uint32_t pin) { + return(digitalPinToInterrupt(pin)); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/ArduinoHal.h b/lib/lib_rf/RadioLib/src/ArduinoHal.h new file mode 100644 index 000000000..00074c1d3 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/ArduinoHal.h @@ -0,0 +1,80 @@ +// make sure this is always compiled +#include "TypeDef.h" + +#if !defined(_RADIOLIB_ARDUINOHAL_H) +#define _RADIOLIB_ARDUINOHAL_H + +// this file only makes sense for Arduino builds +#if defined(RADIOLIB_BUILD_ARDUINO) + +#if defined(RADIOLIB_MBED_TONE_OVERRIDE) +#include "mbed.h" +#endif + +#include "Hal.h" + +#include + +/*! + \class ArduinoHal + \brief Arduino default hardware abstraction library implementation. + This class can be extended to support other Arduino platform or change behaviour of the default implementation. +*/ +class ArduinoHal : public RadioLibHal { + public: + /*! + \brief Arduino Hal constructor. Will use the default SPI interface and automatically initialize it. + */ + ArduinoHal(); + + /*! + \brief Arduino Hal constructor. Will not attempt SPI interface initialization. + \param spi SPI interface to be used, can also use software SPI implementations. + \param spiSettings SPI interface settings. + */ + ArduinoHal(SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); + + // implementations of pure virtual RadioLibHal methods + void pinMode(uint32_t pin, uint32_t mode) override; + void digitalWrite(uint32_t pin, uint32_t value) override; + uint32_t digitalRead(uint32_t pin) override; + void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override; + void detachInterrupt(uint32_t interruptNum) override; + void delay(unsigned long ms) override; + void delayMicroseconds(unsigned long us) override; + unsigned long millis() override; + unsigned long micros() override; + long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override; + void spiBegin() override; + void spiBeginTransaction() override; + void spiTransfer(uint8_t* out, size_t len, uint8_t* in) override; + void spiEndTransaction() override; + void spiEnd() override; + + // implementations of virtual RadioLibHal methods + void init() override; + void term() override; + void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) override; + void noTone(uint32_t pin) override; + void yield() override; + uint32_t pinToInterrupt(uint32_t pin) override; + +#if !RADIOLIB_GODMODE + private: +#endif + SPIClass* spi = NULL; + SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS; + bool initInterface = false; + + #if defined(RADIOLIB_MBED_TONE_OVERRIDE) + mbed::PwmOut *pwmPin = NULL; + #endif + + #if defined(RADIOLIB_ESP32) + int32_t prev = -1; + #endif +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/BuildOpt.h b/lib/lib_rf/RadioLib/src/BuildOpt.h new file mode 100644 index 000000000..5653a1ef1 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/BuildOpt.h @@ -0,0 +1,566 @@ +#if !defined(_RADIOLIB_BUILD_OPTIONS_H) +#define _RADIOLIB_BUILD_OPTIONS_H + +/* RadioLib build configuration options */ + +/* + * Debug output enable. + * Warning: Debug output will slow down the whole system significantly. + * Also, it will result in larger compiled binary. + * Levels: basic - only main info + * protocol - mainly LoRaWAN stuff, but other protocols as well + * SPI - full transcript of all SPI communication + */ +#if !defined(RADIOLIB_DEBUG_BASIC) + #define RADIOLIB_DEBUG_BASIC (0) +#endif +#if !defined(RADIOLIB_DEBUG_PROTOCOL) + #define RADIOLIB_DEBUG_PROTOCOL (0) +#endif +#if !defined(RADIOLIB_DEBUG_SPI) + #define RADIOLIB_DEBUG_SPI (0) +#endif + +// set which output port should be used for debug output +// may be Serial port (on Arduino) or file like stdout or stderr (on generic platforms) +#if !defined(RADIOLIB_DEBUG_PORT) + #define RADIOLIB_DEBUG_PORT Serial +#endif + +/* + * Comment to disable "paranoid" SPI mode, or set RADIOLIB_SPI_PARANOID to 0 + * Every write to an SPI register using SPI set function will be verified by a subsequent read operation. + * This improves reliability, but slightly slows down communication. + * Note: Enabled by default. + */ +#if !defined(RADIOLIB_SPI_PARANOID) + #define RADIOLIB_SPI_PARANOID (1) +#endif + +/* + * Comment to disable parameter range checking + * RadioLib will check provided parameters (such as frequency) against limits determined by the device manufacturer. + * It is highly advised to keep this macro defined, removing it will allow invalid values to be set, + * possibly leading to bricked module and/or program crashing. + * Note: Enabled by default. + */ +#if !defined(RADIOLIB_CHECK_PARAMS) + #define RADIOLIB_CHECK_PARAMS (1) +#endif + +/* + * SX127x errata fix enable + * Warning: SX127x errata fix has been reported to cause issues with LoRa bandwidths lower than 62.5 kHz. + * It should only be enabled if you really are observing some errata-related issue. + * Note: Disabled by default. + */ +#if !defined(RADIOLIB_FIX_ERRATA_SX127X) + #define RADIOLIB_FIX_ERRATA_SX127X (0) +#endif + +/* + * God mode enable - all methods and member variables in all classes will be made public, thus making them accessible from Arduino code. + * Warning: Come on, it's called GOD mode - obviously only use this if you know what you're doing. + * Failure to heed the above warning may result in bricked module. + */ +#if !defined(RADIOLIB_GODMODE) + #define RADIOLIB_GODMODE (0) +#endif + +/* + * Low-level hardware access enable + * This will make some hardware methods like SPI get/set accessible from the user sketch - think of it as "god mode lite" + * Warning: RadioLib won't stop you from writing invalid stuff into your device, so it's quite easy to brick your module with this. + */ +#if !defined(RADIOLIB_LOW_LEVEL) + #define RADIOLIB_LOW_LEVEL (0) +#endif + +/* + * Enable pre-defined modules when using RadioShield, disabled by default. + */ +#if !defined(RADIOLIB_RADIOSHIELD) + #define RADIOLIB_RADIOSHIELD (0) +#endif + +/* + * Enable interrupt-based timing control + * For details, see https://github.com/jgromes/RadioLib/wiki/Interrupt-Based-Timing + */ +#if !defined(RADIOLIB_INTERRUPT_TIMING) + #define RADIOLIB_INTERRUPT_TIMING (0) +#endif + +/* + * Enable static-only memory management: no dynamic allocation will be performed. + * Warning: Large static arrays will be created in some methods. It is not advised to send large packets in this mode. + */ +#if !defined(RADIOLIB_STATIC_ONLY) + #define RADIOLIB_STATIC_ONLY (0) +#endif + +// set the size of static arrays to use +#if !defined(RADIOLIB_STATIC_ARRAY_SIZE) + #define RADIOLIB_STATIC_ARRAY_SIZE (256) +#endif + +/* + * Uncomment on boards whose clock runs too slow or too fast + * Set the value according to the following scheme: + * Enable timestamps on your terminal + * Print something to terminal, wait 1000 milliseconds, print something again + * If the difference is e.g. 1014 milliseconds between the prints, set this value to 14 + * Or, for more accuracy, wait for 100,000 milliseconds and divide the total drift by 100 + */ +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) + //#define RADIOLIB_CLOCK_DRIFT_MS (0) +#endif + +#if ARDUINO >= 100 + // Arduino build + #include "Arduino.h" + #define RADIOLIB_BUILD_ARDUINO +#else + // generic build + #include + #define RADIOLIB_BUILD_GENERIC +#endif + +#if defined(RADIOLIB_BUILD_ARDUINO) +/* + * Platform-specific configuration. + * + * RADIOLIB_PLATFORM - platform name, used in debugging to quickly check the correct platform is detected. + * RADIOLIB_NC - alias for unused pin, usually the largest possible value of uint8_t. + * RADIOLIB_DEFAULT_SPI - default SPIClass instance to use. + * RADIOLIB_NONVOLATILE - macro to place variable into program storage (usually Flash). + * RADIOLIB_NONVOLATILE_READ_BYTE - function/macro to read variables saved in program storage (usually Flash). + * RADIOLIB_TYPE_ALIAS - construct to create an alias for a type, usually vai the `using` keyword. + * RADIOLIB_TONE_UNSUPPORTED - some platforms do not have tone()/noTone(), which is required for AFSK. + * RADIOLIB_BUILTIN_MODULE - some platforms have a builtin radio module on fixed pins, this macro is used to specify that pinout. + * + * In addition, some platforms may require RadioLib to disable specific drivers (such as ESP8266). + * + * Users may also specify their own configuration by uncommenting the RADIOLIB_CUSTOM_ARDUINO, + * and then specifying all platform parameters in the section below. This will override automatic + * platform detection. + */ + + // uncomment to enable custom platform definition + //#define RADIOLIB_CUSTOM_ARDUINO + +#if defined(RADIOLIB_CUSTOM_ARDUINO) + // name for your platform + #define RADIOLIB_PLATFORM "Custom" + + // the following must be defined if the Arduino core does not support tone or yield function + //#define RADIOLIB_TONE_UNSUPPORTED + //#define RADIOLIB_YIELD_UNSUPPORTED + + // in addition, the following macros may be defined if the Arduino core differs from the defaults + #define RADIOLIB_NC (0xFFFFFFFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + + // you might also have to define these if the Arduino core has some uncommon pin mode/status types + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST + + // some of RadioLib drivers may be excluded, to prevent collisions with platforms (or to speed up build process) + // the following is a complete list of all possible exclusion macros, uncomment any of them to disable that driver + // NOTE: Some of the exclusion macros are dependent on each other. For example, it is not possible to exclude RF69 + // while keeping SX1231 (because RF69 is the base class for SX1231). The dependency is always uni-directional, + // so excluding SX1231 and keeping RF69 is valid. + //#define RADIOLIB_EXCLUDE_CC1101 (1) + //#define RADIOLIB_EXCLUDE_NRF24 (1) + //#define RADIOLIB_EXCLUDE_RF69 (1) + //#define RADIOLIB_EXCLUDE_SX1231 (1) // dependent on RADIOLIB_EXCLUDE_RF69 + //#define RADIOLIB_EXCLUDE_SI443X (1) + //#define RADIOLIB_EXCLUDE_RFM2X (1) // dependent on RADIOLIB_EXCLUDE_SI443X + //#define RADIOLIB_EXCLUDE_SX127X (1) + //#define RADIOLIB_EXCLUDE_SX126X (1) + //#define RADIOLIB_EXCLUDE_STM32WLX (1) // dependent on RADIOLIB_EXCLUDE_SX126X + //#define RADIOLIB_EXCLUDE_SX128X (1) + //#define RADIOLIB_EXCLUDE_AFSK (1) + //#define RADIOLIB_EXCLUDE_AX25 (1) + //#define RADIOLIB_EXCLUDE_HELLSCHREIBER (1) + //#define RADIOLIB_EXCLUDE_MORSE (1) + //#define RADIOLIB_EXCLUDE_RTTY (1) + //#define RADIOLIB_EXCLUDE_SSTV (1) + //#define RADIOLIB_EXCLUDE_DIRECT_RECEIVE (1) + +#elif defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_ARCH_MEGAAVR)) + // Arduino AVR boards (except for megaAVR) - Uno, Mega etc. + #define RADIOLIB_PLATFORM "Arduino AVR" + + #if !(defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)) + #define RADIOLIB_LOWEND_PLATFORM + #endif + +#elif defined(ESP8266) + // ESP8266 boards + #define RADIOLIB_PLATFORM "ESP8266" + +#elif defined(ESP32) || defined(ARDUINO_ARCH_ESP32) + #define RADIOLIB_ESP32 + + // ESP32 boards + #define RADIOLIB_PLATFORM "ESP32" + + // ESP32 doesn't support tone(), but it can be emulated via LED control peripheral + #define RADIOLIB_TONE_UNSUPPORTED + #define RADIOLIB_TONE_ESP32_CHANNEL (1) + +#elif defined(ARDUINO_ARCH_STM32) + // official STM32 Arduino core (https://github.com/stm32duino/Arduino_Core_STM32) + #define RADIOLIB_PLATFORM "Arduino STM32 (official)" + +#elif defined(SAMD_SERIES) + // Adafruit SAMD boards (M0 and M4) + #define RADIOLIB_PLATFORM "Adafruit SAMD" + +#elif defined(ARDUINO_ARCH_SAMD) + // Arduino SAMD (Zero, MKR, etc.) + #define RADIOLIB_PLATFORM "Arduino SAMD" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + +#elif defined(__SAM3X8E__) + // Arduino Due + #define RADIOLIB_PLATFORM "Arduino Due" + #define RADIOLIB_TONE_UNSUPPORTED + +#elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) + // Adafruit nRF52 boards + #define RADIOLIB_PLATFORM "Adafruit nRF52" + +#elif defined(ARDUINO_ARC32_TOOLS) + // Intel Curie + #define RADIOLIB_PLATFORM "Intel Curie" + +#elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(PORTDUINO) + // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every + #define RADIOLIB_PLATFORM "Arduino megaAVR" + +#elif defined(ARDUINO_ARCH_APOLLO3) + // Sparkfun Apollo3 boards + #define RADIOLIB_PLATFORM "Sparkfun Apollo3" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (Arduino_PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + +#elif defined(ARDUINO_ARDUINO_NANO33BLE) + // Arduino Nano 33 BLE + #define RADIOLIB_PLATFORM "Arduino Nano 33 BLE" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + + // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds + #define RADIOLIB_TONE_UNSUPPORTED + #define RADIOLIB_MBED_TONE_OVERRIDE + +#elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) + // Arduino Portenta H7 + #define RADIOLIB_PLATFORM "Portenta H7" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + + // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds + #define RADIOLIB_TONE_UNSUPPORTED + #define RADIOLIB_MBED_TONE_OVERRIDE + +#elif defined(__STM32F4__) || defined(__STM32F1__) + // Arduino STM32 core by Roger Clark (https://github.com/rogerclarkmelbourne/Arduino_STM32) + #define RADIOLIB_PLATFORM "STM32duino (unofficial)" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (WiringPinMode) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (ExtIntTriggerMode) + +#elif defined(ARDUINO_ARCH_MEGAAVR) + // MegaCoreX by MCUdude (https://github.com/MCUdude/MegaCoreX) + #define RADIOLIB_PLATFORM "MegaCoreX" + +#elif defined(ARDUINO_ARCH_MBED_RP2040) + // Raspberry Pi Pico (official mbed core) + #define RADIOLIB_PLATFORM "Raspberry Pi Pico" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + + // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds + #define RADIOLIB_TONE_UNSUPPORTED + #define RADIOLIB_MBED_TONE_OVERRIDE + +#elif defined(ARDUINO_ARCH_RP2040) + // Raspberry Pi Pico (unofficial core) + #define RADIOLIB_PLATFORM "Raspberry Pi Pico (unofficial)" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + +#elif defined(__ASR6501__) || defined(ARDUINO_ARCH_ASR650X) || defined(DARDUINO_ARCH_ASR6601) + // CubeCell + #define RADIOLIB_PLATFORM "CubeCell" + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(1000000, MSBFIRST, SPI_MODE0) // see issue #709 + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PINMODE) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (IrqModes) + + // provide an easy access to the on-board module + #include "board-config.h" + #define RADIOLIB_BUILTIN_MODULE RADIO_NSS, RADIO_DIO_1, RADIO_RESET, RADIO_BUSY + + // CubeCell doesn't seem to define nullptr, let's do something like that now + #define nullptr NULL + + // ... and also defines pinMode() as a macro, which is by far the stupidest thing I have seen on Arduino + #undef pinMode + + // ... and uses an outdated GCC which does not support type aliases + #define RADIOLIB_TYPE_ALIAS(type, alias) typedef class type alias; + + // ... and it also has no tone(). This platform was designed by an idiot. + #define RADIOLIB_TONE_UNSUPPORTED + + // ... AND as the (hopefully) final nail in the coffin, IT F*CKING DEFINES YIELD() AS A MACRO THAT DOES NOTHING!!! + #define RADIOLIB_YIELD_UNSUPPORTED + #if defined(yield) + #undef yield + #endif + +#elif defined(RASPI) + // RaspiDuino framework (https://github.com/me-no-dev/RasPiArduino) + #define RADIOLIB_PLATFORM "RasPiArduino" + + // let's start off easy - no tone on this platform, that can happen + #define RADIOLIB_TONE_UNSUPPORTED + + // hmm, no yield either - weird on something like Raspberry PI, but sure, we can handle it + #define RADIOLIB_YIELD_UNSUPPORTED + + // aight, getting to the juicy stuff - PGM_P seems missing, that's the first time + #define PGM_P const char * + + // ... and for the grand finale, we have millis() and micros() DEFINED AS MACROS! + #if defined(millis) + #undef millis + inline unsigned long millis() { return((unsigned long)(STCV / 1000)); }; + #endif + + #if defined(micros) + #undef micros + inline unsigned long micros() { return((unsigned long)(STCV)); }; + #endif + +#elif defined(TEENSYDUINO) + // Teensy + #define RADIOLIB_PLATFORM "Teensy" + +#elif defined(ARDUINO_ARCH_RENESAS) + // Arduino Renesas (UNO R4) + #define RADIOLIB_PLATFORM "Arduino Renesas (UNO R4)" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + +#else + // other Arduino platforms not covered by the above list - this may or may not work + #define RADIOLIB_PLATFORM "Unknown Arduino" + #define RADIOLIB_UNKNOWN_PLATFORM + +#endif + + // set the default values for all macros + // these will be applied if they were not defined above + #if !defined(RADIOLIB_NC) + #define RADIOLIB_NC (0xFFFFFFFF) + #endif + + #if !defined(RADIOLIB_DEFAULT_SPI) + #define RADIOLIB_DEFAULT_SPI SPI + #endif + + #if !defined(RADIOLIB_DEFAULT_SPI_SETTINGS) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #endif + + #if !defined(RADIOLIB_NONVOLATILE) + #define RADIOLIB_NONVOLATILE PROGMEM + #endif + + #if !defined(RADIOLIB_NONVOLATILE_PTR) + #define RADIOLIB_NONVOLATILE_PTR PGM_P + #endif + + #if !defined(RADIOLIB_NONVOLATILE_READ_BYTE) + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #endif + + #if !defined(RADIOLIB_NONVOLATILE_READ_DWORD) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) + #endif + + #if !defined(RADIOLIB_TYPE_ALIAS) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + #endif + + #if !defined(RADIOLIB_ARDUINOHAL_PIN_MODE_CAST) + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST + #endif + + #if !defined(RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST + #endif + + #if !defined(RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST + #endif + +#else + // generic non-Arduino platform + #define RADIOLIB_PLATFORM "Generic" + + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_NONVOLATILE + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) (*((uint8_t *)(void *)(addr))) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) (*((uint32_t *)(void *)(addr))) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + + #if !defined(RADIOLIB_DEBUG_PORT) + #define RADIOLIB_DEBUG_PORT stdout + #endif + + #define DEC 10 + #define HEX 16 + #define OCT 8 + #define BIN 2 + + #include + +#endif + +// This only compiles on STM32 boards with SUBGHZ module, but also +// include when generating docs +#if (!defined(ARDUINO_ARCH_STM32) || !defined(SUBGHZSPI_BASE)) && !defined(DOXYGEN) + #define RADIOLIB_EXCLUDE_STM32WLX (1) +#endif + +// set the global debug mode flag +#if RADIOLIB_DEBUG_BASIC || RADIOLIB_DEBUG_PROTOCOL || RADIOLIB_DEBUG_SPI + #define RADIOLIB_DEBUG (1) +#else + #define RADIOLIB_DEBUG (0) +#endif + +#if RADIOLIB_DEBUG + #if defined(RADIOLIB_BUILD_ARDUINO) + #define RADIOLIB_DEBUG_PRINT(...) Module::serialPrintf(__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN(M, ...) Module::serialPrintf(M "\n", ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) Module::serialPrintf(LEVEL "" M, ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) Module::serialPrintf(LEVEL "" M "\n", ##__VA_ARGS__) + + // some platforms do not support printf("%f"), so it has to be done this way + #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL); RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS) + #else + #if !defined(RADIOLIB_DEBUG_PRINT) + #define RADIOLIB_DEBUG_PRINT(...) fprintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__) + #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) fprintf(RADIOLIB_DEBUG_PORT, LEVEL "" M, ##__VA_ARGS__) + #endif + #if !defined(RADIOLIB_DEBUG_PRINTLN) + #define RADIOLIB_DEBUG_PRINTLN(M, ...) fprintf(RADIOLIB_DEBUG_PORT, M "\n", ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) fprintf(RADIOLIB_DEBUG_PORT, LEVEL "" M "\n", ##__VA_ARGS__) + #endif + #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL "%.3f", VAL) + #endif + + #define RADIOLIB_DEBUG_HEXDUMP(LEVEL, ...) Module::hexdump(LEVEL, __VA_ARGS__) +#else + #define RADIOLIB_DEBUG_PRINT(...) {} + #define RADIOLIB_DEBUG_PRINTLN(...) {} + #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) {} + #define RADIOLIB_DEBUG_HEXDUMP(...) {} +#endif + +#if RADIOLIB_DEBUG_BASIC + #define RADIOLIB_DEBUG_BASIC_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_DBG: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT_LVL("", __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_DBG: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_DBG: ", __VA_ARGS__); + #define RADIOLIB_DEBUG_BASIC_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_DBG: ", __VA_ARGS__); +#else + #define RADIOLIB_DEBUG_BASIC_PRINT(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINTLN(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) {} + #define RADIOLIB_DEBUG_BASIC_HEXDUMP(...) {} +#endif + +#if RADIOLIB_DEBUG_PROTOCOL + #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_PRO: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_PRO: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_PRO: ", __VA_ARGS__); + #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_PRO: ", __VA_ARGS__); +#else + #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) {} +#endif + +#if RADIOLIB_DEBUG_SPI + #define RADIOLIB_DEBUG_SPI_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_SPI: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT_LVL("", __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_SPI: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN_LVL("", __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_SPI: ", __VA_ARGS__); + #define RADIOLIB_DEBUG_SPI_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_SPI: ", __VA_ARGS__); +#else + #define RADIOLIB_DEBUG_SPI_PRINT(...) {} + #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) {} + #define RADIOLIB_DEBUG_SPI_PRINTLN(...) {} + #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) {} + #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) {} + #define RADIOLIB_DEBUG_SPI_HEXDUMP(...) {} +#endif + + +/*! + \brief A simple assert macro, will return on error. +*/ +#define RADIOLIB_ASSERT(STATEVAR) { if((STATEVAR) != RADIOLIB_ERR_NONE) { return(STATEVAR); } } + +/*! + \brief Macro to check variable is within constraints - this is commonly used to check parameter ranges. Requires RADIOLIB_CHECK_RANGE to be enabled +*/ +#if RADIOLIB_CHECK_PARAMS + #define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) { if(!(((VAR) >= (MIN)) && ((VAR) <= (MAX)))) { return(ERR); } } +#else + #define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) {} +#endif + +#if RADIOLIB_FIX_ERRATA_SX127X + #define RADIOLIB_ERRATA_SX127X(...) { errataFix(__VA_ARGS__); } +#else + #define RADIOLIB_ERRATA_SX127X(...) {} +#endif + +// these macros are usually defined by Arduino, but some platforms undef them, so its safer to use our own +#define RADIOLIB_MIN(a,b) ((a)<(b)?(a):(b)) +#define RADIOLIB_MAX(a,b) ((a)>(b)?(a):(b)) +#define RADIOLIB_ABS(x) ((x)>0?(x):-(x)) + +// version definitions +#define RADIOLIB_VERSION_MAJOR 6 +#define RADIOLIB_VERSION_MINOR 4 +#define RADIOLIB_VERSION_PATCH 2 +#define RADIOLIB_VERSION_EXTRA 0 + +#define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) + +#endif \ No newline at end of file diff --git a/lib/lib_rf/RadioLib/src/BuildOptUser.h b/lib/lib_rf/RadioLib/src/BuildOptUser.h new file mode 100644 index 000000000..d81104d7d --- /dev/null +++ b/lib/lib_rf/RadioLib/src/BuildOptUser.h @@ -0,0 +1,12 @@ +#if !defined(_RADIOLIB_USER_BUILD_OPTIONS_H) +#define _RADIOLIB_USER_BUILD_OPTIONS_H + +// this file can be used to define any user build options +// most commonly, RADIOLIB_EXCLUDE_* macros +// or enabling debug output + +//#define RADIOLIB_DEBUG_BASIC (1) // basic debugging (e.g. reporting GPIO timeouts or module not being found) +//#define RADIOLIB_DEBUG_PROTOCOL (1) // protocol information (e.g. LoRaWAN internal information) +//#define RADIOLIB_DEBUG_SPI (1) // verbose transcription of all SPI communication - produces large debug logs! + +#endif diff --git a/lib/lib_rf/RadioLib/src/Hal.cpp b/lib/lib_rf/RadioLib/src/Hal.cpp new file mode 100644 index 000000000..1a42aa15a --- /dev/null +++ b/lib/lib_rf/RadioLib/src/Hal.cpp @@ -0,0 +1,35 @@ +#include "Hal.h" + +RadioLibHal::RadioLibHal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling) + : GpioModeInput(input), + GpioModeOutput(output), + GpioLevelLow(low), + GpioLevelHigh(high), + GpioInterruptRising(rising), + GpioInterruptFalling(falling) {} + +void RadioLibHal::init() { + +} + +void RadioLibHal::term() { + +} + +void RadioLibHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) { + (void)pin; + (void)frequency; + (void)duration; +} + +void RadioLibHal::noTone(uint32_t pin) { + (void)pin; +} + +void RadioLibHal::yield() { + +} + +uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) { + return(pin); +} diff --git a/lib/lib_rf/RadioLib/src/Hal.h b/lib/lib_rf/RadioLib/src/Hal.h new file mode 100644 index 000000000..03bf174ce --- /dev/null +++ b/lib/lib_rf/RadioLib/src/Hal.h @@ -0,0 +1,212 @@ +#if !defined(_RADIOLIB_HAL_H) +#define _RADIOLIB_HAL_H + +#include +#include + +#include "BuildOpt.h" + +/*! + \class RadioLibHal + \brief Hardware abstraction library base interface. +*/ +class RadioLibHal { + public: + + // values for pin modes, levels and change directions + // these tell RadioLib how are different logic states represented on a given platform + + /*! + \brief Value to be used as the "input" GPIO direction. + */ + const uint32_t GpioModeInput; + + /*! + \brief Value to be used as the "output" GPIO direction. + */ + const uint32_t GpioModeOutput; + + /*! + \brief Value to be used as the "low" GPIO level. + */ + const uint32_t GpioLevelLow; + + /*! + \brief Value to be used as the "high" GPIO level. + */ + const uint32_t GpioLevelHigh; + + /*! + \brief Value to be used as the "rising" GPIO level change direction. + */ + const uint32_t GpioInterruptRising; + + /*! + \brief Value to be used as the "falling" GPIO level change direction. + */ + const uint32_t GpioInterruptFalling; + + /*! + \brief Default constructor. + \param input Value to be used as the "input" GPIO direction. + \param output Value to be used as the "output" GPIO direction. + \param low Value to be used as the "low" GPIO level. + \param high Value to be used as the "high" GPIO level. + \param rising Value to be used as the "rising" GPIO level change direction. + \param falling Value to be used as the "falling" GPIO level change direction. + */ + RadioLibHal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling); + + // pure virtual methods - these must be implemented by the hardware abstraction for RadioLib to function + + /*! + \brief GPIO pin mode (input/output/...) configuration method. + Must be implemented by the platform-specific hardware abstraction! + \param pin Pin to be changed (platform-specific). + \param mode Mode to be set (platform-specific). + */ + virtual void pinMode(uint32_t pin, uint32_t mode) = 0; + + /*! + \brief Digital write method. + Must be implemented by the platform-specific hardware abstraction! + \param pin Pin to be changed (platform-specific). + \param value Value to set (platform-specific). + */ + virtual void digitalWrite(uint32_t pin, uint32_t value) = 0; + + /*! + \brief Digital read method. + Must be implemented by the platform-specific hardware abstraction! + \param pin Pin to be changed (platform-specific). + \returns Value read on the pin (platform-specific). + */ + virtual uint32_t digitalRead(uint32_t pin) = 0; + + /*! + \brief Method to attach function to an external interrupt. + Must be implemented by the platform-specific hardware abstraction! + \param interruptNum Interrupt number to attach to (platform-specific). + \param interruptCb Interrupt service routine to execute. + \param mode Rising/falling mode (platform-specific). + */ + virtual void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) = 0; + + /*! + \brief Method to detach function from an external interrupt. + Must be implemented by the platform-specific hardware abstraction! + \param interruptNum Interrupt number to detach from (platform-specific). + */ + virtual void detachInterrupt(uint32_t interruptNum) = 0; + + /*! + \brief Blocking wait function. + Must be implemented by the platform-specific hardware abstraction! + \param ms Number of milliseconds to wait. + */ + virtual void delay(unsigned long ms) = 0; + + /*! + \brief Blocking microsecond wait function. + Must be implemented by the platform-specific hardware abstraction! + \param us Number of microseconds to wait. + */ + virtual void delayMicroseconds(unsigned long us) = 0; + + /*! + \brief Get number of milliseconds since start. + Must be implemented by the platform-specific hardware abstraction! + \returns Number of milliseconds since start. + */ + virtual unsigned long millis() = 0; + + /*! + \brief Get number of microseconds since start. + Must be implemented by the platform-specific hardware abstraction! + \returns Number of microseconds since start. + */ + virtual unsigned long micros() = 0; + + /*! + \brief Measure the length of incoming digital pulse in microseconds. + Must be implemented by the platform-specific hardware abstraction! + \param pin Pin to measure on (platform-specific). + \param state Pin level to monitor (platform-specific). + \param timeout Timeout in microseconds. + \returns Pulse length in microseconds, or 0 if the pulse did not start before timeout. + */ + virtual long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) = 0; + + /*! + \brief SPI initialization method. + */ + virtual void spiBegin() = 0; + + /*! + \brief Method to start SPI transaction. + */ + virtual void spiBeginTransaction() = 0; + + /*! + \brief Method to transfer buffer over SPI. + \param out Buffer to send. + \param len Number of data to send or receive. + \param in Buffer to save received data into. + */ + virtual void spiTransfer(uint8_t* out, size_t len, uint8_t* in) = 0; + + /*! + \brief Method to end SPI transaction. + */ + virtual void spiEndTransaction() = 0; + + /*! + \brief SPI termination method. + */ + virtual void spiEnd() = 0; + + // virtual methods - these may or may not exists on a given platform + // they exist in this implementation, but do nothing + + /*! + \brief Module initialization method. + This will be called by all radio modules at the beginning of startup. + Can be used to e.g., initialize SPI interface. + */ + virtual void init(); + + /*! + \brief Module termination method. + This will be called by all radio modules when the destructor is called. + Can be used to e.g., stop SPI interface. + */ + virtual void term(); + + /*! + \brief Method to produce a square-wave with 50% duty cycle ("tone") of a given frequency at some pin. + \param pin Pin to be used as the output. + \param frequency Frequency of the square wave. + \param duration Duration of the tone in ms. When set to 0, the tone will be infinite. + */ + virtual void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0); + + /*! + \brief Method to stop producing a tone. + \param pin Pin which is currently producing the tone. + */ + virtual void noTone(uint32_t pin); + + /*! + \brief Yield method, called from long loops in multi-threaded environment (to prevent blocking other threads). + */ + virtual void yield(); + + /*! + \brief Function to convert from pin number to interrupt number. + \param pin Pin to convert from. + \returns The interrupt number of a given pin. + */ + virtual uint32_t pinToInterrupt(uint32_t pin); +}; + +#endif diff --git a/lib/lib_rf/RadioLib/src/Module.cpp b/lib/lib_rf/RadioLib/src/Module.cpp new file mode 100644 index 000000000..c46e26e9c --- /dev/null +++ b/lib/lib_rf/RadioLib/src/Module.cpp @@ -0,0 +1,546 @@ +#include "Module.h" + +// the following is probably only needed on non-Arduino builds +#include +#include +#include + +#if RADIOLIB_DEBUG +// needed for debug print +#include +#endif + +#if defined(RADIOLIB_BUILD_ARDUINO) +#include "ArduinoHal.h" + +Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) { + this->hal = new ArduinoHal(); +} + +Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio, SPIClass& spi, SPISettings spiSettings) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) { + this->hal = new ArduinoHal(spi, spiSettings); +} +#endif + +Module::Module(RadioLibHal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) { + this->hal = hal; +} + +Module::Module(const Module& mod) { + *this = mod; +} + +Module& Module::operator=(const Module& mod) { + this->SPIreadCommand = mod.SPIreadCommand; + this->SPIwriteCommand = mod.SPIwriteCommand; + this->csPin = mod.csPin; + this->irqPin = mod.irqPin; + this->rstPin = mod.rstPin; + this->gpioPin = mod.gpioPin; + return(*this); +} + +void Module::init() { + this->hal->init(); + this->hal->pinMode(csPin, this->hal->GpioModeOutput); + this->hal->digitalWrite(csPin, this->hal->GpioLevelHigh); + RADIOLIB_DEBUG_BASIC_PRINTLN("RadioLib Debug Info"); + RADIOLIB_DEBUG_BASIC_PRINTLN("Version: %d.%d.%d.%d", RADIOLIB_VERSION_MAJOR, RADIOLIB_VERSION_MINOR, RADIOLIB_VERSION_PATCH, RADIOLIB_VERSION_EXTRA); + RADIOLIB_DEBUG_BASIC_PRINTLN("Platform: " RADIOLIB_PLATFORM); + RADIOLIB_DEBUG_BASIC_PRINTLN("Compiled: " __DATE__ " " __TIME__ "\n"); +} + +void Module::term() { + // stop hardware interfaces (if they were initialized by the library) + this->hal->term(); +} + +int16_t Module::SPIgetRegValue(uint16_t reg, uint8_t msb, uint8_t lsb) { + if((msb > 7) || (lsb > 7) || (lsb > msb)) { + return(RADIOLIB_ERR_INVALID_BIT_RANGE); + } + + uint8_t rawValue = SPIreadRegister(reg); + uint8_t maskedValue = rawValue & ((0b11111111 << lsb) & (0b11111111 >> (7 - msb))); + return(maskedValue); +} + +int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask) { + if((msb > 7) || (lsb > 7) || (lsb > msb)) { + return(RADIOLIB_ERR_INVALID_BIT_RANGE); + } + + uint8_t currentValue = SPIreadRegister(reg); + uint8_t mask = ~((0b11111111 << (msb + 1)) | (0b11111111 >> (8 - lsb))); + uint8_t newValue = (currentValue & ~mask) | (value & mask); + SPIwriteRegister(reg, newValue); + + #if RADIOLIB_SPI_PARANOID + // check register value each millisecond until check interval is reached + // some registers need a bit of time to process the change (e.g. SX127X_REG_OP_MODE) + uint32_t start = this->hal->micros(); + uint8_t readValue = 0x00; + while(this->hal->micros() - start < (checkInterval * 1000)) { + readValue = SPIreadRegister(reg); + if((readValue & checkMask) == (newValue & checkMask)) { + // check passed, we can stop the loop + return(RADIOLIB_ERR_NONE); + } + } + + // check failed, print debug info + RADIOLIB_DEBUG_SPI_PRINTLN(); + RADIOLIB_DEBUG_SPI_PRINTLN("address:\t0x%X", reg); + RADIOLIB_DEBUG_SPI_PRINTLN("bits:\t\t%d %d", msb, lsb); + RADIOLIB_DEBUG_SPI_PRINTLN("value:\t\t0x%X", value); + RADIOLIB_DEBUG_SPI_PRINTLN("current:\t0x%X", currentValue); + RADIOLIB_DEBUG_SPI_PRINTLN("mask:\t\t0x%X", mask); + RADIOLIB_DEBUG_SPI_PRINTLN("new:\t\t0x%X", newValue); + RADIOLIB_DEBUG_SPI_PRINTLN("read:\t\t0x%X", readValue); + + return(RADIOLIB_ERR_SPI_WRITE_FAILED); + #else + return(RADIOLIB_ERR_NONE); + #endif +} + +void Module::SPIreadRegisterBurst(uint16_t reg, size_t numBytes, uint8_t* inBytes) { + if(!SPIstreamType) { + SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes); + } else { + uint8_t cmd[] = { SPIreadCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; + SPItransferStream(cmd, 3, false, NULL, inBytes, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT); + } +} + +uint8_t Module::SPIreadRegister(uint16_t reg) { + uint8_t resp = 0; + if(!SPIstreamType) { + SPItransfer(SPIreadCommand, reg, NULL, &resp, 1); + } else { + uint8_t cmd[] = { SPIreadCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; + SPItransferStream(cmd, 3, false, NULL, &resp, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); + } + return(resp); +} + +void Module::SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, size_t numBytes) { + if(!SPIstreamType) { + SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes); + } else { + uint8_t cmd[] = { SPIwriteCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; + SPItransferStream(cmd, 3, true, data, NULL, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT); + } +} + +void Module::SPIwriteRegister(uint16_t reg, uint8_t data) { + if(!SPIstreamType) { + SPItransfer(SPIwriteCommand, reg, &data, NULL, 1); + } else { + uint8_t cmd[] = { SPIwriteCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; + SPItransferStream(cmd, 3, true, &data, NULL, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); + } +} + +void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) { + // prepare the buffers + size_t buffLen = this->SPIaddrWidth/8 + numBytes; + #if RADIOLIB_STATIC_ONLY + uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* buffOut = new uint8_t[buffLen]; + uint8_t* buffIn = new uint8_t[buffLen]; + #endif + uint8_t* buffOutPtr = buffOut; + + // copy the command + if(this->SPIaddrWidth <= 8) { + *(buffOutPtr++) = reg | cmd; + } else { + *(buffOutPtr++) = (reg >> 8) | cmd; + *(buffOutPtr++) = reg & 0xFF; + } + + // copy the data + if(cmd == SPIwriteCommand) { + memcpy(buffOutPtr, dataOut, numBytes); + } else { + memset(buffOutPtr, this->SPInopCommand, numBytes); + } + + // do the transfer + this->hal->spiBeginTransaction(); + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); + this->hal->spiTransfer(buffOut, buffLen, buffIn); + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh); + this->hal->spiEndTransaction(); + + // copy the data + if(cmd == SPIreadCommand) { + memcpy(dataIn, &buffIn[this->SPIaddrWidth/8], numBytes); + } + + // print debug information + #if RADIOLIB_DEBUG_SPI + uint8_t* debugBuffPtr = NULL; + if(cmd == SPIwriteCommand) { + RADIOLIB_DEBUG_SPI_PRINT("W\t%X\t", reg); + debugBuffPtr = &buffOut[this->SPIaddrWidth/8]; + } else if(cmd == SPIreadCommand) { + RADIOLIB_DEBUG_SPI_PRINT("R\t%X\t", reg); + debugBuffPtr = &buffIn[this->SPIaddrWidth/8]; + } + for(size_t n = 0; n < numBytes; n++) { + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", debugBuffPtr[n]); + } + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); + #endif + + #if !RADIOLIB_STATIC_ONLY + delete[] buffOut; + delete[] buffIn; + #endif +} + +int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { + return(this->SPIreadStream(&cmd, 1, data, numBytes, waitForGpio, verify)); +} + +int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { + // send the command + int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT); + RADIOLIB_ASSERT(state); + + // check the status + if(verify) { + state = this->SPIcheckStream(); + } + + return(state); +} + +int16_t Module::SPIwriteStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { + return(this->SPIwriteStream(&cmd, 1, data, numBytes, waitForGpio, verify)); +} + +int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { + // send the command + int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT); + RADIOLIB_ASSERT(state); + + // check the status + if(verify) { + state = this->SPIcheckStream(); + } + + return(state); +} + +int16_t Module::SPIcheckStream() { + int16_t state = RADIOLIB_ERR_NONE; + + #if RADIOLIB_SPI_PARANOID + // get the status + uint8_t spiStatus = 0; + uint8_t cmd = this->SPIstatusCommand; + state = this->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 0, true, RADIOLIB_MODULE_SPI_TIMEOUT); + RADIOLIB_ASSERT(state); + + // translate to RadioLib status code + if(this->SPIparseStatusCb != nullptr) { + this->SPIstreamError = this->SPIparseStatusCb(spiStatus); + } + #endif + + return(state); +} + +int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, uint32_t timeout) { + // prepare the buffers + size_t buffLen = cmdLen + numBytes; + if(!write) { + buffLen++; + } + #if RADIOLIB_STATIC_ONLY + uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* buffOut = new uint8_t[buffLen]; + uint8_t* buffIn = new uint8_t[buffLen]; + #endif + uint8_t* buffOutPtr = buffOut; + + // copy the command + for(uint8_t n = 0; n < cmdLen; n++) { + *(buffOutPtr++) = cmd[n]; + } + + // copy the data + if(write) { + memcpy(buffOutPtr, dataOut, numBytes); + } else { + memset(buffOutPtr, this->SPInopCommand, numBytes + 1); + } + + // ensure GPIO is low + if(this->gpioPin == RADIOLIB_NC) { + this->hal->delay(1); + } else { + uint32_t start = this->hal->millis(); + while(this->hal->digitalRead(this->gpioPin)) { + this->hal->yield(); + if(this->hal->millis() - start >= timeout) { + RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?"); + #if !RADIOLIB_STATIC_ONLY + delete[] buffOut; + delete[] buffIn; + #endif + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + } + } + } + + // do the transfer + this->hal->spiBeginTransaction(); + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); + this->hal->spiTransfer(buffOut, buffLen, buffIn); + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh); + this->hal->spiEndTransaction(); + + // wait for GPIO to go high and then low + if(waitForGpio) { + if(this->gpioPin == RADIOLIB_NC) { + this->hal->delay(1); + } else { + this->hal->delayMicroseconds(1); + uint32_t start = this->hal->millis(); + while(this->hal->digitalRead(this->gpioPin)) { + this->hal->yield(); + if(this->hal->millis() - start >= timeout) { + RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO post-transfer timeout, is it connected?"); + #if !RADIOLIB_STATIC_ONLY + delete[] buffOut; + delete[] buffIn; + #endif + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + } + } + } + } + + // parse status + int16_t state = RADIOLIB_ERR_NONE; + if((this->SPIparseStatusCb != nullptr) && (numBytes > 0)) { + state = this->SPIparseStatusCb(buffIn[cmdLen]); + } + + // copy the data + if(!write) { + // skip the first byte for read-type commands (status-only) + memcpy(dataIn, &buffIn[cmdLen + 1], numBytes); + } + + // print debug information + #if RADIOLIB_DEBUG_SPI + // print command byte(s) + RADIOLIB_DEBUG_SPI_PRINT("CMD"); + if(write) { + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("W\t"); + } else { + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("R\t"); + } + size_t n = 0; + for(; n < cmdLen; n++) { + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", cmd[n]); + } + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); + + // print data bytes + RADIOLIB_DEBUG_SPI_PRINT("SI\t"); + for(n = 0; n < cmdLen; n++) { + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("\t"); + } + for(; n < buffLen; n++) { + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", buffOut[n]); + } + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); + RADIOLIB_DEBUG_SPI_PRINT("SO\t"); + for(n = 0; n < buffLen; n++) { + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", buffIn[n]); + } + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); + #endif + + #if !RADIOLIB_STATIC_ONLY + delete[] buffOut; + delete[] buffIn; + #endif + + return(state); +} + +void Module::waitForMicroseconds(uint32_t start, uint32_t len) { + #if RADIOLIB_INTERRUPT_TIMING + (void)start; + if((this->TimerSetupCb != nullptr) && (len != this->prevTimingLen)) { + prevTimingLen = len; + this->TimerSetupCb(len); + } + this->TimerFlag = false; + while(!this->TimerFlag) { + this->hal->yield(); + } + #else + while(this->hal->micros() - start < len) { + this->hal->yield(); + } + #endif +} + +uint32_t Module::reflect(uint32_t in, uint8_t bits) { + uint32_t res = 0; + for(uint8_t i = 0; i < bits; i++) { + res |= (((in & ((uint32_t)1 << i)) >> i) << (bits - i - 1)); + } + return(res); +} + +#if RADIOLIB_DEBUG +void Module::hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { + size_t rem_len = len; + for(size_t i = 0; i < len; i+=16) { + char str[80]; + sprintf(str, "%07" PRIx32 " ", i+offset); + size_t line_len = 16; + if(rem_len < line_len) { + line_len = rem_len; + } + for(size_t j = 0; j < line_len; j+=width) { + if(width > 1) { + int m = 0; + int step = width/2; + if(be) { + step *= -1; + } + for(int32_t k = width - 1; k >= -width + 1; k+=step) { + sprintf(&str[8 + (j+m)*3], "%02x ", data[i+j+k+m]); + m++; + } + } else { + sprintf(&str[8 + (j)*3], "%02x ", data[i+j]); + } + } + for(size_t j = line_len; j < 16; j++) { + sprintf(&str[8 + j*3], " "); + } + str[56] = '|'; + str[57] = ' '; + for(size_t j = 0; j < line_len; j++) { + char c = data[i+j]; + if((c < ' ') || (c > '~')) { + c = '.'; + } + sprintf(&str[58 + j], "%c", c); + } + for(size_t j = line_len; j < 16; j++) { + sprintf(&str[58 + j], " "); + } + if(level) { + RADIOLIB_DEBUG_PRINT(level); + } + RADIOLIB_DEBUG_PRINT(str); + RADIOLIB_DEBUG_PRINTLN(); + rem_len -= 16; + } +} + +void Module::regdump(const char* level, uint16_t start, size_t len) { + #if RADIOLIB_STATIC_ONLY + uint8_t buff[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* buff = new uint8_t[len]; + #endif + SPIreadRegisterBurst(start, len, buff); + hexdump(level, buff, len, start); + #if !RADIOLIB_STATIC_ONLY + delete[] buff; + #endif +} +#endif + +#if RADIOLIB_DEBUG && defined(RADIOLIB_BUILD_ARDUINO) +// https://github.com/esp8266/Arduino/blob/65579d29081cb8501e4d7f786747bf12e7b37da2/cores/esp8266/Print.cpp#L50 +size_t Module::serialPrintf(const char* format, ...) { + va_list arg; + va_start(arg, format); + char temp[64]; + char* buffer = temp; + size_t len = vsnprintf(temp, sizeof(temp), format, arg); + va_end(arg); + if (len > sizeof(temp) - 1) { + buffer = new char[len + 1]; + if (!buffer) { + return 0; + } + va_start(arg, format); + vsnprintf(buffer, len + 1, format, arg); + va_end(arg); + } + len = RADIOLIB_DEBUG_PORT.write((const uint8_t*)buffer, len); + if (buffer != temp) { + delete[] buffer; + } + return len; +} +#endif + +void Module::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { + // This can be on the stack, setRfSwitchTable copies the contents + const uint32_t pins[] = { + rxEn, txEn, RADIOLIB_NC, + }; + + // This must be static, since setRfSwitchTable stores a reference. + static const RfSwitchMode_t table[] = { + { MODE_IDLE, {this->hal->GpioLevelLow, this->hal->GpioLevelLow} }, + { MODE_RX, {this->hal->GpioLevelHigh, this->hal->GpioLevelLow} }, + { MODE_TX, {this->hal->GpioLevelLow, this->hal->GpioLevelHigh} }, + END_OF_MODE_TABLE, + }; + setRfSwitchTable(pins, table); +} + +void Module::setRfSwitchTable(const uint32_t (&pins)[3], const RfSwitchMode_t table[]) { + memcpy(this->rfSwitchPins, pins, sizeof(this->rfSwitchPins)); + this->rfSwitchTable = table; + for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) + this->hal->pinMode(pins[i], this->hal->GpioModeOutput); +} + +const Module::RfSwitchMode_t *Module::findRfSwitchMode(uint8_t mode) const { + const RfSwitchMode_t *row = this->rfSwitchTable; + while (row && row->mode != MODE_END_OF_TABLE) { + if (row->mode == mode) + return row; + ++row; + } + return nullptr; +} + +void Module::setRfSwitchState(uint8_t mode) { + const RfSwitchMode_t *row = findRfSwitchMode(mode); + if(!row) { + // RF switch control is disabled or does not have this mode + return; + } + + // set pins + const uint32_t *value = &row->values[0]; + for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) { + uint32_t pin = this->rfSwitchPins[i]; + if (pin != RADIOLIB_NC) + this->hal->digitalWrite(pin, *value); + ++value; + } +} diff --git a/lib/lib_rf/RadioLib/src/Module.h b/lib/lib_rf/RadioLib/src/Module.h new file mode 100644 index 000000000..9b5b78dbc --- /dev/null +++ b/lib/lib_rf/RadioLib/src/Module.h @@ -0,0 +1,512 @@ +#if !defined(_RADIOLIB_MODULE_H) +#define _RADIOLIB_MODULE_H + +#include "TypeDef.h" +#include "Hal.h" + +#if defined(RADIOLIB_BUILD_ARDUINO) + #include +#endif + +#if defined(STM32WLxx) + #include +#endif + +/*! +* Value to use as the last element in a mode table to indicate the +* end of the table. +* +* See setRfSwitchTable() for details. +*/ +#define END_OF_MODE_TABLE { Module::MODE_END_OF_TABLE, {} } + +// default timeout for SPI transfers +#define RADIOLIB_MODULE_SPI_TIMEOUT (1000) + +/*! + \class Module + \brief Implements all common low-level methods to control the wireless module. + Every module class contains one private instance of this class. +*/ +class Module { + public: + /*! + * \brief The maximum number of pins supported by the RF switch + * code. + * + * Note: It is not recommended to use this constant in your sketch + * when defining a rfswitch pins array, to prevent issues when this + * value is ever increased and such an array gets extra zero + * elements (that will be interpreted as pin 0). + */ + static const size_t RFSWITCH_MAX_PINS = 3; + + /*! + * Description of RF switch pin states for a single mode. + * + * See setRfSwitchTable() for details. + */ + struct RfSwitchMode_t { + uint8_t mode; + uint32_t values[RFSWITCH_MAX_PINS]; + }; + + /*! + * Constants to use in a mode table set be setRfSwitchTable. These + * constants work for most radios, but some radios define their own + * constants to be used instead. + * + * See setRfSwitchTable() for details. + */ + enum OpMode_t { + /*! End of table marker, use \ref END_OF_MODE_TABLE constant + * instead. Value is zero to ensure zero-initialized mode ends the + * table */ + MODE_END_OF_TABLE = 0, + /*! Idle mode */ + MODE_IDLE, + /*! Receive mode */ + MODE_RX, + /*! Transmission mode */ + MODE_TX, + }; + + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Arduino Module constructor. Will use the default SPI interface and automatically initialize it. + \param cs Arduino pin to be used as chip select. + \param irq Arduino pin to be used as interrupt/GPIO. + \param rst Arduino pin to be used as hardware reset for the module. + \param gpio Arduino pin to be used as additional interrupt/GPIO. + */ + Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio = RADIOLIB_NC); + + /*! + \brief Arduino Module constructor. Will not attempt SPI interface initialization. + \param cs Arduino pin to be used as chip select. + \param irq Arduino pin to be used as interrupt/GPIO. + \param rst Arduino pin to be used as hardware reset for the module. + \param gpio Arduino pin to be used as additional interrupt/GPIO. + \param spi SPI interface to be used, can also use software SPI implementations. + \param spiSettings SPI interface settings. + */ + Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio, SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); + #endif + + /*! + \brief Module constructor. + \param hal A Hardware abstraction layer instance. An ArduinoHal instance for example. + \param cs Pin to be used as chip select. + \param irq Pin to be used as interrupt/GPIO. + \param rst Pin to be used as hardware reset for the module. + \param gpio Pin to be used as additional interrupt/GPIO. + */ + Module(RadioLibHal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio = RADIOLIB_NC); + + /*! + \brief Copy constructor. + \param mod Module instance to copy. + */ + Module(const Module& mod); + + /*! + \brief Overload for assignment operator. + \param frame rvalue Module. + */ + Module& operator=(const Module& mod); + + // public member variables + /*! + \brief Hardware abstraction layer to be used. + */ + RadioLibHal* hal = NULL; + + /*! + \brief Basic SPI read command. Defaults to 0x00. + */ + uint8_t SPIreadCommand = 0b00000000; + + /*! + \brief Basic SPI write command. Defaults to 0x80. + */ + uint8_t SPIwriteCommand = 0b10000000; + + /*! + \brief Basic SPI no-operation command. Defaults to 0x00. + */ + uint8_t SPInopCommand = 0x00; + + /*! + \brief Basic SPI status read command. Defaults to 0x00. + */ + uint8_t SPIstatusCommand = 0x00; + + /*! + \brief SPI address width. Defaults to 8, currently only supports 8 and 16-bit addresses. + */ + uint8_t SPIaddrWidth = 8; + + /*! + \brief Whether the SPI interface is stream-type (e.g. SX126x) or register-type (e.g. SX127x). + Defaults to register-type SPI interfaces. + */ + bool SPIstreamType = false; + + /*! + \brief The last recorded SPI stream error. + */ + int16_t SPIstreamError = RADIOLIB_ERR_UNKNOWN; + + /*! + \brief SPI status parsing callback typedef. + */ + typedef int16_t (*SPIparseStatusCb_t)(uint8_t in); + + /*! + \brief Callback to function that will parse the module-specific status codes to RadioLib status codes. + Typically used for modules with SPI stream-type interface (e.g. SX126x/SX128x). + */ + SPIparseStatusCb_t SPIparseStatusCb = nullptr; + + #if RADIOLIB_INTERRUPT_TIMING + + /*! + \brief Timer interrupt setup callback typedef. + */ + typedef void (*TimerSetupCb_t)(uint32_t len); + + /*! + \brief Callback to timer interrupt setup function when running in interrupt timing control mode. + */ + TimerSetupCb_t TimerSetupCb = nullptr; + + /*! + \brief Timer flag variable to be controlled by a platform-dependent interrupt. + */ + volatile bool TimerFlag = false; + + #endif + + // basic methods + + /*! + \brief Initialize low-level module control. + */ + void init(); + + /*! + \brief Terminate low-level module control. + */ + void term(); + + // SPI methods + + /*! + \brief SPI read method that automatically masks unused bits. This method is the preferred SPI read mechanism. + \param reg Address of SPI register to read. + \param msb Most significant bit of the register variable. Bits above this one will be masked out. + \param lsb Least significant bit of the register variable. Bits below this one will be masked out. + \returns Masked register value or status code. + */ + int16_t SPIgetRegValue(uint16_t reg, uint8_t msb = 7, uint8_t lsb = 0); + + /*! + \brief Overwrite-safe SPI write method with verification. This method is the preferred SPI write mechanism. + \param reg Address of SPI register to write. + \param value Single byte value that will be written to the SPI register. + \param msb Most significant bit of the register variable. Bits above this one will not be affected by the write operation. + \param lsb Least significant bit of the register variable. Bits below this one will not be affected by the write operation. + \param checkInterval Number of milliseconds between register writing and verification reading. Some registers need up to 10ms to process the change. + \param checkMask Mask of bits to check, only bits set to 1 will be verified. + \returns \ref status_codes + */ + int16_t SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2, uint8_t checkMask = 0xFF); + + /*! + \brief SPI burst read method. + \param reg Address of SPI register to read. + \param numBytes Number of bytes that will be read. + \param inBytes Pointer to array that will hold the read data. + */ + void SPIreadRegisterBurst(uint16_t reg, size_t numBytes, uint8_t* inBytes); + + /*! + \brief SPI basic read method. Use of this method is reserved for special cases, SPIgetRegValue should be used instead. + \param reg Address of SPI register to read. + \returns Value that was read from register. + */ + uint8_t SPIreadRegister(uint16_t reg); + + /*! + \brief SPI burst write method. + \param reg Address of SPI register to write. + \param data Pointer to array that holds the data that will be written. + \param numBytes Number of bytes that will be written. + */ + void SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, size_t numBytes); + + /*! + \brief SPI basic write method. Use of this method is reserved for special cases, SPIsetRegValue should be used instead. + \param reg Address of SPI register to write. + \param data Value that will be written to the register. + */ + void SPIwriteRegister(uint16_t reg, uint8_t data); + + /*! + \brief SPI single transfer method. + \param cmd SPI access command (read/write/burst/...). + \param reg Address of SPI register to transfer to/from. + \param dataOut Data that will be transferred from master to slave. + \param dataIn Data that was transferred from slave to master. + \param numBytes Number of bytes to transfer. + */ + void SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes); + + /*! + \brief Method to check the result of last SPI stream transfer. + \returns \ref status_codes + */ + int16_t SPIcheckStream(); + + /*! + \brief Method to perform a read transaction with SPI stream. + \param cmd SPI operation command. + \param data Data that will be transferred from slave to master. + \param numBytes Number of bytes to transfer. + \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). + \param verify Whether to verify the result of the transaction after it is finished. + \returns \ref status_codes + */ + int16_t SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); + + /*! + \brief Method to perform a read transaction with SPI stream. + \param cmd SPI operation command. + \param cmdLen SPI command length in bytes. + \param data Data that will be transferred from slave to master. + \param numBytes Number of bytes to transfer. + \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). + \param verify Whether to verify the result of the transaction after it is finished. + \returns \ref status_codes + */ + int16_t SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); + + /*! + \brief Method to perform a write transaction with SPI stream. + \param cmd SPI operation command. + \param data Data that will be transferred from master to slave. + \param numBytes Number of bytes to transfer. + \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). + \param verify Whether to verify the result of the transaction after it is finished. + \returns \ref status_codes + */ + int16_t SPIwriteStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); + + /*! + \brief Method to perform a write transaction with SPI stream. + \param cmd SPI operation command. + \param cmdLen SPI command length in bytes. + \param data Data that will be transferred from master to slave. + \param numBytes Number of bytes to transfer. + \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). + \param verify Whether to verify the result of the transaction after it is finished. + \returns \ref status_codes + */ + int16_t SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); + + /*! + \brief SPI single transfer method for modules with stream-type SPI interface (SX126x, SX128x etc.). + \param cmd SPI operation command. + \param cmdLen SPI command length in bytes. + \param write Set to true for write commands, false for read commands. + \param dataOut Data that will be transferred from master to slave. + \param dataIn Data that was transferred from slave to master. + \param numBytes Number of bytes to transfer. + \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). + \param timeout GPIO wait period timeout in milliseconds. + \returns \ref status_codes + */ + int16_t SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, uint32_t timeout); + + // pin number access methods + + /*! + \brief Access method to get the pin number of SPI chip select. + \returns Pin number of SPI chip select configured in the constructor. + */ + uint32_t getCs() const { return(csPin); } + + /*! + \brief Access method to get the pin number of interrupt/GPIO. + \returns Pin number of interrupt/GPIO configured in the constructor. + */ + uint32_t getIrq() const { return(irqPin); } + + /*! + \brief Access method to get the pin number of hardware reset pin. + \returns Pin number of hardware reset pin configured in the constructor. + */ + uint32_t getRst() const { return(rstPin); } + + /*! + \brief Access method to get the pin number of second interrupt/GPIO. + \returns Pin number of second interrupt/GPIO configured in the constructor. + */ + uint32_t getGpio() const { return(gpioPin); } + + /*! + \brief Some modules contain external RF switch controlled by pins. + This function gives RadioLib control over those pins to + automatically switch between various modes: When idle both pins + will be LOW, during TX the `txEn` pin will be HIGH, during RX the + `rxPin` will be HIGH. + + Radiolib will automatically set the pin mode and value of these + pins, so do not control them from the sketch. + + When more than two pins or more control over the output values are + needed, use the setRfSwitchTable() function. + + \param rxEn RX enable pin. + \param txEn TX enable pin. + */ + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); + + /*! + \brief Some modules contain external RF switch controlled by pins. + This function gives RadioLib control over those pins to + automatically switch between various modes. + + Radiolib will automatically set the pin mode and value of these + pins, so do not control them from the sketch. + + + \param pins A reference to an array of pins to control. This + should always be an array of 3 elements. If you need less pins, + use RADIOLIB_NC for the unused elements. + + \param table A reference to an array of pin values to use for each + supported mode. Each element is an RfSwitchMode_T struct that + lists the mode for which it applies and the values for each of the + pins passed in the pins argument respectively. + + The `pins` array will be copied into the Module object, so the + original array can be deallocated after this call. However, + a reference to the `table` array will be stored, so that array + must remain valid as long RadioLib is being used. + + The `mode` field in each table row should normally use any of the + `MODE_*` constants from the Module::OpMode_t enum. However, some + radios support additional modes and will define their own OpMode_t + enum. + + The length of the table is variable (to support radios that add + additional modes), so the table must always be terminated with the + special END_OF_MODE_TABLE value. + + Normally all modes should be listed in the table, but for some + radios, modes can be omitted to indicate they are not supported + (e.g. when a radio has a high power and low power TX mode but + external circuitry only supports low power). If applicable, this + is documented in the radio class itself. + + #### Example + For example, on a board that has an RF switch with an enable pin + connected to PA0 and a TX/RX select pin connected to PA1: + + \code + // In global scope, define the pin array and mode table + static const uint32_t rfswitch_pins[] = + {PA0, PA1, RADIOLIB_NC}; + static const Module::RfSwitchMode_t rfswitch_table[] = { + {Module::MODE_IDLE, {LOW, LOW}}, + {Module::MODE_RX, {HIGH, LOW}}, + {Module::MODE_TX, {HIGH, HIGH}}, + Module::END_OF_MODE_TABLE, + }; + + void setup() { + ... + // Then somewhere in setup, pass them to radiolib + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + ... + } + \endcode + */ + + void setRfSwitchTable(const uint32_t (&pins)[RFSWITCH_MAX_PINS], const RfSwitchMode_t table[]); + + /*! + \brief Find a mode in the RfSwitchTable. + \param The mode to find. + \returns A pointer to the RfSwitchMode_t struct in the table that + matches the passed mode. Returns nullptr if no rfswitch pins are + configured, or the passed mode is not listed in the table. + */ + const RfSwitchMode_t *findRfSwitchMode(uint8_t mode) const; + + /*! + \brief Set RF switch state. + \param mode The mode to set. This must be one of the MODE_ constants, or a radio-specific constant. + */ + void setRfSwitchState(uint8_t mode); + + /*! + \brief Wait for time to elapse, either using the microsecond timer, or the TimerFlag. + Note that in interrupt timing mode, it is up to the user to set up the timing interrupt! + + \param start Waiting start timestamp, in microseconds. + \param len Waiting duration, in microseconds; + */ + void waitForMicroseconds(uint32_t start, uint32_t len); + + /*! + \brief Function to reflect bits within a byte. + \param in The input to reflect. + \param bits Number of bits to reflect. + \return The reflected input. + */ + static uint32_t reflect(uint32_t in, uint8_t bits); + + #if RADIOLIB_DEBUG + /*! + \brief Function to dump data as hex into the debug port. + \param level RadioLib debug level, set to NULL to not print. + \param data Data to dump. + \param len Number of bytes to dump. + \param width Word width (1 for uint8_t, 2 for uint16_t, 4 for uint32_t). + \param be Print multi-byte data as big endian. Defaults to false. + */ + static void hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false); + + /*! + \brief Function to dump device registers as hex into the debug port. + \param level RadioLib debug level, set to NULL to not print. + \param start First address to dump. + \param len Number of bytes to dump. + */ + void regdump(const char* level, uint16_t start, size_t len); + #endif + + #if RADIOLIB_DEBUG and defined(RADIOLIB_BUILD_ARDUINO) + static size_t serialPrintf(const char* format, ...); + #endif + +#if !RADIOLIB_GODMODE + private: +#endif + uint32_t csPin = RADIOLIB_NC; + uint32_t irqPin = RADIOLIB_NC; + uint32_t rstPin = RADIOLIB_NC; + uint32_t gpioPin = RADIOLIB_NC; + + // RF switch pins and table + uint32_t rfSwitchPins[RFSWITCH_MAX_PINS] = { RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; + const RfSwitchMode_t *rfSwitchTable = nullptr; + + #if RADIOLIB_INTERRUPT_TIMING + uint32_t prevTimingLen = 0; + #endif +}; + +#endif diff --git a/lib/lib_rf/RadioLib/src/RadioLib.h b/lib/lib_rf/RadioLib/src/RadioLib.h new file mode 100644 index 000000000..0e3d7f6d1 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/RadioLib.h @@ -0,0 +1,165 @@ +#if !defined(_RADIOLIB_H) +#define _RADIOLIB_H + +/*! + \mainpage RadioLib Documentation + + Universal wireless communication library for Arduino. + + \par Currently Supported Wireless Modules and Protocols + - CC1101 FSK module + - RF69 FSK module + - Si443x FSK module + - SX126x LoRa/FSK module + - SX127x LoRa/FSK module + - SX128x LoRa/GFSK/BLE/FLRC module + - SX1231 FSK module + - PhysicalLayer protocols + - RTTY (RTTYClient) + - Morse Code (MorseClient) + - AX.25 (AX25Client) + - SSTV (SSTVClient) + - Hellschreiber (HellClient) + - 4-FSK (FSK4Client) + - APRS (APRSClient) + + \par Quick Links + Documentation for most common methods can be found in its reference page (see the list above).\n + Some methods (mainly configuration) are also overridden in derived classes, such as SX1272, SX1278, RFM96 etc. for SX127x.\n + \ref status_codes have their own page.\n + Some modules implement methods of one or more compatibility layers, loosely based on the ISO/OSI model: + - PhysicalLayer - FSK and LoRa radio modules + + \see https://github.com/jgromes/RadioLib + + \copyright Copyright (c) 2019 Jan Gromes +*/ + +#include "TypeDef.h" +#include "Module.h" + +#include "Hal.h" +#if defined(RADIOLIB_BUILD_ARDUINO) +#include "ArduinoHal.h" +#endif + + +// warnings are printed in this file since BuildOpt.h is compiled in multiple places + +// check God mode +#if RADIOLIB_GODMODE + #warning "God mode active, I hope it was intentional. Buckle up, lads." +#endif + +// print debug info +#if RADIOLIB_DEBUG + #define RADIOLIB_VALUE_TO_STRING(x) #x + #define RADIOLIB_VALUE(x) RADIOLIB_VALUE_TO_STRING(x) + #pragma message("\nRadioLib Debug Info\nVersion: \"" \ + RADIOLIB_VALUE(RADIOLIB_VERSION_MAJOR) "." \ + RADIOLIB_VALUE(RADIOLIB_VERSION_MINOR) "." \ + RADIOLIB_VALUE(RADIOLIB_VERSION_PATCH) "." \ + RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\"\n" \ + "Platform: " RADIOLIB_VALUE(RADIOLIB_PLATFORM) "\n" \ + "Compiled: " RADIOLIB_VALUE(__DATE__) " " RADIOLIB_VALUE(__TIME__) \ + ) +#endif + +// check unknown/unsupported platform +#if defined(RADIOLIB_UNKNOWN_PLATFORM) + #warning "RadioLib might not be compatible with this Arduino board - check supported platforms at https://github.com/jgromes/RadioLib!" +#endif + +// print warning for low-end platforms +#if defined(RADIOLIB_LOWEND_PLATFORM) + #warning "Low-end platform detected, stability issues are likely!" +#endif + +#include "modules/CC1101/CC1101.h" +#include "modules/LLCC68/LLCC68.h" +#include "modules/nRF24/nRF24.h" +#include "modules/RF69/RF69.h" +#include "modules/RFM2x/RFM22.h" +#include "modules/RFM2x/RFM23.h" +#include "modules/Si443x/Si4430.h" +#include "modules/Si443x/Si4431.h" +#include "modules/Si443x/Si4432.h" +#include "modules/SX123x/SX1231.h" +#include "modules/SX123x/SX1233.h" +#include "modules/SX126x/SX1261.h" +#include "modules/SX126x/SX1262.h" +#include "modules/SX126x/SX1268.h" +#include "modules/SX126x/STM32WLx.h" +#include "modules/SX127x/SX1272.h" +#include "modules/SX127x/SX1273.h" +#include "modules/SX127x/SX1276.h" +#include "modules/SX127x/SX1277.h" +#include "modules/SX127x/SX1278.h" +#include "modules/SX127x/SX1279.h" +#include "modules/SX128x/SX1280.h" +#include "modules/SX128x/SX1281.h" +#include "modules/SX128x/SX1282.h" + +// physical layer protocols +#include "protocols/PhysicalLayer/PhysicalLayer.h" +#include "protocols/AFSK/AFSK.h" +#include "protocols/AX25/AX25.h" +#include "protocols/Hellschreiber/Hellschreiber.h" +#include "protocols/Morse/Morse.h" +#include "protocols/Pager/Pager.h" +#include "protocols/RTTY/RTTY.h" +#include "protocols/SSTV/SSTV.h" +#include "protocols/FSK4/FSK4.h" +#include "protocols/APRS/APRS.h" +#include "protocols/ExternalRadio/ExternalRadio.h" +#include "protocols/Print/Print.h" +#include "protocols/BellModem/BellModem.h" +#include "protocols/LoRaWAN/LoRaWAN.h" + +// utilities +#include "utils/CRC.h" +#include "utils/Cryptography.h" + +// only create Radio class when using RadioShield +#if RADIOLIB_RADIOSHIELD + +// RadioShield pin definitions +#define RADIOSHIELD_CS_A 10 +#define RADIOSHIELD_IRQ_A 2 +#define RADIOSHIELD_RST_A 9 +#define RADIOSHIELD_GPIO_A 8 +#define RADIOSHIELD_CS_B 5 +#define RADIOSHIELD_IRQ_B 3 +#define RADIOSHIELD_RST_B 7 +#define RADIOSHIELD_GPIO_B 6 + +/*! + \class Radio + + \brief Library control object when using RadioShield. + Contains two pre-configured "modules", which correspond to the slots on shield. +*/ +class Radio { + public: + + Module* ModuleA; + Module* ModuleB; + + /*! + \brief Default constructor. Only used to set ModuleA and ModuleB configuration. + */ + Radio() { + ModuleA = new Module(RADIOSHIELD_CS_A, RADIOSHIELD_IRQ_A, RADIOSHIELD_RST_A, RADIOSHIELD_GPIO_A); + ModuleB = new Module(RADIOSHIELD_CS_B, RADIOSHIELD_IRQ_B, RADIOSHIELD_RST_B, RADIOSHIELD_GPIO_B); + } + +#if RADIOLIB_GODMODE + private: +#endif + +}; + +Radio RadioShield; +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/TypeDef.h b/lib/lib_rf/RadioLib/src/TypeDef.h new file mode 100644 index 000000000..818d99d59 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/TypeDef.h @@ -0,0 +1,565 @@ +#if !defined(_RADIOLIB_TYPES_H) +#define _RADIOLIB_TYPES_H + +// user build options may override the default +#include "BuildOptUser.h" +#include "BuildOpt.h" + +/*! + \defgroup config_shaping Data shaping filter values aliases. + + \{ +*/ + +/*! + \brief No shaping. +*/ +#define RADIOLIB_SHAPING_NONE (0x00) + +/*! + \brief Gaussian shaping filter, BT = 0.3 +*/ +#define RADIOLIB_SHAPING_0_3 (0x01) + +/*! + \brief Gaussian shaping filter, BT = 0.5 +*/ +#define RADIOLIB_SHAPING_0_5 (0x02) + +/*! + \brief Gaussian shaping filter, BT = 0.7 +*/ +#define RADIOLIB_SHAPING_0_7 (0x03) + +/*! + \brief Gaussian shaping filter, BT = 1.0 +*/ +#define RADIOLIB_SHAPING_1_0 (0x04) + +/*! + \} +*/ + +/*! + \defgroup config_encoding Encoding type aliases. + + \{ +*/ + +/*! + \brief Non-return to zero - no encoding. +*/ +#define RADIOLIB_ENCODING_NRZ (0x00) + +/*! + \brief Manchester encoding. +*/ +#define RADIOLIB_ENCODING_MANCHESTER (0x01) + +/*! + \brief Whitening. +*/ +#define RADIOLIB_ENCODING_WHITENING (0x02) + +/*! + \} +*/ + +/*! + \defgroup config_standby Standby mode type aliases. + + \{ +*/ + +/*! + \brief Default standby used by the module +*/ +#define RADIOLIB_STANDBY_DEFAULT (0x00) + +/*! + \brief Warm standby (e.g. crystal left running). +*/ +#define RADIOLIB_STANDBY_WARM (0x01) + +/*! + \brief Cold standby (e.g. only internal RC oscillator running). +*/ +#define RADIOLIB_STANDBY_COLD (0x02) + +/*! + \} +*/ + +/*! + \defgroup status_codes Status Codes + + \{ +*/ + +// common status codes + +/*! + \brief No error, method executed successfully. +*/ +#define RADIOLIB_ERR_NONE (0) + +/*! + \brief There was an unexpected, unknown error. If you see this, something went incredibly wrong. + Your Arduino may be possessed, contact your local exorcist to resolve this error. +*/ +#define RADIOLIB_ERR_UNKNOWN (-1) + +// SX127x/RFM9x status codes + +/*! + \brief Radio chip was not found during initialization. This can be caused by specifying wrong chip type in the constructor + (i.e. calling SX1272 constructor for SX1278 chip) or by a fault in your wiring (incorrect slave select pin). +*/ +#define RADIOLIB_ERR_CHIP_NOT_FOUND (-2) + +/*! + \brief Failed to allocate memory for temporary buffer. This can be cause by not enough RAM or by passing invalid pointer. +*/ +#define RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED (-3) + +/*! + \brief Packet supplied to transmission method was longer than limit. +*/ +#define RADIOLIB_ERR_PACKET_TOO_LONG (-4) + +/*! + \brief Timed out waiting for transmission finish. +*/ +#define RADIOLIB_ERR_TX_TIMEOUT (-5) + +/*! + \brief Timed out waiting for incoming transmission. +*/ +#define RADIOLIB_ERR_RX_TIMEOUT (-6) + +/*! + \brief The calculated and expected CRCs of received packet do not match. + This means that the packet was damaged during transmission and should be sent again. +*/ +#define RADIOLIB_ERR_CRC_MISMATCH (-7) + +/*! + \brief The supplied bandwidth value is invalid for this module. +*/ +#define RADIOLIB_ERR_INVALID_BANDWIDTH (-8) + +/*! + \brief The supplied spreading factor value is invalid for this module. +*/ +#define RADIOLIB_ERR_INVALID_SPREADING_FACTOR (-9) + +/*! + \brief The supplied coding rate value is invalid for this module. +*/ +#define RADIOLIB_ERR_INVALID_CODING_RATE (-10) + +/*! + \brief Internal only. +*/ +#define RADIOLIB_ERR_INVALID_BIT_RANGE (-11) + +/*! + \brief The supplied frequency value is invalid for this module. +*/ +#define RADIOLIB_ERR_INVALID_FREQUENCY (-12) + +/*! + \brief The supplied output power value is invalid for this module. +*/ +#define RADIOLIB_ERR_INVALID_OUTPUT_POWER (-13) + +/*! + \brief LoRa preamble was detected during channel activity detection. + This means that there is some LoRa device currently transmitting in your channel. +*/ +#define RADIOLIB_PREAMBLE_DETECTED (-14) + +/*! + \brief No LoRa preambles were detected during channel activity detection. Your channel is free. +*/ +#define RADIOLIB_CHANNEL_FREE (-15) + +/*! + \brief Real value in SPI register does not match the expected one. This can be caused by faulty SPI wiring. +*/ +#define RADIOLIB_ERR_SPI_WRITE_FAILED (-16) + +/*! + \brief The supplied current limit value is invalid. +*/ +#define RADIOLIB_ERR_INVALID_CURRENT_LIMIT (-17) + +/*! + \brief The supplied preamble length is invalid. +*/ +#define RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH (-18) + +/*! + \brief The supplied gain value is invalid. +*/ +#define RADIOLIB_ERR_INVALID_GAIN (-19) + +/*! + \brief User tried to execute modem-exclusive method on a wrong modem. + For example, this can happen when you try to change LoRa configuration when FSK modem is active. +*/ +#define RADIOLIB_ERR_WRONG_MODEM (-20) + +/*! + \brief The supplied number of RSSI samples is invalid. +*/ +#define RADIOLIB_ERR_INVALID_NUM_SAMPLES (-21) + +/*! + \brief The supplied RSSI offset is invalid. +*/ +#define RADIOLIB_ERR_INVALID_RSSI_OFFSET (-22) + +/*! + \brief The supplied encoding is invalid. +*/ +#define RADIOLIB_ERR_INVALID_ENCODING (-23) + +/*! + \brief LoRa packet header has been damaged. +*/ +#define RADIOLIB_ERR_LORA_HEADER_DAMAGED (-24) + +/*! + \brief The requested functionality is not supported for this device +*/ +#define RADIOLIB_ERR_UNSUPPORTED (-25) + +/*! + \brief The specified DIO pin does not exist on this device +*/ +#define RADIOLIB_ERR_INVALID_DIO_PIN (-26) + +/*! + \brief The supplied RSSI threshold is invalid. +*/ +#define RADIOLIB_ERR_INVALID_RSSI_THRESHOLD (-27) + +/*! + \brief A `NULL` pointer has been encountered. If you see this, there may be a potential security vulnerability. +*/ +#define RADIOLIB_ERR_NULL_POINTER (-28) + +// RF69-specific status codes + +/*! + \brief The supplied bit rate value is invalid. +*/ +#define RADIOLIB_ERR_INVALID_BIT_RATE (-101) + +/*! + \brief The supplied frequency deviation value is invalid. +*/ +#define RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION (-102) + +/*! + \brief The supplied bit rate to bandwidth ratio is invalid. See the module datasheet for more information. +*/ +#define RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO (-103) + +/*! + \brief The supplied receiver bandwidth value is invalid. +*/ +#define RADIOLIB_ERR_INVALID_RX_BANDWIDTH (-104) + +/*! + \brief The supplied FSK sync word is invalid. +*/ +#define RADIOLIB_ERR_INVALID_SYNC_WORD (-105) + +/*! + \brief The supplied FSK data shaping option is invalid. +*/ +#define RADIOLIB_ERR_INVALID_DATA_SHAPING (-106) + +/*! + \brief The current modulation is invalid for the requested operation. +*/ +#define RADIOLIB_ERR_INVALID_MODULATION (-107) + +/*! + \brief Supplied Peak type is invalid. +*/ +#define RADIOLIB_ERR_INVALID_OOK_RSSI_PEAK_TYPE (-108) + +// APRS status codes + +/*! + \brief Supplied APRS symbol is invalid. +*/ +#define RADIOLIB_ERR_INVALID_SYMBOL (-201) + +/*! + \brief Mic-E Telemetry is invalid. +*/ +#define RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY (-202) + +/*! + \brief Mic-E Telemetry length is invalid (only 0, 2 or 5 is allowed). +*/ +#define RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY_LENGTH (-203) + +/*! + \brief Mic-E message cannot contain both telemetry and status text. +*/ +#define RADIOLIB_ERR_MIC_E_TELEMETRY_STATUS (-204) + +// SSDV status codes + +/*! + \brief SSDV mode is invalid. +*/ +#define RADIOLIB_ERR_INVALID_SSDV_MODE (-301) + +/*! + \brief Image size is invalid. +*/ +#define RADIOLIB_ERR_INVALID_IMAGE_SIZE (-302) + +/*! + \brief Image quality is invalid. +*/ +#define RADIOLIB_ERR_INVALID_IMAGE_QUALITY (-303) + +/*! + \brief Image subsampling is invalid. +*/ +#define RADIOLIB_ERR_INVALID_SUBSAMPLING (-304) + +// RTTY status codes + +/*! + \brief Supplied RTTY frequency shift is invalid for this module. +*/ +#define RADIOLIB_ERR_INVALID_RTTY_SHIFT (-401) + +/*! + \brief Supplied RTTY encoding is invalid. +*/ +#define RADIOLIB_ERR_UNSUPPORTED_ENCODING (-402) + +// nRF24-specific status codes + +/*! + \brief Supplied data rate is invalid. +*/ +#define RADIOLIB_ERR_INVALID_DATA_RATE (-501) + +/*! + \brief Supplied address width is invalid. +*/ +#define RADIOLIB_ERR_INVALID_ADDRESS_WIDTH (-502) + +/*! + \brief Supplied data pipe number is invalid. +*/ +#define RADIOLIB_ERR_INVALID_PIPE_NUMBER (-503) + +/*! + \brief ACK packet from destination module was not received within 15 retries. +*/ +#define RADIOLIB_ERR_ACK_NOT_RECEIVED (-504) + +// CC1101-specific status codes + +/*! + \brief Supplied number of broadcast addresses is invalid. +*/ +#define RADIOLIB_ERR_INVALID_NUM_BROAD_ADDRS (-601) + +// SX126x-specific status codes + +/*! + \brief Supplied CRC configuration is invalid. +*/ +#define RADIOLIB_ERR_INVALID_CRC_CONFIGURATION (-701) + +/*! + \brief Detected LoRa transmission while scanning channel. +*/ +#define RADIOLIB_LORA_DETECTED (-702) + +/*! + \brief Supplied TCXO reference voltage is invalid. +*/ +#define RADIOLIB_ERR_INVALID_TCXO_VOLTAGE (-703) + +/*! + \brief Bit rate / bandwidth / frequency deviation ratio is invalid. See SX126x datasheet for details. +*/ +#define RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS (-704) + +/*! + \brief SX126x timed out while waiting for complete SPI command. +*/ +#define RADIOLIB_ERR_SPI_CMD_TIMEOUT (-705) + +/*! + \brief SX126x received invalid SPI command. +*/ +#define RADIOLIB_ERR_SPI_CMD_INVALID (-706) + +/*! + \brief SX126x failed to execute SPI command. + Often this means that the module is trying to use TCXO while + XTAL is connected (or vice versa). Make sure your crystal setup + (e.g. TCXO reference voltage) matches your hardware by setting + "tcxoVoltage" to 0 when using XTAL module, or to appropriate value + when using TCXO module. +*/ +#define RADIOLIB_ERR_SPI_CMD_FAILED (-707) + +/*! + \brief The supplied sleep period is invalid. + + The specified sleep period is shorter than the time necessary to sleep and wake the hardware + including TCXO delay, or longer than the maximum possible +*/ +#define RADIOLIB_ERR_INVALID_SLEEP_PERIOD (-708) + +/*! + \brief The supplied Rx period is invalid. + + The specified Rx period is shorter or longer than the hardware can handle. +*/ +#define RADIOLIB_ERR_INVALID_RX_PERIOD (-709) + +// AX.25-specific status codes + +/*! + \brief The provided callsign is invalid. + + The specified callsign is longer than 6 ASCII characters. +*/ +#define RADIOLIB_ERR_INVALID_CALLSIGN (-801) + +/*! + \brief The provided repeater configuration is invalid. + + The specified number of repeaters does not match number of repeater IDs or their callsigns. +*/ +#define RADIOLIB_ERR_INVALID_NUM_REPEATERS (-802) + +/*! + \brief One of the provided repeater callsigns is invalid. + + The specified callsign is longer than 6 ASCII characters. +*/ +#define RADIOLIB_ERR_INVALID_REPEATER_CALLSIGN (-803) + +// SX128x-specific status codes + +/*! + \brief Timed out waiting for ranging exchange finish. +*/ +#define RADIOLIB_ERR_RANGING_TIMEOUT (-901) + +// Pager-specific status codes + +/*! + \brief The provided payload data configuration is invalid. +*/ +#define RADIOLIB_ERR_INVALID_PAYLOAD (-1001) + +/*! + \brief The requested address was not found in the received data. +*/ +#define RADIOLIB_ERR_ADDRESS_NOT_FOUND (-1002) + +/*! + \brief The function code is invalid. 2 Bits only. +*/ +#define RADIOLIB_ERR_INVALID_FUNCTION (-1003) + +// LoRaWAN-specific status codes + +/*! + \brief Unable to restore existing LoRaWAN session because this node did not join any network yet. +*/ +#define RADIOLIB_ERR_NETWORK_NOT_JOINED (-1101) + +/*! + \brief Malformed downlink packet received from network server. +*/ +#define RADIOLIB_ERR_DOWNLINK_MALFORMED (-1102) + +/*! + \brief Network server requested switch to unsupported LoRaWAN revision. +*/ +#define RADIOLIB_ERR_INVALID_REVISION (-1103) + +/*! + \brief Invalid LoRaWAN uplink port requested by user. +*/ +#define RADIOLIB_ERR_INVALID_PORT (-1104) + +/*! + \brief User did not enable downlink in time. +*/ +#define RADIOLIB_ERR_NO_RX_WINDOW (-1105) + +/*! + \brief No valid channel for the currently active LoRaWAN band was found. +*/ +#define RADIOLIB_ERR_INVALID_CHANNEL (-1106) + +/*! + \brief Invalid LoRaWAN MAC command ID. +*/ +#define RADIOLIB_ERR_INVALID_CID (-1107) + +/*! + \brief User requested to start uplink while still inside RX window or under dutycycle. +*/ +#define RADIOLIB_ERR_UPLINK_UNAVAILABLE (-1108) + +/*! + \brief Unable to push new MAC command because the queue is full. +*/ +#define RADIOLIB_ERR_COMMAND_QUEUE_FULL (-1109) + +/*! + \brief Unable to delete MAC command because it was not found in the queue. +*/ +#define RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND (-1110) + +/*! + \brief Unable to join network because JoinNonce is not higher than saved value. +*/ +#define RADIOLIB_ERR_JOIN_NONCE_INVALID (-1111) + +/*! + \brief Received downlink Network frame counter is invalid (lower than last heard value). +*/ +#define RADIOLIB_ERR_N_FCNT_DOWN_INVALID (-1112) + +/*! + \brief Received downlink Application frame counter is invalid (lower than last heard value). +*/ +#define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1113) + +/*! + \brief Uplink payload length at this datarate exceeds the active dwell time limitations. +*/ +#define RADIOLIB_ERR_DWELL_TIME_EXCEEDED (-1114) + +/*! + \brief The buffer integrity check did not match the supplied checksum value. +*/ +#define RADIOLIB_ERR_CHECKSUM_MISMATCH (-1115) + +/*! + \} +*/ + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.cpp b/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.cpp new file mode 100644 index 000000000..447e0420e --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.cpp @@ -0,0 +1,1119 @@ +#include "CC1101.h" +#include +#if !RADIOLIB_EXCLUDE_CC1101 + +CC1101::CC1101(Module* module) : PhysicalLayer(RADIOLIB_CC1101_FREQUENCY_STEP_SIZE, RADIOLIB_CC1101_MAX_PACKET_LENGTH) { + this->mod = module; +} + +int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t pwr, uint8_t preambleLength) { + // set module properties + this->mod->SPIreadCommand = RADIOLIB_CC1101_CMD_READ; + this->mod->SPIwriteCommand = RADIOLIB_CC1101_CMD_WRITE; + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + + // try to find the CC1101 chip + uint8_t i = 0; + bool flagFound = false; + while((i < 10) && !flagFound) { + int16_t version = getChipVersion(); + if((version == RADIOLIB_CC1101_VERSION_CURRENT) || (version == RADIOLIB_CC1101_VERSION_LEGACY) || (version == RADIOLIB_CC1101_VERSION_CLONE)) { + flagFound = true; + } else { + RADIOLIB_DEBUG_BASIC_PRINTLN("CC1101 not found! (%d of 10 tries) RADIOLIB_CC1101_REG_VERSION == 0x%04X, expected 0x0004/0x0014", i + 1, version); + this->mod->hal->delay(10); + i++; + } + } + + if(!flagFound) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No CC1101 found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } else { + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tCC1101"); + } + + // configure settings not accessible by API + int16_t state = config(); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + // configure bitrate + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + // configure default RX bandwidth + state = setRxBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + // configure default frequency deviation + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + // configure default TX output power + state = setOutputPower(pwr); + RADIOLIB_ASSERT(state); + + // set default packet length mode + state = variablePacketLengthMode(); + RADIOLIB_ASSERT(state); + + // configure default preamble length + state = setPreambleLength(preambleLength, preambleLength - 4); + RADIOLIB_ASSERT(state); + + // set default data shaping + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + + // set default encoding + state = setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + + // set default sync word + uint8_t sw[RADIOLIB_CC1101_DEFAULT_SW_LEN] = RADIOLIB_CC1101_DEFAULT_SW; + state = setSyncWord(sw[0], sw[1], 0, false); + RADIOLIB_ASSERT(state); + + // flush FIFOs + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); + + return(state); +} + +void CC1101::reset() { + // this is the manual power-on-reset sequence + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + this->mod->hal->delayMicroseconds(5); + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); + this->mod->hal->delayMicroseconds(40); + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + this->mod->hal->delay(10); + SPIsendCommand(RADIOLIB_CC1101_CMD_RESET); +} + +int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { + // calculate timeout (5ms + 500 % of expected time-on-air) + uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (this->bitRate * 1000.0)) * 5000000.0); + + // start transmission + int16_t state = startTransmit(data, len, addr); + RADIOLIB_ASSERT(state); + + // wait for transmission start or timeout + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + + if(this->mod->hal->micros() - start > timeout) { + finishTransmit(); + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + + // wait for transmission end or timeout + start = this->mod->hal->micros(); + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + + if(this->mod->hal->micros() - start > timeout) { + finishTransmit(); + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + + return(finishTransmit()); +} + +int16_t CC1101::receive(uint8_t* data, size_t len) { + // calculate timeout (500 ms + 400 full max-length packets at current bit rate) + uint32_t timeout = 500000 + (1.0/(this->bitRate*1000.0))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0); + + // start reception + int16_t state = startReceive(); + RADIOLIB_ASSERT(state); + + // wait for packet start or timeout + uint32_t start = this->mod->hal->micros(); + while(this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + + if(this->mod->hal->micros() - start > timeout) { + standby(); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } + + // wait for packet end or timeout + start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + + if(this->mod->hal->micros() - start > timeout) { + standby(); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } + + // read packet data + return(readData(data, len)); +} + +int16_t CC1101::standby() { + // set idle mode + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); + + // wait until idle is reached + uint32_t start = this->mod->hal->millis(); + while(SPIgetRegValue(RADIOLIB_CC1101_REG_MARCSTATE, 4, 0) != RADIOLIB_CC1101_MARC_STATE_IDLE) { + mod->hal->yield(); + if(this->mod->hal->millis() - start > 100) { + // timeout, this should really not happen + return(RADIOLIB_ERR_UNKNOWN); + } + }; + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + return(RADIOLIB_ERR_NONE); +} + +int16_t CC1101::standby(uint8_t mode) { + (void)mode; + return(standby()); +} + +int16_t CC1101::transmitDirect(uint32_t frf) { + return transmitDirect(true, frf); +} + +int16_t CC1101::transmitDirectAsync(uint32_t frf) { + return transmitDirect(false, frf); +} + +int16_t CC1101::transmitDirect(bool sync, uint32_t frf) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_TX); + + // user requested to start transmitting immediately (required for RTTY) + if(frf != 0) { + SPIwriteRegister(RADIOLIB_CC1101_REG_FREQ2, (frf & 0xFF0000) >> 16); + SPIwriteRegister(RADIOLIB_CC1101_REG_FREQ1, (frf & 0x00FF00) >> 8); + SPIwriteRegister(RADIOLIB_CC1101_REG_FREQ0, frf & 0x0000FF); + + SPIsendCommand(RADIOLIB_CC1101_CMD_TX); + return(RADIOLIB_ERR_NONE); + } + + // activate direct mode + int16_t state = directMode(sync); + RADIOLIB_ASSERT(state); + + // start transmitting + SPIsendCommand(RADIOLIB_CC1101_CMD_TX); + return(state); +} + +int16_t CC1101::receiveDirect() { + return receiveDirect(true); +} + +int16_t CC1101::receiveDirectAsync() { + return receiveDirect(false); +} + +int16_t CC1101::receiveDirect(bool sync) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // activate direct mode + int16_t state = directMode(sync); + RADIOLIB_ASSERT(state); + + // start receiving + SPIsendCommand(RADIOLIB_CC1101_CMD_RX); + return(RADIOLIB_ERR_NONE); +} + +int16_t CC1101::packetMode() { + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, RADIOLIB_CC1101_CRC_AUTOFLUSH_OFF | RADIOLIB_CC1101_APPEND_STATUS_ON | RADIOLIB_CC1101_ADR_CHK_NONE, 3, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_WHITE_DATA_OFF | RADIOLIB_CC1101_PKT_FORMAT_NORMAL, 6, 4); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_ON | this->packetLengthConfig, 2, 0); + return(state); +} + +void CC1101::setGdo0Action(void (*func)(void), uint32_t dir) { + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, dir); +} + +void CC1101::clearGdo0Action() { + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); +} + +void CC1101::setPacketReceivedAction(void (*func)(void)) { + this->setGdo0Action(func, this->mod->hal->GpioInterruptRising); +} + +void CC1101::clearPacketReceivedAction() { + this->clearGdo0Action(); +} + +void CC1101::setPacketSentAction(void (*func)(void)) { + this->setGdo2Action(func, this->mod->hal->GpioInterruptFalling); +} + +void CC1101::clearPacketSentAction() { + this->clearGdo2Action(); +} + +void CC1101::setGdo2Action(void (*func)(void), uint32_t dir) { + if(this->mod->getGpio() == RADIOLIB_NC) { + return; + } + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()), func, dir); +} + +void CC1101::clearGdo2Action() { + if(this->mod->getGpio() == RADIOLIB_NC) { + return; + } + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio())); +} + +int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { + // check packet length + if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set mode to standby + standby(); + + // flush Tx FIFO + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); + + // set GDO0 mapping + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 5, 0); + RADIOLIB_ASSERT(state); + + // optionally write packet length + if(this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { + SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, len); + } + + // check address filtering + uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0); + if(filter != RADIOLIB_CC1101_ADR_CHK_NONE) { + SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, addr); + } + + // fill the FIFO + SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, len); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_TX); + + // set mode to transmit + SPIsendCommand(RADIOLIB_CC1101_CMD_TX); + + return(state); +} + +int16_t CC1101::finishTransmit() { + // set mode to standby to disable transmitter/RF switch + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // flush Tx FIFO + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); + + return(state); +} + +int16_t CC1101::startReceive() { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // flush Rx FIFO + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + + // set GDO0 mapping + // GDO0 is de-asserted at packet end, hence it is inverted here + state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDO0_INV | RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 6, 0); + RADIOLIB_ASSERT(state); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // set mode to receive + SPIsendCommand(RADIOLIB_CC1101_CMD_RX); + + return(state); +} + +int16_t CC1101::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)timeout; + (void)irqFlags; + (void)irqMask; + (void)len; + return(startReceive()); +} + +int16_t CC1101::readData(uint8_t* data, size_t len) { + // get packet length + size_t length = getPacketLength(); + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + length = len; + } + + // check address filtering + uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0); + if(filter != RADIOLIB_CC1101_ADR_CHK_NONE) { + SPIreadRegister(RADIOLIB_CC1101_REG_FIFO); + } + + // read packet data + SPIreadRegisterBurst(RADIOLIB_CC1101_REG_FIFO, length, data); + + // check if status bytes are enabled (default: RADIOLIB_CC1101_APPEND_STATUS_ON) + bool isAppendStatus = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 2, 2) == RADIOLIB_CC1101_APPEND_STATUS_ON; + + // If status byte is enabled at least 2 bytes (2 status bytes + any following packet) will remain in FIFO. + int16_t state = RADIOLIB_ERR_NONE; + if (isAppendStatus) { + // read RSSI byte + this->rawRSSI = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO); + + // read LQI and CRC byte + uint8_t val = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO); + this->rawLQI = val & 0x7F; + + // check CRC + if(this->crcOn && (val & RADIOLIB_CC1101_CRC_OK) == RADIOLIB_CC1101_CRC_ERROR) { + this->packetLengthQueried = false; + state = RADIOLIB_ERR_CRC_MISMATCH; + } + } + + // clear internal flag so getPacketLength can return the new packet length + this->packetLengthQueried = false; + + // Flush then standby according to RXOFF_MODE (default: RADIOLIB_CC1101_RXOFF_IDLE) + if(SPIgetRegValue(RADIOLIB_CC1101_REG_MCSM1, 3, 2) == RADIOLIB_CC1101_RXOFF_IDLE) { + + // set mode to standby + standby(); + + // flush Rx FIFO + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + } + + return(state); +} + +int16_t CC1101::setFrequency(float freq) { + // check allowed frequency range + if(!(((freq > 300.0) && (freq < 348.0)) || + ((freq > 387.0) && (freq < 464.0)) || + ((freq > 779.0) && (freq < 928.0)))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY); + } + + // set mode to standby + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); + + //set carrier frequency + uint32_t base = 1; + uint32_t FRF = (freq * (base << 16)) / 26.0; + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ2, (FRF & 0xFF0000) >> 16, 7, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ1, (FRF & 0x00FF00) >> 8, 7, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ0, FRF & 0x0000FF, 7, 0); + + if(state == RADIOLIB_ERR_NONE) { + this->frequency = freq; + } + + // Update the TX power accordingly to new freq. (PA values depend on chosen freq) + return(setOutputPower(this->power)); +} + +int16_t CC1101::setBitRate(float br) { + RADIOLIB_CHECK_RANGE(br, 0.025, 600.0, RADIOLIB_ERR_INVALID_BIT_RATE); + + // set mode to standby + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); + + // calculate exponent and mantissa values + uint8_t e = 0; + uint8_t m = 0; + getExpMant(br * 1000.0, 256, 28, 14, e, m); + + // set bit rate value + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, e, 3, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG3, m); + if(state == RADIOLIB_ERR_NONE) { + this->bitRate = br; + } + return(state); +} + +int16_t CC1101::setRxBandwidth(float rxBw) { + RADIOLIB_CHECK_RANGE(rxBw, 58.0, 812.0, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); + + // set mode to standby + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); + + // calculate exponent and mantissa values + for(int8_t e = 3; e >= 0; e--) { + for(int8_t m = 3; m >= 0; m --) { + float point = (RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0)/(8 * (m + 4) * ((uint32_t)1 << e)); + if(fabs((rxBw * 1000.0) - point) <= 1000) { + // set Rx channel filter bandwidth + return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4)); + } + + } + } + + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); +} + +int16_t CC1101::setFrequencyDeviation(float freqDev) { + // set frequency deviation to lowest available setting (required for digimodes) + float newFreqDev = freqDev; + if(freqDev < 0.0) { + newFreqDev = 1.587; + } + + // check range unless 0 (special value) + if (freqDev != 0) { + RADIOLIB_CHECK_RANGE(newFreqDev, 1.587, 380.8, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + } + + // set mode to standby + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); + + // calculate exponent and mantissa values + uint8_t e = 0; + uint8_t m = 0; + getExpMant(newFreqDev * 1000.0, 8, 17, 7, e, m); + + // set frequency deviation value + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_DEVIATN, (e << 4), 6, 4); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_DEVIATN, m, 2, 0); + + return(state); +} + +int16_t CC1101::getFrequencyDeviation(float *freqDev) { + if (freqDev == NULL) { + return(RADIOLIB_ERR_NULL_POINTER); + } + + // if ASK/OOK, deviation makes no sense + if (this->modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK) { + *freqDev = 0.0; + + return(RADIOLIB_ERR_NONE); + } + + // get exponent and mantissa values from registers + uint8_t e = (uint8_t)(SPIgetRegValue(RADIOLIB_CC1101_REG_DEVIATN, 6, 4) >> 4); + uint8_t m = (uint8_t)SPIgetRegValue(RADIOLIB_CC1101_REG_DEVIATN, 2, 0); + + // calculate frequency deviation (pag. 79 of the CC1101 datasheet): + // + // freqDev = (fXosc / 2^17) * (8 + m) * 2^e + // + *freqDev = (1000.0 / (uint32_t(1) << 17)) - (8 + m) * (uint32_t(1) << e); + + return(RADIOLIB_ERR_NONE); +} + +int16_t CC1101::setOutputPower(int8_t pwr) { + // round to the known frequency settings + uint8_t f; + if(this->frequency < 374.0) { + // 315 MHz + f = 0; + } else if(this->frequency < 650.5) { + // 434 MHz + f = 1; + } else if(this->frequency < 891.5) { + // 868 MHz + f = 2; + } else { + // 915 MHz + f = 3; + } + + // get raw power setting + uint8_t paTable[8][4] = {{0x12, 0x12, 0x03, 0x03}, + {0x0D, 0x0E, 0x0F, 0x0E}, + {0x1C, 0x1D, 0x1E, 0x1E}, + {0x34, 0x34, 0x27, 0x27}, + {0x51, 0x60, 0x50, 0x8E}, + {0x85, 0x84, 0x81, 0xCD}, + {0xCB, 0xC8, 0xCB, 0xC7}, + {0xC2, 0xC0, 0xC2, 0xC0}}; + + uint8_t powerRaw; + switch(pwr) { + case -30: + powerRaw = paTable[0][f]; + break; + case -20: + powerRaw = paTable[1][f]; + break; + case -15: + powerRaw = paTable[2][f]; + break; + case -10: + powerRaw = paTable[3][f]; + break; + case 0: + powerRaw = paTable[4][f]; + break; + case 5: + powerRaw = paTable[5][f]; + break; + case 7: + powerRaw = paTable[6][f]; + break; + case 10: + powerRaw = paTable[7][f]; + break; + default: + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + + // store the value + this->power = pwr; + + if(this->modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK){ + // Amplitude modulation: + // PA_TABLE[0] is the power to be used when transmitting a 0 (no power) + // PA_TABLE[1] is the power to be used when transmitting a 1 (full power) + + uint8_t paValues[2] = {0x00, powerRaw}; + SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_PATABLE, paValues, 2); + return(RADIOLIB_ERR_NONE); + + } else { + // Freq modulation: + // PA_TABLE[0] is the power to be used when transmitting. + return(SPIsetRegValue(RADIOLIB_CC1101_REG_PATABLE, powerRaw)); + } +} + +int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, bool requireCarrierSense) { + if((maxErrBits > 1) || (len != 2)) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + + // sync word must not contain value 0x00 + for(uint8_t i = 0; i < len; i++) { + if(syncWord[i] == 0x00) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + } + + // enable sync word filtering + int16_t state = enableSyncWordFiltering(maxErrBits, requireCarrierSense); + RADIOLIB_ASSERT(state); + + // set sync word register + state = SPIsetRegValue(RADIOLIB_CC1101_REG_SYNC1, syncWord[0]); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_SYNC0, syncWord[1]); + + return(state); +} + +int16_t CC1101::setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits, bool requireCarrierSense) { + uint8_t syncWord[] = { syncH, syncL }; + return(setSyncWord(syncWord, sizeof(syncWord), maxErrBits, requireCarrierSense)); +} + +int16_t CC1101::setPreambleLength(uint8_t preambleLength, uint8_t qualityThreshold) { + // check allowed values + uint8_t value; + switch(preambleLength) { + case 16: + value = RADIOLIB_CC1101_NUM_PREAMBLE_2; + break; + case 24: + value = RADIOLIB_CC1101_NUM_PREAMBLE_3; + break; + case 32: + value = RADIOLIB_CC1101_NUM_PREAMBLE_4; + break; + case 48: + value = RADIOLIB_CC1101_NUM_PREAMBLE_6; + break; + case 64: + value = RADIOLIB_CC1101_NUM_PREAMBLE_8; + break; + case 96: + value = RADIOLIB_CC1101_NUM_PREAMBLE_12; + break; + case 128: + value = RADIOLIB_CC1101_NUM_PREAMBLE_16; + break; + case 192: + value = RADIOLIB_CC1101_NUM_PREAMBLE_24; + break; + default: + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); + } + + // set preabmble quality threshold and the actual length + uint8_t pqt = qualityThreshold/4; + if(pqt > 7) { + pqt = 7; + } + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, pqt << 5, 7, 5); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG1, value, 6, 4); + return(state); +} + +int16_t CC1101::setNodeAddress(uint8_t nodeAddr, uint8_t numBroadcastAddrs) { + RADIOLIB_CHECK_RANGE(numBroadcastAddrs, 1, 2, RADIOLIB_ERR_INVALID_NUM_BROAD_ADDRS); + + // enable address filtering + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, numBroadcastAddrs + 0x01, 1, 0); + RADIOLIB_ASSERT(state); + + // set node address + return(SPIsetRegValue(RADIOLIB_CC1101_REG_ADDR, nodeAddr)); +} + +int16_t CC1101::disableAddressFiltering() { + // disable address filtering + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, RADIOLIB_CC1101_ADR_CHK_NONE, 1, 0); + RADIOLIB_ASSERT(state); + + // set node address to default (0x00) + return(SPIsetRegValue(RADIOLIB_CC1101_REG_ADDR, 0x00)); +} + + +int16_t CC1101::setOOK(bool enableOOK) { + // Change modulation + if(enableOOK) { + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK, 6, 4); + RADIOLIB_ASSERT(state); + + // PA_TABLE[0] is (by default) the power value used when transmitting a "0". + // Set PA_TABLE[1] to be used when transmitting a "1". + state = SPIsetRegValue(RADIOLIB_CC1101_REG_FREND0, 1, 2, 0); + RADIOLIB_ASSERT(state); + + // update current modulation + this->modulation = RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK; + } else { + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MOD_FORMAT_2_FSK, 6, 4); + RADIOLIB_ASSERT(state); + + // Reset FREND0 to default value. + state = SPIsetRegValue(RADIOLIB_CC1101_REG_FREND0, 0, 2, 0); + RADIOLIB_ASSERT(state); + + // update current modulation + this->modulation = RADIOLIB_CC1101_MOD_FORMAT_2_FSK; + } + + // Update PA_TABLE values according to the new this->modulation. + return(setOutputPower(this->power)); +} + +float CC1101::getRSSI() { + float rssi; + + if (this->directModeEnabled) { + if(this->rawRSSI >= 128) { + rssi = (((float)this->rawRSSI - 256.0)/2.0) - 74.0; + } else { + rssi = (((float)this->rawRSSI)/2.0) - 74.0; + } + } else { + uint8_t rawRssi = SPIreadRegister(RADIOLIB_CC1101_REG_RSSI); + if (rawRssi >= 128) + { + rssi = ((rawRssi - 256) / 2) - 74; + } + else + { + rssi = (rawRssi / 2) - 74; + } + } + return(rssi); +} + +uint8_t CC1101::getLQI() const { + return(this->rawLQI); +} + +size_t CC1101::getPacketLength(bool update) { + if(!this->packetLengthQueried && update) { + if(this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { + this->packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_FIFO); + } else { + this->packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_PKTLEN); + } + + this->packetLengthQueried = true; + } + + return(this->packetLength); +} + +int16_t CC1101::fixedPacketLengthMode(uint8_t len) { + if(len == 0) { + // infinite packet mode + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_LENGTH_CONFIG_INFINITE, 1, 0); + RADIOLIB_ASSERT(state); + } + + return(setPacketMode(RADIOLIB_CC1101_LENGTH_CONFIG_FIXED, len)); +} + +int16_t CC1101::variablePacketLengthMode(uint8_t maxLen) { + return(setPacketMode(RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE, maxLen)); +} + +int16_t CC1101::enableSyncWordFiltering(uint8_t maxErrBits, bool requireCarrierSense) { + int16_t state = RADIOLIB_ERR_NONE; + + switch(maxErrBits) { + case 0: + // in 16 bit sync word, expect all 16 bits + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_16_16_THR : RADIOLIB_CC1101_SYNC_MODE_16_16), 2, 0); + break; + case 1: + // in 16 bit sync word, expect at least 15 bits + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_15_16_THR : RADIOLIB_CC1101_SYNC_MODE_15_16), 2, 0); + break; + default: + state = RADIOLIB_ERR_INVALID_SYNC_WORD; + break; + } + return(state); +} + +int16_t CC1101::disableSyncWordFiltering(bool requireCarrierSense) { + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_NONE_THR : RADIOLIB_CC1101_SYNC_MODE_NONE), 2, 0); + return(state); +} + +int16_t CC1101::setCrcFiltering(bool enable) { + this->crcOn = enable; + + if (this->crcOn == true) { + return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_ON, 2, 2)); + } else { + return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_OFF, 2, 2)); + } +} + +int16_t CC1101::setPromiscuousMode(bool enable) { + int16_t state = RADIOLIB_ERR_NONE; + + if(this->promiscuous == enable) { + return(state); + } + + if(enable) { + // disable sync word filtering and insertion + // this also disables preamble + state = disableSyncWordFiltering(); + RADIOLIB_ASSERT(state); + + // disable CRC filtering + state = setCrcFiltering(false); + } else { + state = setPreambleLength(RADIOLIB_CC1101_DEFAULT_PREAMBLELEN, RADIOLIB_CC1101_DEFAULT_PREAMBLELEN/4); + RADIOLIB_ASSERT(state); + + // enable sync word filtering and insertion + state = enableSyncWordFiltering(); + RADIOLIB_ASSERT(state); + + // enable CRC filtering + state = setCrcFiltering(true); + } + + this->promiscuous = enable; + + return(state); +} + +bool CC1101::getPromiscuousMode() { + return (this->promiscuous); +} + +int16_t CC1101::setDataShaping(uint8_t sh) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set data shaping + switch(sh) { + case RADIOLIB_SHAPING_NONE: + state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MOD_FORMAT_2_FSK, 6, 4); + break; + case RADIOLIB_SHAPING_0_5: + state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MOD_FORMAT_GFSK, 6, 4); + break; + default: + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); + } + return(state); +} + +int16_t CC1101::setEncoding(uint8_t encoding) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set encoding + switch(encoding) { + case RADIOLIB_ENCODING_NRZ: + state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MANCHESTER_EN_OFF, 3, 3); + RADIOLIB_ASSERT(state); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_WHITE_DATA_OFF, 6, 6)); + case RADIOLIB_ENCODING_MANCHESTER: + state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MANCHESTER_EN_ON, 3, 3); + RADIOLIB_ASSERT(state); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_WHITE_DATA_OFF, 6, 6)); + case RADIOLIB_ENCODING_WHITENING: + state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MANCHESTER_EN_OFF, 3, 3); + RADIOLIB_ASSERT(state); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_WHITE_DATA_ON, 6, 6)); + default: + return(RADIOLIB_ERR_INVALID_ENCODING); + } +} + +void CC1101::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { + this->mod->setRfSwitchPins(rxEn, txEn); +} + +void CC1101::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + this->mod->setRfSwitchTable(pins, table); +} + +uint8_t CC1101::randomByte() { + // set mode to Rx + SPIsendCommand(RADIOLIB_CC1101_CMD_RX); + + // wait a bit for the RSSI reading to stabilise + this->mod->hal->delay(10); + + // read RSSI value 8 times, always keep just the least significant bit + uint8_t randByte = 0x00; + for(uint8_t i = 0; i < 8; i++) { + randByte |= ((SPIreadRegister(RADIOLIB_CC1101_REG_RSSI) & 0x01) << i); + } + + // set mode to standby + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); + + return(randByte); +} + +int16_t CC1101::getChipVersion() { + return(SPIgetRegValue(RADIOLIB_CC1101_REG_VERSION)); +} + +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE +void CC1101::setDirectAction(void (*func)(void)) { + setGdo0Action(func, this->mod->hal->GpioInterruptRising); +} + +void CC1101::readBit(uint32_t pin) { + updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin)); +} +#endif + +int16_t CC1101::setDIOMapping(uint32_t pin, uint32_t value) { + if(pin > 2) { + return(RADIOLIB_ERR_INVALID_DIO_PIN); + } + + return(SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0 - pin, value)); +} + +int16_t CC1101::config() { + // Reset the radio. Registers may be dirty from previous usage. + reset(); + + // Wait a ridiculous amount of time to be sure radio is ready. + this->mod->hal->delay(150); + + standby(); + + // enable automatic frequency synthesizer calibration and disable pin control + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MCSM0, RADIOLIB_CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MCSM0, RADIOLIB_CC1101_PIN_CTRL_OFF, 1, 1); + RADIOLIB_ASSERT(state); + + // set GDOs to Hi-Z so that it doesn't output clock on startup (might confuse GDO0 action) + state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_HIGH_Z, 5, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_HIGH_Z, 5, 0); + RADIOLIB_ASSERT(state); + + // set packet mode + state = packetMode(); + + return(state); +} + +int16_t CC1101::directMode(bool sync) { + // set mode to standby + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); + + int16_t state = 0; + this->directModeEnabled = sync; + if(sync) { + // set GDO0 and GDO2 mapping + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_CLOCK , 5, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SERIAL_DATA_SYNC , 5, 0); + + // set continuous mode + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_PKT_FORMAT_SYNCHRONOUS, 5, 4); + } else { + // set GDO0 mapping + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_DATA_ASYNC , 5, 0); + + // set asynchronous continuous mode + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_PKT_FORMAT_ASYNCHRONOUS, 5, 4); + } + + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_LENGTH_CONFIG_INFINITE, 1, 0); + return(state); +} + +void CC1101::getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant) { + // get table origin point (exp = 0, mant = 0) + float origin = (mantOffset * RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0)/((uint32_t)1 << divExp); + + // iterate over possible exponent values + for(int8_t e = expMax; e >= 0; e--) { + // get table column start value (exp = e, mant = 0); + float intervalStart = ((uint32_t)1 << e) * origin; + + // check if target value is in this column + if(target >= intervalStart) { + // save exponent value + exp = e; + + // calculate size of step between table rows + float stepSize = intervalStart/(float)mantOffset; + + // get target point position (exp = e, mant = m) + mant = ((target - intervalStart) / stepSize); + + // we only need the first match, terminate + return; + } + } +} + +int16_t CC1101::setPacketMode(uint8_t mode, uint16_t len) { + // check length + if (len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set PKTCTRL0.LENGTH_CONFIG + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, mode, 1, 0); + RADIOLIB_ASSERT(state); + + // set length to register + state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTLEN, len); + RADIOLIB_ASSERT(state); + + // update the cached values + this->packetLength = len; + this->packetLengthConfig = mode; + return(state); +} + +Module* CC1101::getMod() { + return(this->mod); +} + +int16_t CC1101::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { + // status registers require special command + if((reg > RADIOLIB_CC1101_REG_TEST0) && (reg < RADIOLIB_CC1101_REG_PATABLE)) { + reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; + } + + return(this->mod->SPIgetRegValue(reg, msb, lsb)); +} + +int16_t CC1101::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval) { + // status registers require special command + if((reg > RADIOLIB_CC1101_REG_TEST0) && (reg < RADIOLIB_CC1101_REG_PATABLE)) { + reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; + } + + return(this->mod->SPIsetRegValue(reg, value, msb, lsb, checkInterval)); +} + +void CC1101::SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes) { + this->mod->SPIreadRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, numBytes, inBytes); +} + +uint8_t CC1101::SPIreadRegister(uint8_t reg) { + // status registers require special command + if((reg > RADIOLIB_CC1101_REG_TEST0) && (reg < RADIOLIB_CC1101_REG_PATABLE)) { + reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; + } + + return(this->mod->SPIreadRegister(reg)); +} + +void CC1101::SPIwriteRegister(uint8_t reg, uint8_t data) { + // status registers require special command + if((reg > RADIOLIB_CC1101_REG_TEST0) && (reg < RADIOLIB_CC1101_REG_PATABLE)) { + reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; + } + + return(this->mod->SPIwriteRegister(reg, data)); +} + +void CC1101::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len) { + this->mod->SPIwriteRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, data, len); +} + +void CC1101::SPIsendCommand(uint8_t cmd) { + // pull NSS low + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + + // start transfer + this->mod->hal->spiBeginTransaction(); + + // send the command byte + uint8_t status = 0; + this->mod->hal->spiTransfer(&cmd, 1, &status); + + // stop transfer + this->mod->hal->spiEndTransaction(); + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); + RADIOLIB_DEBUG_SPI_PRINTLN("CMD\tW\t%02X\t%02X", cmd, status); + (void)status; +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.h b/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.h new file mode 100644 index 000000000..9d2254a4c --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/CC1101/CC1101.h @@ -0,0 +1,989 @@ +#if !defined(_RADIOLIB_CC1101_H) && !RADIOLIB_EXCLUDE_CC1101 +#define _RADIOLIB_CC1101_H + +#include "../../TypeDef.h" +#include "../../Module.h" + +#include "../../protocols/PhysicalLayer/PhysicalLayer.h" + +// CC1101 physical layer properties +#define RADIOLIB_CC1101_FREQUENCY_STEP_SIZE 396.7285156 +#define RADIOLIB_CC1101_MAX_PACKET_LENGTH 63 +#define RADIOLIB_CC1101_CRYSTAL_FREQ 26.0 +#define RADIOLIB_CC1101_DIV_EXPONENT 16 + +// CC1101 SPI commands +#define RADIOLIB_CC1101_CMD_READ 0b10000000 +#define RADIOLIB_CC1101_CMD_WRITE 0b00000000 +#define RADIOLIB_CC1101_CMD_BURST 0b01000000 +#define RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG 0b01000000 +#define RADIOLIB_CC1101_CMD_FIFO_RX 0b10000000 +#define RADIOLIB_CC1101_CMD_FIFO_TX 0b00000000 +#define RADIOLIB_CC1101_CMD_RESET 0x30 +#define RADIOLIB_CC1101_CMD_FSTXON 0x31 +#define RADIOLIB_CC1101_CMD_XOFF 0x32 +#define RADIOLIB_CC1101_CMD_CAL 0x33 +#define RADIOLIB_CC1101_CMD_RX 0x34 +#define RADIOLIB_CC1101_CMD_TX 0x35 +#define RADIOLIB_CC1101_CMD_IDLE 0x36 +#define RADIOLIB_CC1101_CMD_WOR 0x38 +#define RADIOLIB_CC1101_CMD_POWER_DOWN 0x39 +#define RADIOLIB_CC1101_CMD_FLUSH_RX 0x3A +#define RADIOLIB_CC1101_CMD_FLUSH_TX 0x3B +#define RADIOLIB_CC1101_CMD_WOR_RESET 0x3C +#define RADIOLIB_CC1101_CMD_NOP 0x3D + +// CC1101 register map +#define RADIOLIB_CC1101_REG_IOCFG2 0x00 +#define RADIOLIB_CC1101_REG_IOCFG1 0x01 +#define RADIOLIB_CC1101_REG_IOCFG0 0x02 +#define RADIOLIB_CC1101_REG_FIFOTHR 0x03 +#define RADIOLIB_CC1101_REG_SYNC1 0x04 +#define RADIOLIB_CC1101_REG_SYNC0 0x05 +#define RADIOLIB_CC1101_REG_PKTLEN 0x06 +#define RADIOLIB_CC1101_REG_PKTCTRL1 0x07 +#define RADIOLIB_CC1101_REG_PKTCTRL0 0x08 +#define RADIOLIB_CC1101_REG_ADDR 0x09 +#define RADIOLIB_CC1101_REG_CHANNR 0x0A +#define RADIOLIB_CC1101_REG_FSCTRL1 0x0B +#define RADIOLIB_CC1101_REG_FSCTRL0 0x0C +#define RADIOLIB_CC1101_REG_FREQ2 0x0D +#define RADIOLIB_CC1101_REG_FREQ1 0x0E +#define RADIOLIB_CC1101_REG_FREQ0 0x0F +#define RADIOLIB_CC1101_REG_MDMCFG4 0x10 +#define RADIOLIB_CC1101_REG_MDMCFG3 0x11 +#define RADIOLIB_CC1101_REG_MDMCFG2 0x12 +#define RADIOLIB_CC1101_REG_MDMCFG1 0x13 +#define RADIOLIB_CC1101_REG_MDMCFG0 0x14 +#define RADIOLIB_CC1101_REG_DEVIATN 0x15 +#define RADIOLIB_CC1101_REG_MCSM2 0x16 +#define RADIOLIB_CC1101_REG_MCSM1 0x17 +#define RADIOLIB_CC1101_REG_MCSM0 0x18 +#define RADIOLIB_CC1101_REG_FOCCFG 0x19 +#define RADIOLIB_CC1101_REG_BSCFG 0x1A +#define RADIOLIB_CC1101_REG_AGCCTRL2 0x1B +#define RADIOLIB_CC1101_REG_AGCCTRL1 0x1C +#define RADIOLIB_CC1101_REG_AGCCTRL0 0x1D +#define RADIOLIB_CC1101_REG_WOREVT1 0x1E +#define RADIOLIB_CC1101_REG_WOREVT0 0x1F +#define RADIOLIB_CC1101_REG_WORCTRL 0x20 +#define RADIOLIB_CC1101_REG_FREND1 0x21 +#define RADIOLIB_CC1101_REG_FREND0 0x22 +#define RADIOLIB_CC1101_REG_FSCAL3 0x23 +#define RADIOLIB_CC1101_REG_FSCAL2 0x24 +#define RADIOLIB_CC1101_REG_FSCAL1 0x25 +#define RADIOLIB_CC1101_REG_FSCAL0 0x26 +#define RADIOLIB_CC1101_REG_RCCTRL1 0x27 +#define RADIOLIB_CC1101_REG_RCCTRL0 0x28 +#define RADIOLIB_CC1101_REG_FSTEST 0x29 +#define RADIOLIB_CC1101_REG_PTEST 0x2A +#define RADIOLIB_CC1101_REG_AGCTEST 0x2B +#define RADIOLIB_CC1101_REG_TEST2 0x2C +#define RADIOLIB_CC1101_REG_TEST1 0x2D +#define RADIOLIB_CC1101_REG_TEST0 0x2E +#define RADIOLIB_CC1101_REG_PARTNUM 0x30 +#define RADIOLIB_CC1101_REG_VERSION 0x31 +#define RADIOLIB_CC1101_REG_FREQEST 0x32 +#define RADIOLIB_CC1101_REG_LQI 0x33 +#define RADIOLIB_CC1101_REG_RSSI 0x34 +#define RADIOLIB_CC1101_REG_MARCSTATE 0x35 +#define RADIOLIB_CC1101_REG_WORTIME1 0x36 +#define RADIOLIB_CC1101_REG_WORTIME0 0x37 +#define RADIOLIB_CC1101_REG_PKTSTATUS 0x38 +#define RADIOLIB_CC1101_REG_VCO_VC_DAC 0x39 +#define RADIOLIB_CC1101_REG_TXBYTES 0x3A +#define RADIOLIB_CC1101_REG_RXBYTES 0x3B +#define RADIOLIB_CC1101_REG_RCCTRL1_STATUS 0x3C +#define RADIOLIB_CC1101_REG_RCCTRL0_STATUS 0x3D +#define RADIOLIB_CC1101_REG_PATABLE 0x3E +#define RADIOLIB_CC1101_REG_FIFO 0x3F + +// status byte (returned during SPI transactions) MSB LSB DESCRIPTION +#define RADIOLIB_CC1101_STATUS_CHIP_READY 0b00000000 // 7 7 chip ready +#define RADIOLIB_CC1101_STATUS_CHIP_NOT_READY 0b10000000 // 7 7 chip not ready (power/crystal not stable) +#define RADIOLIB_CC1101_STATUS_IDLE 0b00000000 // 6 4 idle +#define RADIOLIB_CC1101_STATUS_RX 0b00010000 // 6 4 Rx +#define RADIOLIB_CC1101_STATUS_TX 0b00100000 // 6 4 Tx +#define RADIOLIB_CC1101_STATUS_FSTXON 0b00110000 // 6 4 Fast Tx ready +#define RADIOLIB_CC1101_STATUS_CALIBRATE 0b01000000 // 6 4 synthesizer calibration running +#define RADIOLIB_CC1101_STATUS_SETTLING 0b01010000 // 6 4 PLL settling +#define RADIOLIB_CC1101_STATUS_RXFIFO_OVERFLOW 0b01100000 // 6 4 Rx FIFO overflow +#define RADIOLIB_CC1101_STATUS_TXFIFO_UNDERFLOW 0b01110000 // 6 4 Tx FIFO underflow + +// RADIOLIB_CC1101_REG_IOCFG2 +#define RADIOLIB_CC1101_GDO2_NORM 0b00000000 // 6 6 GDO2 output: active high (default) +#define RADIOLIB_CC1101_GDO2_INV 0b01000000 // 6 6 active low + +// RADIOLIB_CC1101_REG_IOCFG1 +#define RADIOLIB_CC1101_GDO_DS_LOW 0b00000000 // 7 7 GDOx output drive strength: low (default) +#define RADIOLIB_CC1101_GDO_DS_HIGH 0b10000000 // 7 7 high +#define RADIOLIB_CC1101_GDO1_NORM 0b00000000 // 6 6 GDO1 output: active high (default) +#define RADIOLIB_CC1101_GDO1_INV 0b01000000 // 6 6 active low + +// RADIOLIB_CC1101_REG_IOCFG0 +#define RADIOLIB_CC1101_GDO0_TEMP_SENSOR_OFF 0b00000000 // 7 7 analog temperature sensor output: disabled (default) +#define RADIOLIB_CC1101_GDO0_TEMP_SENSOR_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_CC1101_GDO0_NORM 0b00000000 // 6 6 GDO0 output: active high (default) +#define RADIOLIB_CC1101_GDO0_INV 0b01000000 // 6 6 active low + +// RADIOLIB_CC1101_REG_IOCFG2 + REG_IOCFG1 + REG_IOCFG0 +#define RADIOLIB_CC1101_GDOX_RX_FIFO_FULL 0x00 // 5 0 Rx FIFO full or above threshold +#define RADIOLIB_CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END 0x01 // 5 0 Rx FIFO full or above threshold or reached packet end +#define RADIOLIB_CC1101_GDOX_TX_FIFO_ABOVE_THR 0x02 // 5 0 Tx FIFO above threshold +#define RADIOLIB_CC1101_GDOX_TX_FIFO_FULL 0x03 // 5 0 Tx FIFO full +#define RADIOLIB_CC1101_GDOX_RX_FIFO_OVERFLOW 0x04 // 5 0 Rx FIFO overflowed +#define RADIOLIB_CC1101_GDOX_TX_FIFO_UNDERFLOW 0x05 // 5 0 Tx FIFO underflowed +#define RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED 0x06 // 5 0 sync word was sent or packet was received +#define RADIOLIB_CC1101_GDOX_PKT_RECEIVED_CRC_OK 0x07 // 5 0 packet received and CRC check passed +#define RADIOLIB_CC1101_GDOX_PREAMBLE_QUALITY_REACHED 0x08 // 5 0 received preamble quality is above threshold +#define RADIOLIB_CC1101_GDOX_CHANNEL_CLEAR 0x09 // 5 0 RSSI level below threshold (channel is clear) +#define RADIOLIB_CC1101_GDOX_PLL_LOCKED 0x0A // 5 0 PLL is locked +#define RADIOLIB_CC1101_GDOX_SERIAL_CLOCK 0x0B // 5 0 serial data clock +#define RADIOLIB_CC1101_GDOX_SERIAL_DATA_SYNC 0x0C // 5 0 serial data output in: synchronous mode +#define RADIOLIB_CC1101_GDOX_SERIAL_DATA_ASYNC 0x0D // 5 0 asynchronous mode +#define RADIOLIB_CC1101_GDOX_CARRIER_SENSE 0x0E // 5 0 RSSI above threshold +#define RADIOLIB_CC1101_GDOX_CRC_OK 0x0F // 5 0 CRC check passed +#define RADIOLIB_CC1101_GDOX_RX_HARD_DATA1 0x16 // 5 0 direct access to demodulated data +#define RADIOLIB_CC1101_GDOX_RX_HARD_DATA0 0x17 // 5 0 direct access to demodulated data +#define RADIOLIB_CC1101_GDOX_PA_PD 0x1B // 5 0 power amplifier circuit is powered down +#define RADIOLIB_CC1101_GDOX_LNA_PD 0x1C // 5 0 low-noise amplifier circuit is powered down +#define RADIOLIB_CC1101_GDOX_RX_SYMBOL_TICK 0x1D // 5 0 direct access to symbol tick of received data +#define RADIOLIB_CC1101_GDOX_WOR_EVNT0 0x24 // 5 0 wake-on-radio event 0 +#define RADIOLIB_CC1101_GDOX_WOR_EVNT1 0x25 // 5 0 wake-on-radio event 1 +#define RADIOLIB_CC1101_GDOX_CLK_256 0x26 // 5 0 256 Hz clock +#define RADIOLIB_CC1101_GDOX_CLK_32K 0x27 // 5 0 32 kHz clock +#define RADIOLIB_CC1101_GDOX_CHIP_RDYN 0x29 // 5 0 (default for GDO2) +#define RADIOLIB_CC1101_GDOX_XOSC_STABLE 0x2B // 5 0 +#define RADIOLIB_CC1101_GDOX_HIGH_Z 0x2E // 5 0 high impedance state (default for GDO1) +#define RADIOLIB_CC1101_GDOX_HW_TO_0 0x2F // 5 0 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_1 0x30 // 5 0 crystal oscillator clock: f = f(XOSC)/1 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_1_5 0x31 // 5 0 f = f(XOSC)/1.5 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_2 0x32 // 5 0 f = f(XOSC)/2 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_3 0x33 // 5 0 f = f(XOSC)/3 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_4 0x34 // 5 0 f = f(XOSC)/4 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_6 0x35 // 5 0 f = f(XOSC)/6 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_8 0x36 // 5 0 f = f(XOSC)/8 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_12 0x37 // 5 0 f = f(XOSC)/12 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_16 0x38 // 5 0 f = f(XOSC)/16 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_24 0x39 // 5 0 f = f(XOSC)/24 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_32 0x3A // 5 0 f = f(XOSC)/32 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_48 0x3B // 5 0 f = f(XOSC)/48 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_64 0x3C // 5 0 f = f(XOSC)/64 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_96 0x3D // 5 0 f = f(XOSC)/96 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_128 0x3E // 5 0 f = f(XOSC)/128 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_192 0x3F // 5 0 f = f(XOSC)/192 (default for GDO0) + +// RADIOLIB_CC1101_REG_FIFOTHR +#define RADIOLIB_CC1101_ADC_RETENTION_OFF 0b00000000 // 6 6 do not retain ADC settings in sleep mode (default) +#define RADIOLIB_CC1101_ADC_RETENTION_ON 0b01000000 // 6 6 retain ADC settings in sleep mode +#define RADIOLIB_CC1101_RX_ATTEN_0_DB 0b00000000 // 5 4 Rx attenuation: 0 dB (default) +#define RADIOLIB_CC1101_RX_ATTEN_6_DB 0b00010000 // 5 4 6 dB +#define RADIOLIB_CC1101_RX_ATTEN_12_DB 0b00100000 // 5 4 12 dB +#define RADIOLIB_CC1101_RX_ATTEN_18_DB 0b00110000 // 5 4 18 dB +#define RADIOLIB_CC1101_FIFO_THR_TX_61_RX_4 0b00000000 // 3 0 TX fifo threshold: 61, RX fifo threshold: 4 +#define RADIOLIB_CC1101_FIFO_THR_TX_33_RX_32 0b00000111 // 3 0 TX fifo threshold: 33, RX fifo threshold: 32 +#define RADIOLIB_CC1101_FIFO_THRESH_TX 33 +#define RADIOLIB_CC1101_FIFO_THRESH_RX 32 + +// RADIOLIB_CC1101_REG_SYNC1 +#define RADIOLIB_CC1101_SYNC_WORD_MSB 0xD3 // 7 0 sync word MSB + +// RADIOLIB_CC1101_REG_SYNC0 +#define RADIOLIB_CC1101_SYNC_WORD_LSB 0x91 // 7 0 sync word LSB + +// RADIOLIB_CC1101_REG_PKTLEN +#define RADIOLIB_CC1101_PACKET_LENGTH 0xFF // 7 0 packet length in bytes + +// RADIOLIB_CC1101_REG_PKTCTRL1 +#define RADIOLIB_CC1101_PQT 0x00 // 7 5 preamble quality threshold +#define RADIOLIB_CC1101_CRC_AUTOFLUSH_OFF 0b00000000 // 3 3 automatic Rx FIFO flush on CRC check fail: disabled (default) +#define RADIOLIB_CC1101_CRC_AUTOFLUSH_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_CC1101_APPEND_STATUS_OFF 0b00000000 // 2 2 append 2 status bytes to packet: disabled +#define RADIOLIB_CC1101_APPEND_STATUS_ON 0b00000100 // 2 2 enabled (default) +#define RADIOLIB_CC1101_ADR_CHK_NONE 0b00000000 // 1 0 address check: none (default) +#define RADIOLIB_CC1101_ADR_CHK_NO_BROADCAST 0b00000001 // 1 0 without broadcast +#define RADIOLIB_CC1101_ADR_CHK_SINGLE_BROADCAST 0b00000010 // 1 0 broadcast address 0x00 +#define RADIOLIB_CC1101_ADR_CHK_DOUBLE_BROADCAST 0b00000011 // 1 0 broadcast addresses 0x00 and 0xFF + +// RADIOLIB_CC1101_REG_PKTCTRL0 +#define RADIOLIB_CC1101_WHITE_DATA_OFF 0b00000000 // 6 6 data whitening: disabled +#define RADIOLIB_CC1101_WHITE_DATA_ON 0b01000000 // 6 6 enabled (default) +#define RADIOLIB_CC1101_PKT_FORMAT_NORMAL 0b00000000 // 5 4 packet format: normal (FIFOs) +#define RADIOLIB_CC1101_PKT_FORMAT_SYNCHRONOUS 0b00010000 // 5 4 synchronous serial +#define RADIOLIB_CC1101_PKT_FORMAT_RANDOM 0b00100000 // 5 4 random transmissions +#define RADIOLIB_CC1101_PKT_FORMAT_ASYNCHRONOUS 0b00110000 // 5 4 asynchronous serial +#define RADIOLIB_CC1101_CRC_OFF 0b00000000 // 2 2 CRC disabled +#define RADIOLIB_CC1101_CRC_ON 0b00000100 // 2 2 CRC enabled (default) +#define RADIOLIB_CC1101_LENGTH_CONFIG_FIXED 0b00000000 // 1 0 packet length: fixed +#define RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE 0b00000001 // 1 0 variable (default) +#define RADIOLIB_CC1101_LENGTH_CONFIG_INFINITE 0b00000010 // 1 0 infinite + +// RADIOLIB_CC1101_REG_ADDR +#define RADIOLIB_CC1101_DEVICE_ADDR 0x00 // 7 0 device address + +// RADIOLIB_CC1101_REG_CHANNR +#define RADIOLIB_CC1101_CHAN 0x00 // 7 0 channel number + +// RADIOLIB_CC1101_REG_FSCTRL1 +#define RADIOLIB_CC1101_FREQ_IF 0x0F // 4 0 IF frequency setting; f_IF = (f(XOSC) / 2^10) * CC1101_FREQ_IF + +// CC1101_REG_FSCTRL0 +#define RADIOLIB_CC1101_FREQOFF 0x00 // 7 0 base frequency offset (2s-compliment) + +// RADIOLIB_CC1101_REG_FREQ2 + REG_FREQ1 + REG_FREQ0 +#define RADIOLIB_CC1101_FREQ_MSB 0x1E // 5 0 base frequency setting: f_carrier = (f(XOSC) / 2^16) * FREQ +#define RADIOLIB_CC1101_FREQ_MID 0xC4 // 7 0 where f(XOSC) = 26 MHz +#define RADIOLIB_CC1101_FREQ_LSB 0xEC // 7 0 FREQ = 3-byte value of FREQ registers + +// RADIOLIB_CC1101_REG_MDMCFG4 +#define RADIOLIB_CC1101_CHANBW_E 0b10000000 // 7 6 channel bandwidth: BW_channel = f(XOSC) / (8 * (4 + CHANBW_M)*2^CHANBW_E) [Hz] +#define RADIOLIB_CC1101_CHANBW_M 0b00000000 // 5 4 default value for 26 MHz crystal: 203 125 Hz +#define RADIOLIB_CC1101_DRATE_E 0x0C // 3 0 symbol rate: R_data = (((256 + DRATE_M) * 2^DRATE_E) / 2^28) * f(XOSC) [Baud] + +// RADIOLIB_CC1101_REG_MDMCFG3 +#define RADIOLIB_CC1101_DRATE_M 0x22 // 7 0 default value for 26 MHz crystal: 115 051 Baud + +// RADIOLIB_CC1101_REG_MDMCFG2 +#define RADIOLIB_CC1101_DEM_DCFILT_OFF 0b10000000 // 7 7 digital DC filter: disabled +#define RADIOLIB_CC1101_DEM_DCFILT_ON 0b00000000 // 7 7 enabled - only for data rates above 250 kBaud (default) +#define RADIOLIB_CC1101_MOD_FORMAT_2_FSK 0b00000000 // 6 4 modulation format: 2-FSK (default) +#define RADIOLIB_CC1101_MOD_FORMAT_GFSK 0b00010000 // 6 4 GFSK +#define RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK 0b00110000 // 6 4 ASK/OOK +#define RADIOLIB_CC1101_MOD_FORMAT_4_FSK 0b01000000 // 6 4 4-FSK +#define RADIOLIB_CC1101_MOD_FORMAT_MFSK 0b01110000 // 6 4 MFSK - only for data rates above 26 kBaud +#define RADIOLIB_CC1101_MANCHESTER_EN_OFF 0b00000000 // 3 3 Manchester encoding: disabled (default) +#define RADIOLIB_CC1101_MANCHESTER_EN_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_CC1101_SYNC_MODE_NONE 0b00000000 // 2 0 synchronization: no preamble/sync +#define RADIOLIB_CC1101_SYNC_MODE_15_16 0b00000001 // 2 0 15/16 sync word bits +#define RADIOLIB_CC1101_SYNC_MODE_16_16 0b00000010 // 2 0 16/16 sync word bits (default) +#define RADIOLIB_CC1101_SYNC_MODE_30_32 0b00000011 // 2 0 30/32 sync word bits +#define RADIOLIB_CC1101_SYNC_MODE_NONE_THR 0b00000100 // 2 0 no preamble sync, carrier sense above threshold +#define RADIOLIB_CC1101_SYNC_MODE_15_16_THR 0b00000101 // 2 0 15/16 sync word bits, carrier sense above threshold +#define RADIOLIB_CC1101_SYNC_MODE_16_16_THR 0b00000110 // 2 0 16/16 sync word bits, carrier sense above threshold +#define RADIOLIB_CC1101_SYNC_MODE_30_32_THR 0b00000111 // 2 0 30/32 sync word bits, carrier sense above threshold + +// RADIOLIB_CC1101_REG_MDMCFG1 +#define RADIOLIB_CC1101_FEC_OFF 0b00000000 // 7 7 forward error correction: disabled (default) +#define RADIOLIB_CC1101_FEC_ON 0b10000000 // 7 7 enabled - only for fixed packet length +#define RADIOLIB_CC1101_NUM_PREAMBLE_2 0b00000000 // 6 4 number of preamble bytes: 2 +#define RADIOLIB_CC1101_NUM_PREAMBLE_3 0b00010000 // 6 4 3 +#define RADIOLIB_CC1101_NUM_PREAMBLE_4 0b00100000 // 6 4 4 (default) +#define RADIOLIB_CC1101_NUM_PREAMBLE_6 0b00110000 // 6 4 6 +#define RADIOLIB_CC1101_NUM_PREAMBLE_8 0b01000000 // 6 4 8 +#define RADIOLIB_CC1101_NUM_PREAMBLE_12 0b01010000 // 6 4 12 +#define RADIOLIB_CC1101_NUM_PREAMBLE_16 0b01100000 // 6 4 16 +#define RADIOLIB_CC1101_NUM_PREAMBLE_24 0b01110000 // 6 4 24 +#define RADIOLIB_CC1101_CHANSPC_E 0x02 // 1 0 channel spacing: df_channel = (f(XOSC) / 2^18) * (256 + CHANSPC_M) * 2^CHANSPC_E [Hz] + +// RADIOLIB_CC1101_REG_MDMCFG0 +#define RADIOLIB_CC1101_CHANSPC_M 0xF8 // 7 0 default value for 26 MHz crystal: 199 951 kHz + +// RADIOLIB_CC1101_REG_DEVIATN +#define RADIOLIB_CC1101_DEVIATION_E 0b01000000 // 6 4 frequency deviation: f_dev = (f(XOSC) / 2^17) * (8 + DEVIATION_M) * 2^DEVIATION_E [Hz] +#define RADIOLIB_CC1101_DEVIATION_M 0b00000111 // 2 0 default value for 26 MHz crystal: +- 47 607 Hz +#define RADIOLIB_CC1101_MSK_PHASE_CHANGE_PERIOD 0x07 // 2 0 phase change symbol period fraction: 1 / (MSK_PHASE_CHANGE_PERIOD + 1) + +// RADIOLIB_CC1101_REG_MCSM2 +#define RADIOLIB_CC1101_RX_TIMEOUT_RSSI_OFF 0b00000000 // 4 4 Rx timeout based on RSSI value: disabled (default) +#define RADIOLIB_CC1101_RX_TIMEOUT_RSSI_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_CC1101_RX_TIMEOUT_QUAL_OFF 0b00000000 // 3 3 check for sync word on Rx timeout +#define RADIOLIB_CC1101_RX_TIMEOUT_QUAL_ON 0b00001000 // 3 3 check for PQI set on Rx timeout +#define RADIOLIB_CC1101_RX_TIMEOUT_OFF 0b00000111 // 2 0 Rx timeout: disabled (default) +#define RADIOLIB_CC1101_RX_TIMEOUT_MAX 0b00000000 // 2 0 max value (actual value depends on WOR_RES, EVENT0 and f(XOSC)) + +// RADIOLIB_CC1101_REG_MCSM1 +#define RADIOLIB_CC1101_CCA_MODE_ALWAYS 0b00000000 // 5 4 clear channel indication: always +#define RADIOLIB_CC1101_CCA_MODE_RSSI_THR 0b00010000 // 5 4 RSSI below threshold +#define RADIOLIB_CC1101_CCA_MODE_RX_PKT 0b00100000 // 5 4 unless receiving packet +#define RADIOLIB_CC1101_CCA_MODE_RSSI_THR_RX_PKT 0b00110000 // 5 4 RSSI below threshold unless receiving packet (default) +#define RADIOLIB_CC1101_RXOFF_IDLE 0b00000000 // 3 2 next mode after packet reception: idle (default) +#define RADIOLIB_CC1101_RXOFF_FSTXON 0b00000100 // 3 2 FSTxOn +#define RADIOLIB_CC1101_RXOFF_TX 0b00001000 // 3 2 Tx +#define RADIOLIB_CC1101_RXOFF_RX 0b00001100 // 3 2 Rx +#define RADIOLIB_CC1101_TXOFF_IDLE 0b00000000 // 1 0 next mode after packet transmission: idle (default) +#define RADIOLIB_CC1101_TXOFF_FSTXON 0b00000001 // 1 0 FSTxOn +#define RADIOLIB_CC1101_TXOFF_TX 0b00000010 // 1 0 Tx +#define RADIOLIB_CC1101_TXOFF_RX 0b00000011 // 1 0 Rx + +// RADIOLIB_CC1101_REG_MCSM0 +#define RADIOLIB_CC1101_FS_AUTOCAL_NEVER 0b00000000 // 5 4 automatic calibration: never (default) +#define RADIOLIB_CC1101_FS_AUTOCAL_IDLE_TO_RXTX 0b00010000 // 5 4 every transition from idle to Rx/Tx +#define RADIOLIB_CC1101_FS_AUTOCAL_RXTX_TO_IDLE 0b00100000 // 5 4 every transition from Rx/Tx to idle +#define RADIOLIB_CC1101_FS_AUTOCAL_RXTX_TO_IDLE_4TH 0b00110000 // 5 4 every 4th transition from Rx/Tx to idle +#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_1 0b00000000 // 3 2 number of counter expirations before CHP_RDYN goes low: 1 (default) +#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_16 0b00000100 // 3 2 16 +#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_64 0b00001000 // 3 2 64 +#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_256 0b00001100 // 3 2 256 +#define RADIOLIB_CC1101_PIN_CTRL_OFF 0b00000000 // 1 1 pin radio control: disabled (default) +#define RADIOLIB_CC1101_PIN_CTRL_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_CC1101_XOSC_FORCE_OFF 0b00000000 // 0 0 do not force XOSC to remain on in sleep (default) +#define RADIOLIB_CC1101_XOSC_FORCE_ON 0b00000001 // 0 0 force XOSC to remain on in sleep + +// RADIOLIB_CC1101_REG_FOCCFG +#define RADIOLIB_CC1101_FOC_BS_CS_GATE_OFF 0b00000000 // 5 5 do not freeze frequency compensation until CS goes high +#define RADIOLIB_CC1101_FOC_BS_CS_GATE_ON 0b00100000 // 5 5 freeze frequency compensation until CS goes high (default) +#define RADIOLIB_CC1101_FOC_PRE_K 0b00000000 // 4 3 frequency compensation loop gain before sync word: K +#define RADIOLIB_CC1101_FOC_PRE_2K 0b00001000 // 4 3 2K +#define RADIOLIB_CC1101_FOC_PRE_3K 0b00010000 // 4 3 3K (default) +#define RADIOLIB_CC1101_FOC_PRE_4K 0b00011000 // 4 3 4K +#define RADIOLIB_CC1101_FOC_POST_K 0b00000000 // 2 2 frequency compensation loop gain after sync word: same as FOC_PRE +#define RADIOLIB_CC1101_FOC_POST_K_2 0b00000100 // 2 2 K/2 (default) +#define RADIOLIB_CC1101_FOC_LIMIT_NO_COMPENSATION 0b00000000 // 1 0 frequency compensation saturation point: no compensation - required for ASK/OOK +#define RADIOLIB_CC1101_FOC_LIMIT_BW_CHAN_8 0b00000001 // 1 0 +- BW_chan/8 +#define RADIOLIB_CC1101_FOC_LIMIT_BW_CHAN_4 0b00000010 // 1 0 +- BW_chan/4 (default) +#define RADIOLIB_CC1101_FOC_LIMIT_BW_CHAN_2 0b00000011 // 1 0 +- BW_chan/2 + +// RADIOLIB_CC1101_REG_BSCFG +#define RADIOLIB_CC1101_BS_PRE_KI 0b00000000 // 7 6 clock recovery integral gain before sync word: Ki +#define RADIOLIB_CC1101_BS_PRE_2KI 0b01000000 // 7 6 2Ki (default) +#define RADIOLIB_CC1101_BS_PRE_3KI 0b10000000 // 7 6 3Ki +#define RADIOLIB_CC1101_BS_PRE_4KI 0b11000000 // 7 6 4Ki +#define RADIOLIB_CC1101_BS_PRE_KP 0b00000000 // 5 4 clock recovery proportional gain before sync word: Kp +#define RADIOLIB_CC1101_BS_PRE_2KP 0b00010000 // 5 4 2Kp +#define RADIOLIB_CC1101_BS_PRE_3KP 0b00100000 // 5 4 3Kp (default) +#define RADIOLIB_CC1101_BS_PRE_4KP 0b00110000 // 5 4 4Kp +#define RADIOLIB_CC1101_BS_POST_KI 0b00000000 // 3 3 clock recovery integral gain after sync word: same as BS_PRE +#define RADIOLIB_CC1101_BS_POST_KI_2 0b00001000 // 3 3 Ki/2 (default) +#define RADIOLIB_CC1101_BS_POST_KP 0b00000000 // 2 2 clock recovery proportional gain after sync word: same as BS_PRE +#define RADIOLIB_CC1101_BS_POST_KP_1 0b00000100 // 2 2 Kp (default) +#define RADIOLIB_CC1101_BS_LIMIT_NO_COMPENSATION 0b00000000 // 1 0 data rate compensation saturation point: no compensation +#define RADIOLIB_CC1101_BS_LIMIT_3_125 0b00000001 // 1 0 +- 3.125 % +#define RADIOLIB_CC1101_BS_LIMIT_6_25 0b00000010 // 1 0 +- 6.25 % +#define RADIOLIB_CC1101_BS_LIMIT_12_5 0b00000011 // 1 0 +- 12.5 % + +// RADIOLIB_CC1101_REG_AGCCTRL2 +#define RADIOLIB_CC1101_MAX_DVGA_GAIN_0 0b00000000 // 7 6 reduce maximum available DVGA gain: no reduction (default) +#define RADIOLIB_CC1101_MAX_DVGA_GAIN_1 0b01000000 // 7 6 disable top gain setting +#define RADIOLIB_CC1101_MAX_DVGA_GAIN_2 0b10000000 // 7 6 disable top two gain setting +#define RADIOLIB_CC1101_MAX_DVGA_GAIN_3 0b11000000 // 7 6 disable top three gain setting +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_0_DB 0b00000000 // 5 3 reduce maximum LNA gain by: 0 dB (default) +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_2_6_DB 0b00001000 // 5 3 2.6 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_6_1_DB 0b00010000 // 5 3 6.1 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_7_4_DB 0b00011000 // 5 3 7.4 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_9_2_DB 0b00100000 // 5 3 9.2 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_11_5_DB 0b00101000 // 5 3 11.5 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_14_6_DB 0b00110000 // 5 3 14.6 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_17_1_DB 0b00111000 // 5 3 17.1 dB +#define RADIOLIB_CC1101_MAGN_TARGET_24_DB 0b00000000 // 2 0 average amplitude target for filter: 24 dB +#define RADIOLIB_CC1101_MAGN_TARGET_27_DB 0b00000001 // 2 0 27 dB +#define RADIOLIB_CC1101_MAGN_TARGET_30_DB 0b00000010 // 2 0 30 dB +#define RADIOLIB_CC1101_MAGN_TARGET_33_DB 0b00000011 // 2 0 33 dB (default) +#define RADIOLIB_CC1101_MAGN_TARGET_36_DB 0b00000100 // 2 0 36 dB +#define RADIOLIB_CC1101_MAGN_TARGET_38_DB 0b00000101 // 2 0 38 dB +#define RADIOLIB_CC1101_MAGN_TARGET_40_DB 0b00000110 // 2 0 40 dB +#define RADIOLIB_CC1101_MAGN_TARGET_42_DB 0b00000111 // 2 0 42 dB + +// RADIOLIB_CC1101_REG_AGCCTRL1 +#define RADIOLIB_CC1101_AGC_LNA_PRIORITY_LNA2 0b00000000 // 6 6 LNA priority setting: LNA2 first +#define RADIOLIB_CC1101_AGC_LNA_PRIORITY_LNA 0b01000000 // 6 6 LNA first (default) +#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_OFF 0b00000000 // 5 4 RSSI relative change to assert carrier sense: disabled (default) +#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_6_DB 0b00010000 // 5 4 6 dB +#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_10_DB 0b00100000 // 5 4 10 dB +#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_14_DB 0b00110000 // 5 4 14 dB +#define RADIOLIB_CC1101_CARRIER_SENSE_ABS_THR 0x00 // 3 0 RSSI threshold to assert carrier sense in 2s compliment, Thr = MAGN_TARGET + CARRIER_SENSE_ABS_TH [dB] + +// RADIOLIB_CC1101_REG_AGCCTRL0 +#define RADIOLIB_CC1101_HYST_LEVEL_NONE 0b00000000 // 7 6 AGC hysteresis level: none +#define RADIOLIB_CC1101_HYST_LEVEL_LOW 0b01000000 // 7 6 low +#define RADIOLIB_CC1101_HYST_LEVEL_MEDIUM 0b10000000 // 7 6 medium (default) +#define RADIOLIB_CC1101_HYST_LEVEL_HIGH 0b11000000 // 7 6 high +#define RADIOLIB_CC1101_WAIT_TIME_8_SAMPLES 0b00000000 // 5 4 AGC wait time: 8 samples +#define RADIOLIB_CC1101_WAIT_TIME_16_SAMPLES 0b00010000 // 5 4 16 samples (default) +#define RADIOLIB_CC1101_WAIT_TIME_24_SAMPLES 0b00100000 // 5 4 24 samples +#define RADIOLIB_CC1101_WAIT_TIME_32_SAMPLES 0b00110000 // 5 4 32 samples +#define RADIOLIB_CC1101_AGC_FREEZE_NEVER 0b00000000 // 3 2 freeze AGC gain: never (default) +#define RADIOLIB_CC1101_AGC_FREEZE_SYNC_WORD 0b00000100 // 3 2 when sync word is found +#define RADIOLIB_CC1101_AGC_FREEZE_MANUAL_A 0b00001000 // 3 2 manually freeze analog control +#define RADIOLIB_CC1101_AGC_FREEZE_MANUAL_AD 0b00001100 // 3 2 manually freeze analog and digital control +#define RADIOLIB_CC1101_FILTER_LENGTH_8 0b00000000 // 1 0 averaging length for channel filter: 8 samples +#define RADIOLIB_CC1101_FILTER_LENGTH_16 0b00000001 // 1 0 16 samples (default) +#define RADIOLIB_CC1101_FILTER_LENGTH_32 0b00000010 // 1 0 32 samples +#define RADIOLIB_CC1101_FILTER_LENGTH_64 0b00000011 // 1 0 64 samples +#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_4_DB 0b00000000 // 1 0 ASK/OOK decision boundary: 4 dB +#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_8_DB 0b00000001 // 1 0 8 dB (default) +#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_12_DB 0b00000010 // 1 0 12 dB +#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_16_DB 0b00000011 // 1 0 16 dB + +// RADIOLIB_CC1101_REG_WOREVT1 + REG_WOREVT0 +#define RADIOLIB_CC1101_EVENT0_TIMEOUT_MSB 0x87 // 7 0 EVENT0 timeout: t_event0 = (750 / f(XOSC)) * EVENT0_TIMEOUT * 2^(5 * WOR_RES) [s] +#define RADIOLIB_CC1101_EVENT0_TIMEOUT_LSB 0x6B // 7 0 default value for 26 MHz crystal: 1.0 s + +// RADIOLIB_CC1101_REG_WORCTRL +#define RADIOLIB_CC1101_RC_POWER_UP 0b00000000 // 7 7 power up RC oscillator +#define RADIOLIB_CC1101_RC_POWER_DOWN 0b10000000 // 7 7 power down RC oscillator +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_4 0b00000000 // 6 4 EVENT1 timeout: 4 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_6 0b00010000 // 6 4 6 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_8 0b00100000 // 6 4 8 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_12 0b00110000 // 6 4 12 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_16 0b01000000 // 6 4 16 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_24 0b01010000 // 6 4 24 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_32 0b01100000 // 6 4 32 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_48 0b01110000 // 6 4 48 RC periods (default) +#define RADIOLIB_CC1101_RC_CAL_OFF 0b00000000 // 3 3 disable RC oscillator calibration +#define RADIOLIB_CC1101_RC_CAL_ON 0b00001000 // 3 3 enable RC oscillator calibration (default) +#define RADIOLIB_CC1101_WOR_RES_1 0b00000000 // 1 0 EVENT0 resolution: 1 period (default) +#define RADIOLIB_CC1101_WOR_RES_2_5 0b00000001 // 1 0 2^5 periods +#define RADIOLIB_CC1101_WOR_RES_2_10 0b00000010 // 1 0 2^10 periods +#define RADIOLIB_CC1101_WOR_RES_2_15 0b00000011 // 1 0 2^15 periods + +// RADIOLIB_CC1101_REG_FREND1 +#define RADIOLIB_CC1101_LNA_CURRENT 0x01 // 7 6 front-end LNA PTAT current output adjustment +#define RADIOLIB_CC1101_LNA2MIX_CURRENT 0x01 // 5 4 front-end PTAT output adjustment +#define RADIOLIB_CC1101_LODIV_BUF_CURRENT_RX 0x01 // 3 2 Rx LO buffer current adjustment +#define RADIOLIB_CC1101_MIX_CURRENT 0x02 // 1 0 mixer current adjustment + +// RADIOLIB_CC1101_REG_FREND0 +#define RADIOLIB_CC1101_LODIV_BUF_CURRENT_TX 0x01 // 5 4 Tx LO buffer current adjustment +#define RADIOLIB_CC1101_PA_POWER 0x00 // 2 0 set power amplifier power according to PATABLE + +// RADIOLIB_CC1101_REG_FSCAL3 +#define RADIOLIB_CC1101_CHP_CURR_CAL_OFF 0b00000000 // 5 4 disable charge pump calibration +#define RADIOLIB_CC1101_CHP_CURR_CAL_ON 0b00100000 // 5 4 enable charge pump calibration (default) +#define RADIOLIB_CC1101_FSCAL3 0x09 // 3 0 charge pump output current: I_out = I_0 * 2^(FSCAL3/4) [A] + +// RADIOLIB_CC1101_REG_FSCAL2 +#define RADIOLIB_CC1101_VCO_CORE_LOW 0b00000000 // 5 5 VCO: low (default) +#define RADIOLIB_CC1101_VCO_CORE_HIGH 0b00100000 // 5 5 high +#define RADIOLIB_CC1101_FSCAL2 0x0A // 4 0 VCO current result/override + +// RADIOLIB_CC1101_REG_FSCAL1 +#define RADIOLIB_CC1101_FSCAL1 0x20 // 5 0 capacitor array setting for coarse VCO tuning + +// RADIOLIB_CC1101_REG_FSCAL0 +#define RADIOLIB_CC1101_FSCAL0 0x0D // 6 0 frequency synthesizer calibration setting + +// RADIOLIB_CC1101_REG_RCCTRL1 +#define RADIOLIB_CC1101_RCCTRL1 0x41 // 6 0 RC oscillator configuration + +// RADIOLIB_CC1101_REG_RCCTRL0 +#define RADIOLIB_CC1101_RCCTRL0 0x00 // 6 0 RC oscillator configuration + +// RADIOLIB_CC1101_REG_PTEST +#define RADIOLIB_CC1101_TEMP_SENS_IDLE_OFF 0x7F // 7 0 temperature sensor will not be available in idle mode (default) +#define RADIOLIB_CC1101_TEMP_SENS_IDLE_ON 0xBF // 7 0 temperature sensor will be available in idle mode + +// RADIOLIB_CC1101_REG_TEST0 +#define RADIOLIB_CC1101_VCO_SEL_CAL_OFF 0b00000000 // 1 1 disable VCO selection calibration stage +#define RADIOLIB_CC1101_VCO_SEL_CAL_ON 0b00000010 // 1 1 enable VCO selection calibration stage + +// RADIOLIB_CC1101_REG_PARTNUM +#define RADIOLIB_CC1101_PARTNUM 0x00 + +// RADIOLIB_CC1101_REG_VERSION +#define RADIOLIB_CC1101_VERSION_CURRENT 0x14 +#define RADIOLIB_CC1101_VERSION_LEGACY 0x04 +#define RADIOLIB_CC1101_VERSION_CLONE 0x17 + +// RADIOLIB_CC1101_REG_MARCSTATE +#define RADIOLIB_CC1101_MARC_STATE_SLEEP 0x00 // 4 0 main radio control state: sleep +#define RADIOLIB_CC1101_MARC_STATE_IDLE 0x01 // 4 0 idle +#define RADIOLIB_CC1101_MARC_STATE_XOFF 0x02 // 4 0 XOFF +#define RADIOLIB_CC1101_MARC_STATE_VCOON_MC 0x03 // 4 0 VCOON_MC +#define RADIOLIB_CC1101_MARC_STATE_REGON_MC 0x04 // 4 0 REGON_MC +#define RADIOLIB_CC1101_MARC_STATE_MANCAL 0x05 // 4 0 MANCAL +#define RADIOLIB_CC1101_MARC_STATE_VCOON 0x06 // 4 0 VCOON +#define RADIOLIB_CC1101_MARC_STATE_REGON 0x07 // 4 0 REGON +#define RADIOLIB_CC1101_MARC_STATE_STARTCAL 0x08 // 4 0 STARTCAL +#define RADIOLIB_CC1101_MARC_STATE_BWBOOST 0x09 // 4 0 BWBOOST +#define RADIOLIB_CC1101_MARC_STATE_FS_LOCK 0x0A // 4 0 FS_LOCK +#define RADIOLIB_CC1101_MARC_STATE_IFADCON 0x0B // 4 0 IFADCON +#define RADIOLIB_CC1101_MARC_STATE_ENDCAL 0x0C // 4 0 ENDCAL +#define RADIOLIB_CC1101_MARC_STATE_RX 0x0D // 4 0 RX +#define RADIOLIB_CC1101_MARC_STATE_RX_END 0x0E // 4 0 RX_END +#define RADIOLIB_CC1101_MARC_STATE_RX_RST 0x0F // 4 0 RX_RST +#define RADIOLIB_CC1101_MARC_STATE_TXRX_SWITCH 0x10 // 4 0 TXRX_SWITCH +#define RADIOLIB_CC1101_MARC_STATE_RXFIFO_OVERFLOW 0x11 // 4 0 RXFIFO_OVERFLOW +#define RADIOLIB_CC1101_MARC_STATE_FSTXON 0x12 // 4 0 FSTXON +#define RADIOLIB_CC1101_MARC_STATE_TX 0x13 // 4 0 TX +#define RADIOLIB_CC1101_MARC_STATE_TX_END 0x14 // 4 0 TX_END +#define RADIOLIB_CC1101_MARC_STATE_RXTX_SWITCH 0x15 // 4 0 RXTX_SWITCH +#define RADIOLIB_CC1101_MARC_STATE_TXFIFO_UNDERFLOW 0x16 // 4 0 TXFIFO_UNDERFLOW + +// RADIOLIB_CC1101_REG_WORTIME1 + REG_WORTIME0 +#define RADIOLIB_CC1101_WORTIME_MSB 0x00 // 7 0 WOR timer value +#define RADIOLIB_CC1101_WORTIME_LSB 0x00 // 7 0 + +// RADIOLIB_CC1101_REG_PKTSTATUS +#define RADIOLIB_CC1101_CRC_OK 0b10000000 // 7 7 CRC check passed +#define RADIOLIB_CC1101_CRC_ERROR 0b00000000 // 7 7 CRC check failed +#define RADIOLIB_CC1101_CS 0b01000000 // 6 6 carrier sense +#define RADIOLIB_CC1101_PQT_REACHED 0b00100000 // 5 5 preamble quality reached +#define RADIOLIB_CC1101_CCA 0b00010000 // 4 4 channel clear +#define RADIOLIB_CC1101_SFD 0b00001000 // 3 3 start of frame delimiter - sync word received +#define RADIOLIB_CC1101_GDO2_ACTIVE 0b00000100 // 2 2 GDO2 is active/asserted +#define RADIOLIB_CC1101_GDO0_ACTIVE 0b00000001 // 0 0 GDO0 is active/asserted + +// RadioLib defaults +#define RADIOLIB_CC1101_DEFAULT_FREQ 434.0 +#define RADIOLIB_CC1101_DEFAULT_BR 4.8 +#define RADIOLIB_CC1101_DEFAULT_FREQDEV 5.0 +#define RADIOLIB_CC1101_DEFAULT_RXBW 58.0 +#define RADIOLIB_CC1101_DEFAULT_POWER 10 +#define RADIOLIB_CC1101_DEFAULT_PREAMBLELEN 16 +#define RADIOLIB_CC1101_DEFAULT_SW {0x12, 0xAD} +#define RADIOLIB_CC1101_DEFAULT_SW_LEN 2 + +/*! + \class CC1101 + \brief Control class for %CC1101 module. +*/ +class CC1101: public PhysicalLayer { + public: + // introduce PhysicalLayer overloads + using PhysicalLayer::transmit; + using PhysicalLayer::receive; + using PhysicalLayer::startTransmit; + using PhysicalLayer::readData; + + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + CC1101(Module* module); + + // basic methods + + /*! + \brief Initialization method. + \param freq Carrier frequency in MHz. Defaults to 434 MHz. + \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 135.0 kHz. + \param pwr Output power in dBm. Defaults to 10 dBm. + \param preambleLength Preamble Length in bits. Defaults to 16 bits. + \returns \ref status_codes + */ + int16_t begin( + float freq = RADIOLIB_CC1101_DEFAULT_FREQ, + float br = RADIOLIB_CC1101_DEFAULT_BR, + float freqDev = RADIOLIB_CC1101_DEFAULT_FREQDEV, + float rxBw = RADIOLIB_CC1101_DEFAULT_RXBW, + int8_t pwr = RADIOLIB_CC1101_DEFAULT_POWER, + uint8_t preambleLength = RADIOLIB_CC1101_DEFAULT_PREAMBLELEN); + + /*! + \brief Reset method - resets the chip using manual reset sequence (without RESET pin). + */ + void reset(); + + /*! + \brief Blocking binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \param addr Address to send the data to. Will only be added if address filtering was enabled. + \returns \ref status_codes + */ + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Blocking binary receive method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \returns \ref status_codes + */ + int16_t receive(uint8_t* data, size_t len) override; + + /*! + \brief Sets the module to standby mode. + \returns \ref status_codes + */ + int16_t standby() override; + + /*! + \brief Sets the module to standby. + \param mode Standby mode to be used. No effect, implemented only for PhysicalLayer compatibility. + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + + /*! + \brief Starts synchronous direct mode transmission. + \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. + \returns \ref status_codes + */ + int16_t transmitDirect(uint32_t frf = 0) override; + + /*! + \brief Starts synchronous direct mode reception. + \returns \ref status_codes + */ + int16_t receiveDirect() override; + + /*! + \brief Starts asynchronous direct mode transmission. + \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. + \returns \ref status_codes + */ + int16_t transmitDirectAsync(uint32_t frf = 0); + + /*! + \brief Starts asynchronous direct mode reception. + \returns \ref status_codes + */ + int16_t receiveDirectAsync(); + + /*! + \brief Stops direct mode. It is required to call this method to switch from direct transmissions + to packet-based transmissions. + */ + int16_t packetMode(); + + // interrupt methods + + /*! + \brief Sets interrupt service routine to call when GDO0 activates. + \param func ISR to call. + \param dir Signal change direction. + */ + void setGdo0Action(void (*func)(void), uint32_t dir); + + /*! + \brief Clears interrupt service routine to call when GDO0 activates. + */ + void clearGdo0Action(); + + /*! + \brief Sets interrupt service routine to call when GDO2 activates. + \param func ISR to call. + \param dir Signal change direction. + */ + void setGdo2Action(void (*func)(void), uint32_t dir); + + /*! + \brief Clears interrupt service routine to call when GDO0 activates. + */ + void clearGdo2Action(); + + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + + /*! + \brief Interrupt-driven binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \param addr Address to send the data to. Will only be added if address filtering was enabled. + \returns \ref status_codes + */ + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Clean up after transmission is done. + \returns \ref status_codes + */ + int16_t finishTransmit() override; + + /*! + \brief Interrupt-driven receive method. GDO0 will be activated when full packet is received. + \returns \ref status_codes + */ + int16_t startReceive(); + + /*! + \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. + \param timeout Ignored. + \param irqFlags Ignored. + \param irqMask Ignored. + \param len Ignored. + \returns \ref status_codes + */ + int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + + /*! + \brief Reads data received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. + \returns \ref status_codes + */ + int16_t readData(uint8_t* data, size_t len) override; + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values are in bands 300.0 to 348.0 MHz, + 387.0 to 464.0 MHz and 779.0 to 928.0 MHz. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets bit rate. Allowed values range from 0.025 to 600.0 kbps. + \param br Bit rate to be set in kbps. + \returns \ref status_codes + */ + int16_t setBitRate(float br); + + /*! + \brief Sets receiver bandwidth. Allowed values are 58, 68, 81, 102, 116, 135, 162, + 203, 232, 270, 325, 406, 464, 541, 650 and 812 kHz. + \param rxBw Receiver bandwidth to be set in kHz. + \returns \ref status_codes + */ + int16_t setRxBandwidth(float rxBw); + + /*! + \brief Sets frequency deviation. Allowed values range from 1.587 to 380.8 kHz. + \param freqDev Frequency deviation to be set in kHz. + \returns \ref status_codes + */ + int16_t setFrequencyDeviation(float freqDev) override; + + /*! + \brief Gets frequency deviation. + \param[out] freqDev Pointer to variable where to save the frequency deviation. + \returns \ref status_codes + */ + int16_t getFrequencyDeviation(float *freqDev); + + /*! + \brief Sets output power. Allowed values are -30, -20, -15, -10, 0, 5, 7 or 10 dBm. + \param pwr Output power to be set in dBm. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t pwr); + + /*! + \brief Sets 16-bit sync word as a two byte value. + \param syncH MSB of the sync word. + \param syncL LSB of the sync word. + \param maxErrBits Maximum allowed number of bit errors in received sync word. Defaults to 0. + \param requireCarrierSense Require carrier sense above threshold in addition to sync word. + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits = 0, bool requireCarrierSense = false); + + /*! + \brief Sets 1 or 2 bytes of sync word. + \param syncWord Pointer to the array of sync word bytes. + \param len Sync word length in bytes. + \param maxErrBits Maximum allowed number of bit errors in received sync word. Defaults to 0. + \param requireCarrierSense Require carrier sense above threshold in addition to sync word. + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits = 0, bool requireCarrierSense = false); + + /*! + \brief Sets preamble length. + \param preambleLength Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192. + \returns \ref status_codes + */ + int16_t setPreambleLength(uint8_t preambleLength, uint8_t qualityThreshold); + + /*! + \brief Sets node and broadcast addresses. Calling this method will also enable address filtering. + \param nodeAddr Node address to be set. + \param numBroadcastAddrs Number of broadcast addresses to be used. Can be set to 0 (no broadcast), + 1 (broadcast at 0x00) or 2 (broadcast at 0x00 and 0xFF). + \returns \ref status_codes + */ + int16_t setNodeAddress(uint8_t nodeAddr, uint8_t numBroadcastAddrs = 0); + + /*! + \brief Disables address filtering. Calling this method will also erase previously set addresses. + \returns \ref status_codes + */ + int16_t disableAddressFiltering(); + + /*! + \brief Enables/disables OOK modulation instead of FSK. + \param enableOOK Enable (true) or disable (false) OOK. + \returns \ref status_codes + */ + int16_t setOOK(bool enableOOK); + + /*! + \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. + In asynchronous direct mode, returns the current RSSI level. + \returns RSSI in dBm. + */ + float getRSSI(); + + /*! + \brief Gets LQI (Link Quality Indicator) of the last received packet. + \returns Last packet LQI (lower is better). + */ + uint8_t getLQI() const; + + /*! + \brief Query modem for the packet length of received payload. + \param update Update received packet length. Will return cached value when set to false. + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update = true) override; + + /*! + \brief Set modem in fixed packet length mode. + \param len Packet length. + \returns \ref status_codes + */ + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_CC1101_MAX_PACKET_LENGTH); + + /*! + \brief Set modem in variable packet length mode. + \param len Maximum packet length. + \returns \ref status_codes + */ + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_CC1101_MAX_PACKET_LENGTH); + + /*! + \brief Enable sync word filtering and generation. + \param numBits Sync word length in bits. + \param requireCarrierSense Require carrier sense above threshold in addition to sync word. + \returns \ref status_codes + */ + int16_t enableSyncWordFiltering(uint8_t maxErrBits = 0, bool requireCarrierSense = false); + + /*! + \brief Disable preamble and sync word filtering and generation. + \param requireCarrierSense Require carrier sense above threshold. + \returns \ref status_codes + */ + int16_t disableSyncWordFiltering(bool requireCarrierSense = false); + + /*! + \brief Enable CRC filtering and generation. + \param enable Set or unset CRC generation and filtering. + \returns \ref status_codes + */ + int16_t setCrcFiltering(bool enable = true); + + /*! + \brief Set modem in "sniff" mode: no packet filtering (e.g., no preamble, sync word, address, CRC). + \param enable Set or unset promiscuous mode. + \returns \ref status_codes + */ + int16_t setPromiscuousMode(bool enable = true); + + /*! + \brief Get whether the modem is in promiscuous mode: no packet filtering + (e.g., no preamble, sync word, address, CRC). + \returns Whether the modem is in promiscuous mode. + */ + bool getPromiscuousMode(); + + /*! + \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. + Allowed value is RADIOLIB_SHAPING_0_5. Set to RADIOLIB_SHAPING_NONE to disable data shaping. + \param sh Gaussian shaping bandwidth-time product that will be used for data shaping. + \returns \ref status_codes + */ + int16_t setDataShaping(uint8_t sh) override; + + /*! + \brief Sets transmission encoding. Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER, and RADIOLIB_ENCODING_WHITENING. + Note that encoding on CC1101 is applied to the entire stream including preamble, sync word, and CRC. + \param encoding Encoding to be used. + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding) override; + + /*! \copydoc Module::setRfSwitchPins */ + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); + + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + + /*! + \brief Get one truly random byte from RSSI noise. + \returns TRNG byte. + */ + uint8_t randomByte(); + + /*! + \brief Read version SPI register. Should return CC1101_VERSION_LEGACY (0x04) or + CC1101_VERSION_CURRENT (0x14) if CC1101 is connected and working. + \returns Version register contents or \ref status_codes + */ + int16_t getChipVersion(); + + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE + /*! + \brief Set interrupt service routine function to call when data bit is receveid in direct mode. + \param func Pointer to interrupt service routine. + */ + void setDirectAction(void (*func)(void)); + + /*! + \brief Function to read and process data bit in direct reception mode. + \param pin Pin on which to read. + */ + void readBit(uint32_t pin); + #endif + + /*! + \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). + \param pin Pin number onto which a signal is to be placed. + \param value The value that indicates which function to place on that pin. See chip datasheet for details. + \returns \ref status_codes + */ + int16_t setDIOMapping(uint32_t pin, uint32_t value); + + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL + protected: + #endif + Module* getMod(); + + // SPI read overrides to set bit for burst write and status registers access + int16_t SPIgetRegValue(uint8_t reg, uint8_t msb = 7, uint8_t lsb = 0); + int16_t SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2); + void SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes); + uint8_t SPIreadRegister(uint8_t reg); + void SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len); + void SPIwriteRegister(uint8_t reg, uint8_t data); + + void SPIsendCommand(uint8_t cmd); + + #if !RADIOLIB_GODMODE + private: + #endif + Module* mod; + + float frequency = RADIOLIB_CC1101_DEFAULT_FREQ; + float bitRate = RADIOLIB_CC1101_DEFAULT_BR; + uint8_t rawRSSI = 0; + uint8_t rawLQI = 0; + uint8_t modulation = RADIOLIB_CC1101_MOD_FORMAT_2_FSK; + + size_t packetLength = 0; + bool packetLengthQueried = false; + uint8_t packetLengthConfig = RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE; + + bool promiscuous = false; + bool crcOn = true; + bool directModeEnabled = true; + + int8_t power = RADIOLIB_CC1101_DEFAULT_POWER; + + int16_t config(); + int16_t transmitDirect(bool sync, uint32_t frf); + int16_t receiveDirect(bool sync); + int16_t directMode(bool sync); + static void getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant); + int16_t setPacketMode(uint8_t mode, uint16_t len); +}; + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/LLCC68/LLCC68.cpp b/lib/lib_rf/RadioLib/src/modules/LLCC68/LLCC68.cpp new file mode 100644 index 000000000..f7d458ad9 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/LLCC68/LLCC68.cpp @@ -0,0 +1,119 @@ +#include "LLCC68.h" +#if !RADIOLIB_EXCLUDE_SX126X + +LLCC68::LLCC68(Module* mod) : SX1262(mod) { + chipType = RADIOLIB_LLCC68_CHIP_TYPE; + this->XTAL = true; +} + +int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t pwr, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { + // execute common part + int16_t state = SX126x::begin(cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setOutputPower(pwr); + RADIOLIB_ASSERT(state); + + state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t LLCC68::setBandwidth(float bw) { + RADIOLIB_CHECK_RANGE(bw, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + return(SX1262::setBandwidth(bw)); +} + +int16_t LLCC68::setSpreadingFactor(uint8_t sf) { + switch(SX126x::bandwidth) { + case RADIOLIB_SX126X_LORA_BW_125_0: + RADIOLIB_CHECK_RANGE(sf, 5, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + break; + case RADIOLIB_SX126X_LORA_BW_250_0: + RADIOLIB_CHECK_RANGE(sf, 5, 10, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + break; + case RADIOLIB_SX126X_LORA_BW_500_0: + RADIOLIB_CHECK_RANGE(sf, 5, 11, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + break; + default: + return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + } + + return(SX1262::setSpreadingFactor(sf)); +} + +int16_t LLCC68::setDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + RADIOLIB_ASSERT(state); + + // set the coding rate + state = this->setCodingRate(dr.lora.codingRate); + } + + return(state); +} + +int16_t LLCC68::checkDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + return(RADIOLIB_ERR_NONE); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + uint8_t bw_div2 = dr.lora.bandwidth / 2 + 0.01; + switch (bw_div2) { + case 62: // 125.0: + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + break; + case 125: // 250.0 + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 10, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + break; + case 250: // 500.0 + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 11, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + break; + default: + return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } + return(RADIOLIB_ERR_NONE); + + } + + return(state); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/LLCC68/LLCC68.h b/lib/lib_rf/RadioLib/src/modules/LLCC68/LLCC68.h new file mode 100644 index 000000000..3a737060f --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/LLCC68/LLCC68.h @@ -0,0 +1,81 @@ +#if !defined(_RADIOLIB_LLCC68_H) +#define _RADIOLIB_LLCC68_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX126X + +#include "../../Module.h" +#include "../SX126x/SX1262.h" + +//RADIOLIB_SX126X_REG_VERSION_STRING +#define RADIOLIB_LLCC68_CHIP_TYPE "LLCC68" + +/*! + \class LLCC68 + \brief Derived class for %LLCC68 modules. +*/ +class LLCC68: public SX1262 { + public: + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + LLCC68(Module* mod); + + /*! + \brief Initialization method for LoRa modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. + \param sf LoRa spreading factor. Defaults to 9. + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). + \param pwr Output power in dBm. Defaults to 10 dBm. + \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 0 V (XTAL). + If you are seeing -706/-707 error codes, it likely means you are using a module with TCXO. + To use TCXO, either set this value to its reference voltage, or set SX126x::XTAL to false. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t pwr = 10, uint16_t preambleLength = 8, float tcxoVoltage = 0, bool useRegulatorLDO = false); + + // configuration methods + + /*! + \brief Sets LoRa bandwidth. Allowed values are 125.0, 250.0 and 500.0 kHz. + \param bw LoRa bandwidth to be set in kHz. + \returns \ref status_codes + */ + int16_t setBandwidth(float bw); + + /*! + \brief Sets LoRa spreading factor. Allowed values range from 5 to 11, depending on currently set spreading factor. + \param sf LoRa spreading factor to be set. + \returns \ref status_codes + */ + int16_t setSpreadingFactor(uint8_t sf); + + /*! + \brief Set data. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr) override; + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/RF69/RF69.cpp b/lib/lib_rf/RadioLib/src/modules/RF69/RF69.cpp new file mode 100644 index 000000000..a934898ed --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/RF69/RF69.cpp @@ -0,0 +1,1080 @@ +#include "RF69.h" +#include +#if !RADIOLIB_EXCLUDE_RF69 + +RF69::RF69(Module* module) : PhysicalLayer(RADIOLIB_RF69_FREQUENCY_STEP_SIZE, RADIOLIB_RF69_MAX_PACKET_LENGTH) { + this->mod = module; +} + +int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t pwr, uint8_t preambleLen) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + + // try to find the RF69 chip + uint8_t i = 0; + bool flagFound = false; + while((i < 10) && !flagFound) { + // reset the module + reset(); + + // check version register + int16_t version = getChipVersion(); + if(version == RADIOLIB_RF69_CHIP_VERSION) { + flagFound = true; + } else { + RADIOLIB_DEBUG_BASIC_PRINTLN("RF69 not found! (%d of 10 tries) RADIOLIB_RF69_REG_VERSION == 0x%04X, expected 0x0024", i + 1, version); + this->mod->hal->delay(10); + i++; + } + } + + if(!flagFound) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No RF69 found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } else { + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tRF69"); + } + + // configure settings not accessible by API + int16_t state = config(); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + // configure bitrate + this->rxBandwidth = rxBw; + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + // configure default RX bandwidth + state = setRxBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + // configure default frequency deviation + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + // configure default TX output power + state = setOutputPower(pwr); + RADIOLIB_ASSERT(state); + + // configure default preamble length + state = setPreambleLength(preambleLen); + RADIOLIB_ASSERT(state); + + // set default packet length mode + state = variablePacketLengthMode(); + RADIOLIB_ASSERT(state); + + // set default sync word + uint8_t syncWord[] = RADIOLIB_RF69_DEFAULT_SW; + state = setSyncWord(syncWord, sizeof(syncWord)); + RADIOLIB_ASSERT(state); + + // set default data shaping + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + + // set default encoding + state = setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + + // set CRC on by default + state = setCrcFiltering(true); + RADIOLIB_ASSERT(state); + + return(state); +} + +void RF69::reset() { + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + this->mod->hal->delay(1); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + this->mod->hal->delay(10); +} + +int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { + // calculate timeout (5ms + 500 % of expected time-on-air) + uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (this->bitRate * 1000.0)) * 5000000.0); + + // start transmission + int16_t state = startTransmit(data, len, addr); + RADIOLIB_ASSERT(state); + + // wait for transmission end or timeout + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + + if(this->mod->hal->micros() - start > timeout) { + finishTransmit(); + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + + return(finishTransmit()); +} + +int16_t RF69::receive(uint8_t* data, size_t len) { + // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) + uint32_t timeout = 500000 + (1.0/(this->bitRate*1000.0))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0); + + // start reception + int16_t state = startReceive(); + RADIOLIB_ASSERT(state); + + // wait for packet reception or timeout + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + + if(this->mod->hal->micros() - start > timeout) { + standby(); + clearIRQFlags(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } + + // read packet data + return(readData(data, len)); +} + +int16_t RF69::sleep() { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + // set module to sleep + return(setMode(RADIOLIB_RF69_SLEEP)); +} + +int16_t RF69::standby() { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + // set module to standby + return(setMode(RADIOLIB_RF69_STANDBY)); +} + +int16_t RF69::standby(uint8_t mode) { + (void)mode; + return(standby()); +} + +int16_t RF69::transmitDirect(uint32_t frf) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_TX); + + // user requested to start transmitting immediately (required for RTTY) + if(frf != 0) { + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MSB, (frf & 0xFF0000) >> 16); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MID, (frf & 0x00FF00) >> 8); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_LSB, frf & 0x0000FF); + + return(setMode(RADIOLIB_RF69_TX)); + } + + // activate direct mode + int16_t state = directMode(); + RADIOLIB_ASSERT(state); + + // start transmitting + return(setMode(RADIOLIB_RF69_TX)); +} + +int16_t RF69::receiveDirect() { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // activate direct mode + int16_t state = directMode(); + RADIOLIB_ASSERT(state); + + // start receiving + return(setMode(RADIOLIB_RF69_RX)); +} + +int16_t RF69::directMode() { + // set mode to standby + int16_t state = setMode(RADIOLIB_RF69_STANDBY); + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO1_CONT_DCLK | RADIOLIB_RF69_DIO2_CONT_DATA, 5, 2); + RADIOLIB_ASSERT(state); + + // set continuous mode + if(this->bitSync) { + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5)); + } else { + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE, 6, 5)); + } +} + +int16_t RF69::packetMode() { + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_PACKET_MODE, 6, 5)); +} + +void RF69::setAESKey(uint8_t* key) { + this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_AES_KEY_1, key, 16); +} + +int16_t RF69::enableAES() { + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_AES_ON, 0, 0)); +} + +int16_t RF69::disableAES() { + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_AES_OFF, 0, 0)); +} + +int16_t RF69::startReceive() { + // set mode to standby + int16_t state = setMode(RADIOLIB_RF69_STANDBY); + RADIOLIB_ASSERT(state); + + // set RX timeouts and DIO pin mapping + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO0_PACK_PAYLOAD_READY, 7, 4); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_1, RADIOLIB_RF69_TIMEOUT_RX_START); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_2, RADIOLIB_RF69_TIMEOUT_RSSI_THRESH); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + clearIRQFlags(); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // set mode to receive + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA1, RADIOLIB_RF69_PA1_NORMAL); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA2, RADIOLIB_RF69_PA2_NORMAL); + RADIOLIB_ASSERT(state); + + state = setMode(RADIOLIB_RF69_RX); + + return(state); +} + +int16_t RF69::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)timeout; + (void)irqFlags; + (void)irqMask; + (void)len; + return(startReceive()); +} + +void RF69::setDio0Action(void (*func)(void)) { + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising); +} + +void RF69::clearDio0Action() { + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); +} + +void RF69::setDio1Action(void (*func)(void)) { + if(this->mod->getGpio() == RADIOLIB_NC) { + return; + } + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()), func, this->mod->hal->GpioInterruptRising); +} + +void RF69::clearDio1Action() { + if(this->mod->getGpio() == RADIOLIB_NC) { + return; + } + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio())); +} + +void RF69::setPacketReceivedAction(void (*func)(void)) { + this->setDio0Action(func); +} + +void RF69::clearPacketReceivedAction() { + this->clearDio0Action(); +} + +void RF69::setPacketSentAction(void (*func)(void)) { + this->setDio0Action(func); +} + +void RF69::clearPacketSentAction() { + this->clearDio0Action(); +} + +void RF69::setFifoEmptyAction(void (*func)(void)) { + // set DIO1 to the FIFO empty event (the register setting is done in startTransmit) + if(this->mod->getGpio() == RADIOLIB_NC) { + return; + } + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + + // we need to invert the logic here (as compared to setDio1Action), since we are using the "FIFO not empty interrupt" + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()), func, this->mod->hal->GpioInterruptFalling); +} + +void RF69::clearFifoEmptyAction() { + clearDio1Action(); +} + +void RF69::setFifoFullAction(void (*func)(void)) { + // set the interrupt + this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_FIFO_THRESH, 6, 0); + this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO1_PACK_FIFO_LEVEL, 5, 4); + + // set DIO1 to the FIFO full event + setDio1Action(func); +} + +void RF69::clearFifoFullAction() { + clearDio1Action(); + this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, 0x00, 5, 4); +} + +bool RF69::fifoAdd(uint8_t* data, int totalLen, int* remLen) { + // subtract first (this may be the first time we get to modify the remaining length) + *remLen -= RADIOLIB_RF69_FIFO_THRESH - 1; + + // check if there is still something left to send + if(*remLen <= 0) { + // we're done + return(true); + } + + // calculate the number of bytes we can copy + int len = *remLen; + if(len > RADIOLIB_RF69_FIFO_THRESH - 1) { + len = RADIOLIB_RF69_FIFO_THRESH - 1; + } + + // copy the bytes to the FIFO + this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, &data[totalLen - *remLen], len); + + // we're not done yet + return(false); +} + +bool RF69::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) { + // get pointer to the correct position in data buffer + uint8_t* dataPtr = (uint8_t*)&data[*rcvLen]; + + // check how much data are we still expecting + uint8_t len = RADIOLIB_RF69_FIFO_THRESH - 1; + if(totalLen - *rcvLen < len) { + // we're nearly at the end + len = totalLen - *rcvLen; + } + + // get the data + this->mod->SPIreadRegisterBurst(RADIOLIB_RF69_REG_FIFO, len, dataPtr); + *rcvLen = *rcvLen + len; + + // check if we're done + if(*rcvLen >= totalLen) { + return(true); + } + return(false); +} + +int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { + // set mode to standby + int16_t state = setMode(RADIOLIB_RF69_STANDBY); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + clearIRQFlags(); + + // set DIO mapping + if(len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO1_PACK_FIFO_NOT_EMPTY, 5, 4); + } else { + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO0_PACK_PACKET_SENT, 7, 6); + } + RADIOLIB_ASSERT(state); + + // optionally write packet length + if (this->packetLengthConfig == RADIOLIB_RF69_PACKET_FORMAT_VARIABLE) { + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, len); + } + + // check address filtering + uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, 2, 1); + if((filter == RADIOLIB_RF69_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST)) { + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, addr); + } + + // write packet to FIFO + size_t packetLen = len; + if(len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { + packetLen = RADIOLIB_RF69_FIFO_THRESH - 1; + this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY, 7, 7); + } + this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, data, packetLen); + + // this is a hack, but it seems than in Stream mode, Rx FIFO level is getting triggered 1 byte before it should + // just add a padding byte that can be dropped without consequence + if(len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, '/'); + } + + // enable +20 dBm operation + if(this->power > 17) { + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_OFF | 0x0F); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA1, RADIOLIB_RF69_PA1_20_DBM); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA2, RADIOLIB_RF69_PA2_20_DBM); + RADIOLIB_ASSERT(state); + } + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_TX); + + // set mode to transmit + state = setMode(RADIOLIB_RF69_TX); + + return(state); +} + +int16_t RF69::finishTransmit() { + // clear interrupt flags + clearIRQFlags(); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + +int16_t RF69::readData(uint8_t* data, size_t len) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // get packet length + size_t length = getPacketLength(); + size_t dumpLen = 0; + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + dumpLen = length - len; + length = len; + } + + // check address filtering + uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, 2, 1); + if((filter == RADIOLIB_RF69_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST)) { + this->mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); + } + + // read packet data + this->mod->SPIreadRegisterBurst(RADIOLIB_RF69_REG_FIFO, length, data); + + // dump the bytes that weren't requested + if(dumpLen != 0) { + clearFIFO(dumpLen); + } + + // clear internal flag so getPacketLength can return the new packet length + this->packetLengthQueried = false; + + // clear interrupt flags + clearIRQFlags(); + + return(RADIOLIB_ERR_NONE); +} + +int16_t RF69::setOOK(bool enable) { + // set OOK and if successful, save the new setting + int16_t state = RADIOLIB_ERR_NONE; + if(enable) { + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_OOK, 4, 3, 5); + } else { + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK, 4, 3, 5); + } + + if(state == RADIOLIB_ERR_NONE) { + this->ookEnabled = enable; + } + + // call setRxBandwidth again, since register values differ based on OOK mode being enabled + state |= setRxBandwidth(this->rxBandwidth); + + return(state); +} + +int16_t RF69::setOokThresholdType(uint8_t type) { + if((type != RADIOLIB_RF69_OOK_THRESH_FIXED) && (type != RADIOLIB_RF69_OOK_THRESH_PEAK) && (type != RADIOLIB_RF69_OOK_THRESH_AVERAGE)) { + return(RADIOLIB_ERR_INVALID_OOK_RSSI_PEAK_TYPE); + } + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OOK_PEAK, type, 7, 3, 5)); +} + +int16_t RF69::setOokFixedThreshold(uint8_t value) { + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OOK_FIX, value, 7, 0, 5)); +} + +int16_t RF69::setOokPeakThresholdDecrement(uint8_t value) { + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OOK_PEAK, value, 2, 0, 5)); +} + +int16_t RF69::setFrequency(float freq) { + // check allowed frequency range + if(!(((freq > 290.0) && (freq < 340.0)) || + ((freq > 431.0) && (freq < 510.0)) || + ((freq > 862.0) && (freq < 1020.0)))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY); + } + + // set mode to standby + setMode(RADIOLIB_RF69_STANDBY); + + //set carrier frequency + //FRF(23:0) = freq / Fstep = freq * (1 / Fstep) = freq * (2^19 / 32.0) (pag. 17 of datasheet) + uint32_t FRF = (freq * (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT)) / RADIOLIB_RF69_CRYSTAL_FREQ; + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MID, (FRF & 0x00FF00) >> 8); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_LSB, FRF & 0x0000FF); + + return(RADIOLIB_ERR_NONE); +} + +int16_t RF69::getFrequency(float *freq) { + uint32_t FRF = 0; + + //FRF(23:0) = [ [FRF_MSB]|[FRF_MID]|[FRF_LSB]] + //FRF(32:0) = [0x00|[FRF_MSB]|[FRF_MID]|[FRF_LSB]] + FRF |= (((uint32_t)(this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_FRF_MSB, 7, 0)) << 16) & 0x00FF0000); + FRF |= (((uint32_t)(this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_FRF_MID, 7, 0)) << 8) & 0x0000FF00); + FRF |= (((uint32_t)(this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_FRF_LSB, 7, 0)) << 0) & 0x000000FF); + + //freq = Fstep * FRF(23:0) = (32.0 / 2^19) * FRF(23:0) (pag. 17 of datasheet) + *freq = FRF * ( RADIOLIB_RF69_CRYSTAL_FREQ / (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT) ); + + return(RADIOLIB_ERR_NONE); +} + +int16_t RF69::setBitRate(float br) { + // datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine + RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + + // check bitrate-bandwidth ratio + if(!(br < 2000 * this->rxBandwidth)) { + return(RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO); + } + + // set mode to standby + setMode(RADIOLIB_RF69_STANDBY); + + // set bit rate + uint16_t bitRate = 32000 / br; + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); + if(state == RADIOLIB_ERR_NONE) { + this->bitRate = br; + } + return(state); +} + +int16_t RF69::setRxBandwidth(float rxBw) { + // check bitrate-bandwidth ratio + if(!(this->bitRate < 2000 * rxBw)) { + return(RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO); + } + + // set mode to standby + int16_t state = setMode(RADIOLIB_RF69_STANDBY); + RADIOLIB_ASSERT(state); + + // calculate exponent and mantissa values for receiver bandwidth + for(int8_t e = 7; e >= 0; e--) { + for(int8_t m = 2; m >= 0; m--) { + float point = (RADIOLIB_RF69_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + (this->ookEnabled ? 3 : 2)))); + if(fabs(rxBw - (point / 1000.0)) <= 0.1) { + // set Rx bandwidth + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_BW, (m << 3) | e, 4, 0); + if(state == RADIOLIB_ERR_NONE) { + this->rxBandwidth = rxBw; + } + return(state); + } + } + } + + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); +} + +int16_t RF69::setFrequencyDeviation(float freqDev) { + // set frequency deviation to lowest available setting (required for digimodes) + float newFreqDev = freqDev; + if(freqDev < 0.0) { + newFreqDev = 0.6; + } + + // check frequency deviation range + if(!((newFreqDev + this->bitRate/2 <= 500))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + } + + // set mode to standby + setMode(RADIOLIB_RF69_STANDBY); + + // set frequency deviation from carrier frequency + uint32_t fdev = (newFreqDev * (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT)) / 32000; + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_FDEV_MSB, (fdev & 0xFF00) >> 8, 5, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_FDEV_LSB, fdev & 0x00FF, 7, 0); + + return(state); +} + +int16_t RF69::getFrequencyDeviation(float *freqDev) { + if(freqDev == NULL) { + return(RADIOLIB_ERR_NULL_POINTER); + } + + if(this->ookEnabled) { + *freqDev = 0.0; + + return(RADIOLIB_ERR_NONE); + } + + // get raw value from register + uint32_t fdev = 0; + fdev |= (uint32_t)((this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_FDEV_MSB, 5, 0) << 8) & 0x0000FF00); + fdev |= (uint32_t)((this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_FDEV_LSB, 7, 0) << 0) & 0x000000FF); + + // calculate frequency deviation from raw value obtained from register + // Fdev = Fstep * Fdev(13:0) (pag. 20 of datasheet) + *freqDev = (1000.0 * fdev * RADIOLIB_RF69_CRYSTAL_FREQ) / + (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT); + + return(RADIOLIB_ERR_NONE); +} + +int16_t RF69::setOutputPower(int8_t pwr, bool highPower) { + if(highPower) { + RADIOLIB_CHECK_RANGE(pwr, -2, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } else { + RADIOLIB_CHECK_RANGE(pwr, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + + // set mode to standby + setMode(RADIOLIB_RF69_STANDBY); + + // set output power + int16_t state; + if(highPower) { + // check if both PA1 and PA2 are needed + if(pwr <= 10) { + // -2 to 13 dBm, PA1 is enough + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_OFF | RADIOLIB_RF69_PA1_ON | RADIOLIB_RF69_PA2_OFF | (power + 18), 7, 0); + } else if(pwr <= 17) { + // 13 to 17 dBm, both PAs required + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_OFF | RADIOLIB_RF69_PA1_ON | RADIOLIB_RF69_PA2_ON | (power + 14), 7, 0); + } else { + // 18 - 20 dBm, both PAs and hig power settings required + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_OFF | RADIOLIB_RF69_PA1_ON | RADIOLIB_RF69_PA2_ON | (power + 11), 7, 0); + } + + } else { + // low power module, use only PA0 + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_ON | RADIOLIB_RF69_PA1_OFF | RADIOLIB_RF69_PA2_OFF | (power + 18), 7, 0); + } + + // cache the power value + if(state == RADIOLIB_ERR_NONE) { + this->power = pwr; + } + + return(state); +} + +int16_t RF69::setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits) { + // check constraints + if((maxErrBits > 7) || (len > 8)) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + + // sync word must not contain value 0x00 + for(uint8_t i = 0; i < len; i++) { + if(syncWord[i] == 0x00) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + } + + int16_t state = enableSyncWordFiltering(maxErrBits); + RADIOLIB_ASSERT(state); + + // set sync word register + this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_SYNC_VALUE_1, syncWord, len); + + if(state == RADIOLIB_ERR_NONE) { + this->syncWordLength = len; + } + + return(state); +} + +int16_t RF69::setPreambleLength(uint8_t preambleLen) { + // RF69 configures preamble length in bytes + if(preambleLen % 8 != 0) { + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); + } + + uint8_t preLenBytes = preambleLen / 8; + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_PREAMBLE_MSB, 0x00); + + return (this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PREAMBLE_LSB, preLenBytes)); +} + +int16_t RF69::setNodeAddress(uint8_t nodeAddr) { + // enable address filtering (node only) + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_ADDRESS_FILTERING_NODE, 2, 1); + RADIOLIB_ASSERT(state); + + // set node address + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_NODE_ADRS, nodeAddr)); +} + +int16_t RF69::setBroadcastAddress(uint8_t broadAddr) { + // enable address filtering (node + broadcast) + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1); + RADIOLIB_ASSERT(state); + + // set broadcast address + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BROADCAST_ADRS, broadAddr)); +} + +int16_t RF69::disableAddressFiltering() { + // disable address filtering + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_ADDRESS_FILTERING_OFF, 2, 1); + RADIOLIB_ASSERT(state); + + // set node address to default (0x00) + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_NODE_ADRS, 0x00); + RADIOLIB_ASSERT(state); + + // set broadcast address to default (0x00) + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BROADCAST_ADRS, 0x00)); +} + +void RF69::setAmbientTemperature(int16_t tempAmbient) { + this->tempOffset = getTemperature() - tempAmbient; +} + +int16_t RF69::getTemperature() { + // set mode to STANDBY + setMode(RADIOLIB_RF69_STANDBY); + + // start temperature measurement + this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEMP_1, RADIOLIB_RF69_TEMP_MEAS_START, 3, 3); + + // wait until measurement is finished + while(this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_TEMP_1, 2, 2) == RADIOLIB_RF69_TEMP_MEAS_RUNNING) { + // check every 10 us + this->mod->hal->delay(10); + } + int8_t rawTemp = this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_TEMP_2); + + return(0 - (rawTemp + this->tempOffset)); +} + +size_t RF69::getPacketLength(bool update) { + if(!this->packetLengthQueried && update) { + if (this->packetLengthConfig == RADIOLIB_RF69_PACKET_FORMAT_VARIABLE) { + this->packetLength = this->mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); + } else { + this->packetLength = this->mod->SPIreadRegister(RADIOLIB_RF69_REG_PAYLOAD_LENGTH); + } + this->packetLengthQueried = true; + } + + return(this->packetLength); +} + +int16_t RF69::fixedPacketLengthMode(uint8_t len) { + return(setPacketMode(RADIOLIB_RF69_PACKET_FORMAT_FIXED, len)); +} + +int16_t RF69::variablePacketLengthMode(uint8_t maxLen) { + return(setPacketMode(RADIOLIB_RF69_PACKET_FORMAT_VARIABLE, maxLen)); +} + +int16_t RF69::enableSyncWordFiltering(uint8_t maxErrBits) { + // enable sync word recognition + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_ON | RADIOLIB_RF69_FIFO_FILL_CONDITION_SYNC | (this->syncWordLength - 1) << 3 | maxErrBits, 7, 0)); +} + +int16_t RF69::disableSyncWordFiltering() { + // disable sync word detection and generation + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_OFF | RADIOLIB_RF69_FIFO_FILL_CONDITION, 7, 6)); +} + +int16_t RF69::enableContinuousModeBitSync() { + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5); + if(state == RADIOLIB_ERR_NONE) { + this->bitSync = true; + } + + return(state); +} + +int16_t RF69::disableContinuousModeBitSync() { + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE, 6, 5); + if(state == RADIOLIB_ERR_NONE) { + this->bitSync = false; + } + + return(state); +} + +int16_t RF69::setCrcFiltering(bool crcOn) { + if (crcOn == true) { + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_CRC_ON, 4, 4)); + } else { + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_CRC_OFF, 4, 4)); + } +} + +int16_t RF69::setPromiscuousMode(bool enable) { + int16_t state = RADIOLIB_ERR_NONE; + + if (this->promiscuous == enable) { + return(state); + } + + if (enable == true) { + // disable preamble detection and generation + state = setPreambleLength(0); + RADIOLIB_ASSERT(state); + + // disable sync word filtering and insertion + state = disableSyncWordFiltering(); + RADIOLIB_ASSERT(state); + + // disable CRC filtering + state = setCrcFiltering(false); + } else { + // enable preamble detection and generation + state = setPreambleLength(RADIOLIB_RF69_DEFAULT_PREAMBLELEN); + RADIOLIB_ASSERT(state); + + // enable sync word filtering and insertion + state = enableSyncWordFiltering(); + RADIOLIB_ASSERT(state); + + // enable CRC filtering + state = setCrcFiltering(true); + } + if(state == RADIOLIB_ERR_NONE) { + this->promiscuous = enable; + } + + + return(state); +} + +int16_t RF69::setDataShaping(uint8_t sh) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set data shaping + switch(sh) { + case RADIOLIB_SHAPING_NONE: + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_NO_SHAPING, 1, 0)); + case RADIOLIB_SHAPING_0_3: + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_0_3, 1, 0)); + case RADIOLIB_SHAPING_0_5: + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_0_5, 1, 0)); + case RADIOLIB_SHAPING_1_0: + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_1_0, 1, 0)); + default: + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); + } +} + +int16_t RF69::setEncoding(uint8_t encoding) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set encoding + switch(encoding) { + case RADIOLIB_ENCODING_NRZ: + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_DC_FREE_NONE, 6, 5)); + case RADIOLIB_ENCODING_MANCHESTER: + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_DC_FREE_MANCHESTER, 6, 5)); + case RADIOLIB_ENCODING_WHITENING: + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_DC_FREE_WHITENING, 6, 5)); + default: + return(RADIOLIB_ERR_INVALID_ENCODING); + } +} + +int16_t RF69::setLnaTestBoost(bool value) { + if(value) { + return (this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_LNA, RADIOLIB_RF69_TEST_LNA_BOOST_HIGH, 7, 0)); + } + + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_TEST_LNA_BOOST_NORMAL, RADIOLIB_RF69_TEST_LNA_BOOST_HIGH, 7, 0)); +} + +float RF69::getRSSI() { + return(-1.0 * (this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_RSSI_VALUE)/2.0)); +} + +int16_t RF69::setRSSIThreshold(float dbm) { + RADIOLIB_CHECK_RANGE(dbm, -127.5, 0, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD); + + return this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); +} + +void RF69::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { + this->mod->setRfSwitchPins(rxEn, txEn); +} + +void RF69::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + this->mod->setRfSwitchTable(pins, table); +} + +uint8_t RF69::randomByte() { + // set mode to Rx + setMode(RADIOLIB_RF69_RX); + + // wait a bit for the RSSI reading to stabilise + this->mod->hal->delay(10); + + // read RSSI value 8 times, always keep just the least significant bit + uint8_t randByte = 0x00; + for(uint8_t i = 0; i < 8; i++) { + randByte |= ((this->mod->SPIreadRegister(RADIOLIB_RF69_REG_RSSI_VALUE) & 0x01) << i); + } + + // set mode to standby + setMode(RADIOLIB_RF69_STANDBY); + + return(randByte); +} + +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE +void RF69::setDirectAction(void (*func)(void)) { + setDio1Action(func); +} + +void RF69::readBit(uint32_t pin) { + updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin)); +} +#endif + +int16_t RF69::setDIOMapping(uint32_t pin, uint32_t value) { + if(pin > 5) { + return(RADIOLIB_ERR_INVALID_DIO_PIN); + } + + if(pin < 4) { + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin)); + } + + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin)); +} + +Module* RF69::getMod() { + return(this->mod); +} + +int16_t RF69::getChipVersion() { + return(this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_VERSION)); +} + +int16_t RF69::config() { + int16_t state = RADIOLIB_ERR_NONE; + + // set mode to STANDBY + state = setMode(RADIOLIB_RF69_STANDBY); + RADIOLIB_ASSERT(state); + + // set operation modes + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OP_MODE, RADIOLIB_RF69_SEQUENCER_ON | RADIOLIB_RF69_LISTEN_OFF, 7, 6); + RADIOLIB_ASSERT(state); + + // enable over-current protection + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON, 4, 4); + RADIOLIB_ASSERT(state); + + // set data mode, modulation type and shaping + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_PACKET_MODE | RADIOLIB_RF69_FSK, 6, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_0_3, 1, 0); + RADIOLIB_ASSERT(state); + + // set RSSI threshold + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, RADIOLIB_RF69_RSSI_THRESHOLD, 7, 0); + RADIOLIB_ASSERT(state); + + // reset FIFO flag + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_IRQ_FLAGS_2, RADIOLIB_RF69_IRQ_FIFO_OVERRUN); + + // disable ClkOut on DIO5 + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_2, RADIOLIB_RF69_CLK_OUT_OFF, 2, 0); + RADIOLIB_ASSERT(state); + + // set packet configuration and disable encryption + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_PACKET_FORMAT_VARIABLE | RADIOLIB_RF69_DC_FREE_NONE | RADIOLIB_RF69_CRC_ON | RADIOLIB_RF69_CRC_AUTOCLEAR_ON | RADIOLIB_RF69_ADDRESS_FILTERING_OFF, 7, 1); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_INTER_PACKET_RX_DELAY, 7, 4); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_AUTO_RX_RESTART_ON | RADIOLIB_RF69_AES_OFF, 1, 0); + RADIOLIB_ASSERT(state); + + // set payload length + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PAYLOAD_LENGTH, RADIOLIB_RF69_PAYLOAD_LENGTH, 7, 0); + RADIOLIB_ASSERT(state); + + // set FIFO threshold + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY | RADIOLIB_RF69_FIFO_THRESH, 7, 0); + RADIOLIB_ASSERT(state); + + // set Rx timeouts + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_1, RADIOLIB_RF69_TIMEOUT_RX_START, 7, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_2, RADIOLIB_RF69_TIMEOUT_RSSI_THRESH, 7, 0); + RADIOLIB_ASSERT(state); + + // enable improved fading margin + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_DAGC, RADIOLIB_RF69_CONTINUOUS_DAGC_LOW_BETA_OFF, 7, 0); + + return(state); +} + +int16_t RF69::setPacketMode(uint8_t mode, uint8_t len) { + // check length + if (len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set to fixed packet length + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, mode, 7, 7); + RADIOLIB_ASSERT(state); + + // set length to register + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PAYLOAD_LENGTH, len); + RADIOLIB_ASSERT(state); + + // update the cached value + this->packetLengthConfig = mode; + return(state); +} + +int16_t RF69::setMode(uint8_t mode) { + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OP_MODE, mode, 4, 2)); +} + +void RF69::clearIRQFlags() { + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_IRQ_FLAGS_1, 0b11111111); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_IRQ_FLAGS_2, 0b11111111); +} + +void RF69::clearFIFO(size_t count) { + while(count) { + this->mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); + count--; + } +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/RF69/RF69.h b/lib/lib_rf/RadioLib/src/modules/RF69/RF69.h new file mode 100644 index 000000000..177b839ca --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/RF69/RF69.h @@ -0,0 +1,1038 @@ +#if !defined(_RADIOLIB_RF69_H) +#define _RADIOLIB_RF69_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_RF69 + +#include "../../Module.h" + +#include "../../protocols/PhysicalLayer/PhysicalLayer.h" + +// RF69 physical layer properties +#define RADIOLIB_RF69_FREQUENCY_STEP_SIZE 61.03515625 +#define RADIOLIB_RF69_MAX_PACKET_LENGTH 64 +#define RADIOLIB_RF69_CRYSTAL_FREQ 32.0 +#define RADIOLIB_RF69_DIV_EXPONENT 19 + +// RF69 register map +#define RADIOLIB_RF69_REG_FIFO 0x00 +#define RADIOLIB_RF69_REG_OP_MODE 0x01 +#define RADIOLIB_RF69_REG_DATA_MODUL 0x02 +#define RADIOLIB_RF69_REG_BITRATE_MSB 0x03 +#define RADIOLIB_RF69_REG_BITRATE_LSB 0x04 +#define RADIOLIB_RF69_REG_FDEV_MSB 0x05 +#define RADIOLIB_RF69_REG_FDEV_LSB 0x06 +#define RADIOLIB_RF69_REG_FRF_MSB 0x07 +#define RADIOLIB_RF69_REG_FRF_MID 0x08 +#define RADIOLIB_RF69_REG_FRF_LSB 0x09 +#define RADIOLIB_RF69_REG_OSC_1 0x0A +#define RADIOLIB_RF69_REG_AFC_CTRL 0x0B +#define RADIOLIB_RF69_REG_LISTEN_1 0x0D +#define RADIOLIB_RF69_REG_LISTEN_2 0x0E +#define RADIOLIB_RF69_REG_LISTEN_3 0x0F +#define RADIOLIB_RF69_REG_VERSION 0x10 +#define RADIOLIB_RF69_REG_PA_LEVEL 0x11 +#define RADIOLIB_RF69_REG_PA_RAMP 0x12 +#define RADIOLIB_RF69_REG_OCP 0x13 +#define RADIOLIB_RF69_REG_LNA 0x18 +#define RADIOLIB_RF69_REG_RX_BW 0x19 +#define RADIOLIB_RF69_REG_AFC_BW 0x1A +#define RADIOLIB_RF69_REG_OOK_PEAK 0x1B +#define RADIOLIB_RF69_REG_OOK_AVG 0x1C +#define RADIOLIB_RF69_REG_OOK_FIX 0x1D +#define RADIOLIB_RF69_REG_AFC_FEI 0x1E +#define RADIOLIB_RF69_REG_AFC_MSB 0x1F +#define RADIOLIB_RF69_REG_AFC_LSB 0x20 +#define RADIOLIB_RF69_REG_FEI_MSB 0x21 +#define RADIOLIB_RF69_REG_FEI_LSB 0x22 +#define RADIOLIB_RF69_REG_RSSI_CONFIG 0x23 +#define RADIOLIB_RF69_REG_RSSI_VALUE 0x24 +#define RADIOLIB_RF69_REG_DIO_MAPPING_1 0x25 +#define RADIOLIB_RF69_REG_DIO_MAPPING_2 0x26 +#define RADIOLIB_RF69_REG_IRQ_FLAGS_1 0x27 +#define RADIOLIB_RF69_REG_IRQ_FLAGS_2 0x28 +#define RADIOLIB_RF69_REG_RSSI_THRESH 0x29 +#define RADIOLIB_RF69_REG_RX_TIMEOUT_1 0x2A +#define RADIOLIB_RF69_REG_RX_TIMEOUT_2 0x2B +#define RADIOLIB_RF69_REG_PREAMBLE_MSB 0x2C +#define RADIOLIB_RF69_REG_PREAMBLE_LSB 0x2D +#define RADIOLIB_RF69_REG_SYNC_CONFIG 0x2E +#define RADIOLIB_RF69_REG_SYNC_VALUE_1 0x2F +#define RADIOLIB_RF69_REG_SYNC_VALUE_2 0x30 +#define RADIOLIB_RF69_REG_SYNC_VALUE_3 0x31 +#define RADIOLIB_RF69_REG_SYNC_VALUE_4 0x32 +#define RADIOLIB_RF69_REG_SYNC_VALUE_5 0x33 +#define RADIOLIB_RF69_REG_SYNC_VALUE_6 0x34 +#define RADIOLIB_RF69_REG_SYNC_VALUE_7 0x35 +#define RADIOLIB_RF69_REG_SYNC_VALUE_8 0x36 +#define RADIOLIB_RF69_REG_PACKET_CONFIG_1 0x37 +#define RADIOLIB_RF69_REG_PAYLOAD_LENGTH 0x38 +#define RADIOLIB_RF69_REG_NODE_ADRS 0x39 +#define RADIOLIB_RF69_REG_BROADCAST_ADRS 0x3A +#define RADIOLIB_RF69_REG_AUTO_MODES 0x3B +#define RADIOLIB_RF69_REG_FIFO_THRESH 0x3C +#define RADIOLIB_RF69_REG_PACKET_CONFIG_2 0x3D +#define RADIOLIB_RF69_REG_AES_KEY_1 0x3E +#define RADIOLIB_RF69_REG_AES_KEY_2 0x3F +#define RADIOLIB_RF69_REG_AES_KEY_3 0x40 +#define RADIOLIB_RF69_REG_AES_KEY_4 0x41 +#define RADIOLIB_RF69_REG_AES_KEY_5 0x42 +#define RADIOLIB_RF69_REG_AES_KEY_6 0x43 +#define RADIOLIB_RF69_REG_AES_KEY_7 0x44 +#define RADIOLIB_RF69_REG_AES_KEY_8 0x45 +#define RADIOLIB_RF69_REG_AES_KEY_9 0x46 +#define RADIOLIB_RF69_REG_AES_KEY_10 0x47 +#define RADIOLIB_RF69_REG_AES_KEY_11 0x48 +#define RADIOLIB_RF69_REG_AES_KEY_12 0x49 +#define RADIOLIB_RF69_REG_AES_KEY_13 0x4A +#define RADIOLIB_RF69_REG_AES_KEY_14 0x4B +#define RADIOLIB_RF69_REG_AES_KEY_15 0x4C +#define RADIOLIB_RF69_REG_AES_KEY_16 0x4D +#define RADIOLIB_RF69_REG_TEMP_1 0x4E +#define RADIOLIB_RF69_REG_TEMP_2 0x4F +#define RADIOLIB_RF69_REG_TEST_LNA 0x58 +#define RADIOLIB_RF69_REG_TEST_PA1 0x5A +#define RADIOLIB_RF69_REG_TEST_PA2 0x5C +#define RADIOLIB_RF69_REG_TEST_DAGC 0x6F + +// RF69 modem settings +// RADIOLIB_RF69_REG_OP_MODE MSB LSB DESCRIPTION +#define RADIOLIB_RF69_SEQUENCER_OFF 0b10000000 // 7 7 disable automatic sequencer +#define RADIOLIB_RF69_SEQUENCER_ON 0b00000000 // 7 7 enable automatic sequencer +#define RADIOLIB_RF69_LISTEN_OFF 0b00000000 // 6 6 disable Listen mode +#define RADIOLIB_RF69_LISTEN_ON 0b01000000 // 6 6 enable Listen mode +#define RADIOLIB_RF69_LISTEN_ABORT 0b00100000 // 5 5 abort Listen mode (has to be set together with RF69_LISTEN_OFF) +#define RADIOLIB_RF69_SLEEP 0b00000000 // 4 2 sleep +#define RADIOLIB_RF69_STANDBY 0b00000100 // 4 2 standby +#define RADIOLIB_RF69_FS 0b00001000 // 4 2 frequency synthesis +#define RADIOLIB_RF69_TX 0b00001100 // 4 2 transmit +#define RADIOLIB_RF69_RX 0b00010000 // 4 2 receive + +// RADIOLIB_RF69_REG_DATA_MODUL +#define RADIOLIB_RF69_PACKET_MODE 0b00000000 // 6 5 packet mode (default) +#define RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC 0b01000000 // 6 5 continuous mode with bit synchronizer +#define RADIOLIB_RF69_CONTINUOUS_MODE 0b01100000 // 6 5 continuous mode without bit synchronizer +#define RADIOLIB_RF69_FSK 0b00000000 // 4 3 modulation: FSK (default) +#define RADIOLIB_RF69_OOK 0b00001000 // 4 3 OOK +#define RADIOLIB_RF69_NO_SHAPING 0b00000000 // 1 0 modulation shaping: no shaping (default) +#define RADIOLIB_RF69_FSK_GAUSSIAN_1_0 0b00000001 // 1 0 FSK modulation Gaussian filter, BT = 1.0 +#define RADIOLIB_RF69_FSK_GAUSSIAN_0_5 0b00000010 // 1 0 FSK modulation Gaussian filter, BT = 0.5 +#define RADIOLIB_RF69_FSK_GAUSSIAN_0_3 0b00000011 // 1 0 FSK modulation Gaussian filter, BT = 0.3 +#define RADIOLIB_RF69_OOK_FILTER_BR 0b00000001 // 1 0 OOK modulation filter, f_cutoff = BR +#define RADIOLIB_RF69_OOK_FILTER_2BR 0b00000010 // 1 0 OOK modulation filter, f_cutoff = 2*BR + +// RADIOLIB_RF69_REG_BITRATE_MSB + REG_BITRATE_LSB +#define RADIOLIB_RF69_BITRATE_MSB 0x1A // 7 0 bit rate setting: rate = F(XOSC) / BITRATE +#define RADIOLIB_RF69_BITRATE_LSB 0x0B // 7 0 default value: 4.8 kbps + +// RADIOLIB_RF69_REG_FDEV_MSB + REG_FDEV_LSB +#define RADIOLIB_RF69_FDEV_MSB 0x00 // 5 0 frequency deviation: f_dev = f_step * FDEV +#define RADIOLIB_RF69_FDEV_LSB 0x52 // 7 0 default value: 5 kHz + +// RADIOLIB_RF69_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB +#define RADIOLIB_RF69_FRF_MSB 0xE4 // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 +#define RADIOLIB_RF69_FRF_MID 0xC0 // 7 0 where F(XOSC) = 32 MHz +#define RADIOLIB_RF69_FRF_LSB 0x00 // 7 0 default value: 915 MHz + +// RADIOLIB_RF69_REG_OSC_1 +#define RADIOLIB_RF69_RC_CAL_START 0b10000000 // 7 7 force RC oscillator calibration +#define RADIOLIB_RF69_RC_CAL_RUNNING 0b00000000 // 6 6 RC oscillator calibration is still running +#define RADIOLIB_RF69_RC_CAL_DONE 0b00000000 // 5 5 RC oscillator calibration has finished + +// RADIOLIB_RF69_REG_AFC_CTRL +#define RADIOLIB_RF69_AFC_LOW_BETA_OFF 0b00000000 // 5 5 standard AFC routine +#define RADIOLIB_RF69_AFC_LOW_BETA_ON 0b00100000 // 5 5 improved AFC routine for signals with modulation index less than 2 + +// RADIOLIB_RF69_REG_LISTEN_1 +#define RADIOLIB_RF69_LISTEN_RES_IDLE_64_US 0b01000000 // 7 6 resolution of Listen mode idle time: 64 us +#define RADIOLIB_RF69_LISTEN_RES_IDLE_4_1_MS 0b10000000 // 7 6 4.1 ms (default) +#define RADIOLIB_RF69_LISTEN_RES_IDLE_262_MS 0b11000000 // 7 6 262 ms +#define RADIOLIB_RF69_LISTEN_RES_RX_64_US 0b00010000 // 5 4 resolution of Listen mode rx time: 64 us (default) +#define RADIOLIB_RF69_LISTEN_RES_RX_4_1_MS 0b00100000 // 5 4 4.1 ms +#define RADIOLIB_RF69_LISTEN_RES_RX_262_MS 0b00110000 // 5 4 262 ms +#define RADIOLIB_RF69_LISTEN_ACCEPT_ABOVE_RSSI_THRESH 0b00000000 // 3 3 packet acceptance criteria: RSSI above threshold +#define RADIOLIB_RF69_LISTEN_ACCEPT_MATCH_SYNC_ADDRESS 0b00001000 // 3 3 RSSI above threshold AND sync address matched +#define RADIOLIB_RF69_LISTEN_END_KEEP_RX 0b00000000 // 2 1 action after packet acceptance: stay in Rx mode +#define RADIOLIB_RF69_LISTEN_END_KEEP_RX_TIMEOUT 0b00000010 // 2 1 stay in Rx mode until timeout (default) +#define RADIOLIB_RF69_LISTEN_END_KEEP_RX_TIMEOUT_RESUME 0b00000100 // 2 1 stay in Rx mode until timeout, Listen mode will resume + +// RADIOLIB_RF69_REG_LISTEN_2 +#define RADIOLIB_RF69_LISTEN_COEF_IDLE 0xF5 // 7 0 duration of idle phase in Listen mode + +// RADIOLIB_RF69_REG_LISTEN_3 +#define RADIOLIB_RF69_LISTEN_COEF_RX 0x20 // 7 0 duration of Rx phase in Listen mode + +// RADIOLIB_RF69_REG_VERSION +#define RADIOLIB_RF69_CHIP_VERSION 0x24 // 7 0 + +// RADIOLIB_RF69_REG_PA_LEVEL +#define RADIOLIB_RF69_PA0_OFF 0b00000000 // 7 7 PA0 disabled +#define RADIOLIB_RF69_PA0_ON 0b10000000 // 7 7 PA0 enabled (default) +#define RADIOLIB_RF69_PA1_OFF 0b00000000 // 6 6 PA1 disabled (default) +#define RADIOLIB_RF69_PA1_ON 0b01000000 // 6 6 PA1 enabled +#define RADIOLIB_RF69_PA2_OFF 0b00000000 // 5 5 PA2 disabled (default) +#define RADIOLIB_RF69_PA2_ON 0b00100000 // 5 5 PA2 enabled +#define RADIOLIB_RF69_OUTPUT_POWER 0b00011111 // 4 0 output power: P_out = -18 + OUTPUT_POWER + +// RADIOLIB_RF69_REG_PA_RAMP +#define RADIOLIB_RF69_PA_RAMP_3_4_MS 0b00000000 // 3 0 PA ramp rise/fall time: 3.4 ms +#define RADIOLIB_RF69_PA_RAMP_2_MS 0b00000001 // 3 0 2 ms +#define RADIOLIB_RF69_PA_RAMP_1_MS 0b00000010 // 3 0 1 ms +#define RADIOLIB_RF69_PA_RAMP_500_US 0b00000011 // 3 0 500 us +#define RADIOLIB_RF69_PA_RAMP_250_US 0b00000100 // 3 0 250 us +#define RADIOLIB_RF69_PA_RAMP_125_US 0b00000101 // 3 0 125 us +#define RADIOLIB_RF69_PA_RAMP_100_US 0b00000110 // 3 0 100 us +#define RADIOLIB_RF69_PA_RAMP_62_US 0b00000111 // 3 0 62 us +#define RADIOLIB_RF69_PA_RAMP_50_US 0b00001000 // 3 0 50 us +#define RADIOLIB_RF69_PA_RAMP_40_US 0b00001001 // 3 0 40 us (default) +#define RADIOLIB_RF69_PA_RAMP_31_US 0b00001010 // 3 0 31 us +#define RADIOLIB_RF69_PA_RAMP_25_US 0b00001011 // 3 0 25 us +#define RADIOLIB_RF69_PA_RAMP_20_US 0b00001100 // 3 0 20 us +#define RADIOLIB_RF69_PA_RAMP_15_US 0b00001101 // 3 0 15 us +#define RADIOLIB_RF69_PA_RAMP_12_US 0b00001110 // 3 0 12 us +#define RADIOLIB_RF69_PA_RAMP_10_US 0b00001111 // 3 0 10 us + +// RADIOLIB_RF69_REG_OCP +#define RADIOLIB_RF69_OCP_OFF 0b00000000 // 4 4 PA overload current protection disabled +#define RADIOLIB_RF69_OCP_ON 0b00010000 // 4 4 PA overload current protection enabled +#define RADIOLIB_RF69_OCP_TRIM 0b00001010 // 3 0 OCP current: I_max(OCP_TRIM = 0b1010) = 95 mA + +// RADIOLIB_RF69_REG_LNA +#define RADIOLIB_RF69_LNA_Z_IN_50_OHM 0b00000000 // 7 7 LNA input impedance: 50 ohm +#define RADIOLIB_RF69_LNA_Z_IN_200_OHM 0b10000000 // 7 7 200 ohm +#define RADIOLIB_RF69_LNA_CURRENT_GAIN 0b00001000 // 5 3 manually set LNA current gain +#define RADIOLIB_RF69_LNA_GAIN_AUTO 0b00000000 // 2 0 LNA gain setting: set automatically by AGC +#define RADIOLIB_RF69_LNA_GAIN_MAX 0b00000001 // 2 0 max gain +#define RADIOLIB_RF69_LNA_GAIN_MAX_6_DB 0b00000010 // 2 0 max gain - 6 dB +#define RADIOLIB_RF69_LNA_GAIN_MAX_12_DB 0b00000011 // 2 0 max gain - 12 dB +#define RADIOLIB_RF69_LNA_GAIN_MAX_24_DB 0b00000100 // 2 0 max gain - 24 dB +#define RADIOLIB_RF69_LNA_GAIN_MAX_36_DB 0b00000101 // 2 0 max gain - 36 dB +#define RADIOLIB_RF69_LNA_GAIN_MAX_48_DB 0b00000110 // 2 0 max gain - 48 dB + +// RADIOLIB_RF69_REG_RX_BW +#define RADIOLIB_RF69_DCC_FREQ 0b01000000 // 7 5 DC offset canceller cutoff frequency (4% Rx BW by default) +#define RADIOLIB_RF69_RX_BW_MANT_16 0b00000000 // 4 3 Channel filter bandwidth FSK: RxBw = F(XOSC)/(RxBwMant * 2^(RxBwExp + 2)) +#define RADIOLIB_RF69_RX_BW_MANT_20 0b00001000 // 4 3 OOK: RxBw = F(XOSC)/(RxBwMant * 2^(RxBwExp + 3)) +#define RADIOLIB_RF69_RX_BW_MANT_24 0b00010000 // 4 3 +#define RADIOLIB_RF69_RX_BW_EXP 0b00000101 // 2 0 default RxBwExp value = 5 + +// RADIOLIB_RF69_REG_AFC_BW +#define RADIOLIB_RF69_DCC_FREQ_AFC 0b10000000 // 7 5 default DccFreq parameter for AFC +#define RADIOLIB_RF69_DCC_RX_BW_MANT_AFC 0b00001000 // 4 3 default RxBwMant parameter for AFC +#define RADIOLIB_RF69_DCC_RX_BW_EXP_AFC 0b00000011 // 2 0 default RxBwExp parameter for AFC + +// RADIOLIB_RF69_REG_OOK_PEAK +#define RADIOLIB_RF69_OOK_THRESH_FIXED 0b00000000 // 7 6 OOK threshold type: fixed +#define RADIOLIB_RF69_OOK_THRESH_PEAK 0b01000000 // 7 6 peak (default) +#define RADIOLIB_RF69_OOK_THRESH_AVERAGE 0b10000000 // 7 6 average +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_0_5_DB 0b00000000 // 5 3 OOK demodulator step size: 0.5 dB (default) +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_1_0_DB 0b00001000 // 5 3 1.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_1_5_DB 0b00010000 // 5 3 1.5 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_2_0_DB 0b00011000 // 5 3 2.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_3_0_DB 0b00100000 // 5 3 3.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_4_0_DB 0b00101000 // 5 3 4.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_5_0_DB 0b00110000 // 5 3 5.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_6_0_DB 0b00111000 // 5 3 6.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_1_CHIP 0b00000000 // 2 0 OOK demodulator step period: once per chip (default) +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_2_CHIP 0b00000001 // 2 0 once every 2 chips +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_4_CHIP 0b00000010 // 2 0 once every 4 chips +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_8_CHIP 0b00000011 // 2 0 once every 8 chips +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_2_1_CHIP 0b00000100 // 2 0 2 times per chip +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_4_1_CHIP 0b00000101 // 2 0 4 times per chip +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_8_1_CHIP 0b00000110 // 2 0 8 times per chip +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_16_1_CHIP 0b00000111 // 2 0 16 times per chip + +// RADIOLIB_RF69_REG_OOK_AVG +#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_32_PI 0b00000000 // 7 6 OOK average filter coefficient: chip rate / 32*pi +#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_8_PI 0b01000000 // 7 6 chip rate / 8*pi +#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_4_PI 0b10000000 // 7 6 chip rate / 4*pi (default) +#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_2_PI 0b11000000 // 7 6 chip rate / 2*pi + +// RADIOLIB_RF69_REG_OOK_FIX +#define RADIOLIB_RF69_OOK_FIXED_THRESH 0b00000110 // 7 0 default OOK fixed threshold (6 dB) + +// RADIOLIB_RF69_REG_AFC_FEI +#define RADIOLIB_RF69_FEI_RUNNING 0b00000000 // 6 6 FEI status: on-going +#define RADIOLIB_RF69_FEI_DONE 0b01000000 // 6 6 done +#define RADIOLIB_RF69_FEI_START 0b00100000 // 5 5 force new FEI measurement +#define RADIOLIB_RF69_AFC_RUNNING 0b00000000 // 4 4 AFC status: on-going +#define RADIOLIB_RF69_AFC_DONE 0b00010000 // 4 4 done +#define RADIOLIB_RF69_AFC_AUTOCLEAR_OFF 0b00000000 // 3 3 AFC register autoclear disabled +#define RADIOLIB_RF69_AFC_AUTOCLEAR_ON 0b00001000 // 3 3 AFC register autoclear enabled +#define RADIOLIB_RF69_AFC_AUTO_OFF 0b00000000 // 2 2 perform AFC only manually +#define RADIOLIB_RF69_AFC_AUTO_ON 0b00000100 // 2 2 perform AFC each time Rx mode is started +#define RADIOLIB_RF69_AFC_CLEAR 0b00000010 // 1 1 clear AFC register +#define RADIOLIB_RF69_AFC_START 0b00000001 // 0 0 start AFC + +// RADIOLIB_RF69_REG_RSSI_CONFIG +#define RADIOLIB_RF69_RSSI_RUNNING 0b00000000 // 1 1 RSSI status: on-going +#define RADIOLIB_RF69_RSSI_DONE 0b00000010 // 1 1 done +#define RADIOLIB_RF69_RSSI_START 0b00000001 // 0 0 start RSSI measurement + +// RADIOLIB_RF69_REG_DIO_MAPPING_1 +#define RADIOLIB_RF69_DIO0_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_PLL_LOCK 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_TIMEOUT 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_RSSI 0b10000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_CRC_OK 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_PAYLOAD_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_SYNC_ADDRESS 0b10000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_RSSI 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO1_CONT_PLL_LOCK 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO1_CONT_DCLK 0b00000000 // 5 4 +#define RADIOLIB_RF69_DIO1_CONT_RX_READY 0b00010000 // 5 4 +#define RADIOLIB_RF69_DIO1_CONT_SYNC_ADDRESS 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO1_CONT_TX_READY 0b00010000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_FIFO_FULL 0b00010000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_FIFO_NOT_EMPTY 0b00100000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_PLL_LOCK 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_TIMEOUT 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO2_CONT_DATA 0b00000000 // 3 2 +#define RADIOLIB_RF69_DIO2_PACK_FIFO_NOT_EMPTY 0b00000000 // 3 2 +#define RADIOLIB_RF69_DIO2_PACK_AUTO_MODE 0b00001100 // 3 2 +#define RADIOLIB_RF69_DIO2_PACK_DATA 0b00000100 // 3 2 +#define RADIOLIB_RF69_DIO3_CONT_AUTO_MODE 0b00000010 // 0 1 +#define RADIOLIB_RF69_DIO3_CONT_RSSI 0b00000000 // 0 1 +#define RADIOLIB_RF69_DIO3_CONT_RX_READY 0b00000001 // 0 1 +#define RADIOLIB_RF69_DIO3_CONT_TIMEOUT 0b00000011 // 0 1 +#define RADIOLIB_RF69_DIO3_CONT_TX_READY 0b00000001 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_FIFO_FULL 0b00000000 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_PLL_LOCK 0b00000011 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_RSSI 0b00000001 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_SYNC_ADDRESSS 0b00000010 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_TX_READY 0b00000001 // 0 1 + +// RADIOLIB_RF69_REG_DIO_MAPPING_2 +#define RADIOLIB_RF69_DIO4_CONT_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO4_CONT_TIMEOUT 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO4_CONT_RX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO4_CONT_SYNC_ADDRESS 0b10000000 // 7 6 +#define RADIOLIB_RF69_DIO4_CONT_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_TIMEOUT 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_RSSI 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_RX_READY 0b10000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_MODE_READY 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO5_CONT_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_RF69_DIO5_CONT_RSSI 0b00010000 // 5 4 +#define RADIOLIB_RF69_DIO5_PACK_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_RF69_DIO5_PACK_DATA 0b00010000 // 5 4 +#define RADIOLIB_RF69_CLK_OUT_FXOSC 0b00000000 // 2 0 ClkOut frequency: F(XOSC) +#define RADIOLIB_RF69_CLK_OUT_FXOSC_2 0b00000001 // 2 0 F(XOSC) / 2 +#define RADIOLIB_RF69_CLK_OUT_FXOSC_4 0b00000010 // 2 0 F(XOSC) / 4 +#define RADIOLIB_RF69_CLK_OUT_FXOSC_8 0b00000011 // 2 0 F(XOSC) / 8 +#define RADIOLIB_RF69_CLK_OUT_FXOSC_16 0b00000100 // 2 0 F(XOSC) / 16 +#define RADIOLIB_RF69_CLK_OUT_FXOSC_32 0b00000101 // 2 0 F(XOSC) / 31 +#define RADIOLIB_RF69_CLK_OUT_RC 0b00000110 // 2 0 RC +#define RADIOLIB_RF69_CLK_OUT_OFF 0b00000111 // 2 0 disabled (default) + +// RADIOLIB_RF69_REG_IRQ_FLAGS_1 +#define RADIOLIB_RF69_IRQ_MODE_READY 0b10000000 // 7 7 requested mode was set +#define RADIOLIB_RF69_IRQ_RX_READY 0b01000000 // 6 6 Rx mode ready +#define RADIOLIB_RF69_IRQ_TX_READY 0b00100000 // 5 5 Tx mode ready +#define RADIOLIB_RF69_IRQ_PLL_LOCK 0b00010000 // 4 4 PLL is locked +#define RADIOLIB_RF69_IRQ_RSSI 0b00001000 // 3 3 RSSI value exceeded RssiThreshold +#define RADIOLIB_RF69_IRQ_TIMEOUT 0b00000100 // 2 2 timeout occurred +#define RADIOLIB_RF69_IRQ_AUTO_MODE 0b00000010 // 1 1 entered intermediate mode +#define RADIOLIB_RF69_SYNC_ADDRESS_MATCH 0b00000001 // 0 0 sync address detected + +// RADIOLIB_RF69_REG_IRQ_FLAGS_2 +#define RADIOLIB_RF69_IRQ_FIFO_FULL 0b10000000 // 7 7 FIFO is full +#define RADIOLIB_RF69_IRQ_FIFO_NOT_EMPTY 0b01000000 // 6 6 FIFO contains at least 1 byte +#define RADIOLIB_RF69_IRQ_FIFO_LEVEL 0b00100000 // 5 5 FIFO contains more than FifoThreshold bytes +#define RADIOLIB_RF69_IRQ_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occurred +#define RADIOLIB_RF69_IRQ_PACKET_SENT 0b00001000 // 3 3 packet was sent +#define RADIOLIB_RF69_IRQ_PAYLOAD_READY 0b00000100 // 2 2 last payload byte received and CRC check passed +#define RADIOLIB_RF69_IRQ_CRC_OK 0b00000010 // 1 1 CRC check passed + +// RADIOLIB_RF69_REG_RSSI_THRESH +#define RADIOLIB_RF69_RSSI_THRESHOLD 0xE4 // 7 0 RSSI threshold level (2 dB by default) + +// RADIOLIB_RF69_REG_RX_TIMEOUT_1 +#define RADIOLIB_RF69_TIMEOUT_RX_START_OFF 0x00 // 7 0 RSSI interrupt timeout disabled (default) +#define RADIOLIB_RF69_TIMEOUT_RX_START 0xFF // 7 0 timeout will occur if RSSI interrupt is not received + +// RADIOLIB_RF69_REG_RX_TIMEOUT_2 +#define RADIOLIB_RF69_TIMEOUT_RSSI_THRESH_OFF 0x00 // 7 0 PayloadReady interrupt timeout disabled (default) +#define RADIOLIB_RF69_TIMEOUT_RSSI_THRESH 0xFF // 7 0 timeout will occur if PayloadReady interrupt is not received + +// RADIOLIB_RF69_REG_PREAMBLE_MSB + REG_PREAMBLE_MSB +#define RADIOLIB_RF69_PREAMBLE_MSB 0x00 // 7 0 2-byte preamble size value +#define RADIOLIB_RF69_PREAMBLE_LSB 0x03 // 7 0 + +// RADIOLIB_RF69_REG_SYNC_CONFIG +#define RADIOLIB_RF69_SYNC_OFF 0b00000000 // 7 7 sync word detection off +#define RADIOLIB_RF69_SYNC_ON 0b10000000 // 7 7 sync word detection on (default) +#define RADIOLIB_RF69_FIFO_FILL_CONDITION_SYNC 0b00000000 // 6 6 FIFO fill condition: on SyncAddress interrupt (default) +#define RADIOLIB_RF69_FIFO_FILL_CONDITION 0b01000000 // 6 6 as long as the bit is set +#define RADIOLIB_RF69_SYNC_SIZE 0b00001000 // 5 3 size of sync word: SyncSize + 1 bytes +#define RADIOLIB_RF69_SYNC_TOL 0b00000000 // 2 0 number of tolerated errors in sync word + +// RADIOLIB_RF69_REG_SYNC_VALUE_1 - SYNC_VALUE_8 +#define RADIOLIB_RF69_SYNC_BYTE_1 0x01 // 7 0 sync word: 1st byte (MSB) +#define RADIOLIB_RF69_SYNC_BYTE_2 0x01 // 7 0 2nd byte +#define RADIOLIB_RF69_SYNC_BYTE_3 0x01 // 7 0 3rd byte +#define RADIOLIB_RF69_SYNC_BYTE_4 0x01 // 7 0 4th byte +#define RADIOLIB_RF69_SYNC_BYTE_5 0x01 // 7 0 5th byte +#define RADIOLIB_RF69_SYNC_BYTE_6 0x01 // 7 0 6th byte +#define RADIOLIB_RF69_SYNC_BYTE_7 0x01 // 7 0 7th byte +#define RADIOLIB_RF69_SYNC_BYTE_8 0x01 // 7 0 8th byte (LSB) + +// RADIOLIB_RF69_REG_PACKET_CONFIG_1 +#define RADIOLIB_RF69_PACKET_FORMAT_FIXED 0b00000000 // 7 7 fixed packet length (default) +#define RADIOLIB_RF69_PACKET_FORMAT_VARIABLE 0b10000000 // 7 7 variable packet length +#define RADIOLIB_RF69_DC_FREE_NONE 0b00000000 // 6 5 DC-free encoding: none (default) +#define RADIOLIB_RF69_DC_FREE_MANCHESTER 0b00100000 // 6 5 Manchester +#define RADIOLIB_RF69_DC_FREE_WHITENING 0b01000000 // 6 5 Whitening +#define RADIOLIB_RF69_CRC_OFF 0b00000000 // 4 4 CRC disabled +#define RADIOLIB_RF69_CRC_ON 0b00010000 // 4 4 CRC enabled (default) +#define RADIOLIB_RF69_CRC_AUTOCLEAR_ON 0b00000000 // 3 3 discard packet when CRC check fails (default) +#define RADIOLIB_RF69_CRC_AUTOCLEAR_OFF 0b00001000 // 3 3 keep packet when CRC check fails +#define RADIOLIB_RF69_ADDRESS_FILTERING_OFF 0b00000000 // 2 1 address filtering: none (default) +#define RADIOLIB_RF69_ADDRESS_FILTERING_NODE 0b00000010 // 2 1 node +#define RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST 0b00000100 // 2 1 node or broadcast + +// RADIOLIB_RF69_REG_PAYLOAD_LENGTH +#define RADIOLIB_RF69_PAYLOAD_LENGTH 0xFF // 7 0 payload length + +// RADIOLIB_RF69_REG_AUTO_MODES +#define RADIOLIB_RF69_ENTER_COND_NONE 0b00000000 // 7 5 condition for entering intermediate mode: none, AutoModes disabled (default) +#define RADIOLIB_RF69_ENTER_COND_FIFO_NOT_EMPTY 0b00100000 // 7 5 FifoNotEmpty rising edge +#define RADIOLIB_RF69_ENTER_COND_FIFO_LEVEL 0b01000000 // 7 5 FifoLevel rising edge +#define RADIOLIB_RF69_ENTER_COND_CRC_OK 0b01100000 // 7 5 CrcOk rising edge +#define RADIOLIB_RF69_ENTER_COND_PAYLOAD_READY 0b10000000 // 7 5 PayloadReady rising edge +#define RADIOLIB_RF69_ENTER_COND_SYNC_ADDRESS 0b10100000 // 7 5 SyncAddress rising edge +#define RADIOLIB_RF69_ENTER_COND_PACKET_SENT 0b11000000 // 7 5 PacketSent rising edge +#define RADIOLIB_RF69_ENTER_COND_FIFO_EMPTY 0b11100000 // 7 5 FifoNotEmpty falling edge +#define RADIOLIB_RF69_EXIT_COND_NONE 0b00000000 // 4 2 condition for exiting intermediate mode: none, AutoModes disabled (default) +#define RADIOLIB_RF69_EXIT_COND_FIFO_EMPTY 0b00100000 // 4 2 FifoNotEmpty falling edge +#define RADIOLIB_RF69_EXIT_COND_FIFO_LEVEL 0b01000000 // 4 2 FifoLevel rising edge +#define RADIOLIB_RF69_EXIT_COND_CRC_OK 0b01100000 // 4 2 CrcOk rising edge +#define RADIOLIB_RF69_EXIT_COND_PAYLOAD_READY 0b10000000 // 4 2 PayloadReady rising edge +#define RADIOLIB_RF69_EXIT_COND_SYNC_ADDRESS 0b10100000 // 4 2 SyncAddress rising edge +#define RADIOLIB_RF69_EXIT_COND_PACKET_SENT 0b11000000 // 4 2 PacketSent rising edge +#define RADIOLIB_RF69_EXIT_COND_TIMEOUT 0b11100000 // 4 2 timeout rising edge +#define RADIOLIB_RF69_INTER_MODE_SLEEP 0b00000000 // 1 0 intermediate mode: sleep (default) +#define RADIOLIB_RF69_INTER_MODE_STANDBY 0b00000001 // 1 0 standby +#define RADIOLIB_RF69_INTER_MODE_RX 0b00000010 // 1 0 Rx +#define RADIOLIB_RF69_INTER_MODE_TX 0b00000011 // 1 0 Tx + +// RADIOLIB_RF69_REG_FIFO_THRESH +#define RADIOLIB_RF69_TX_START_CONDITION_FIFO_LEVEL 0b00000000 // 7 7 packet transmission start condition: FifoLevel +#define RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY 0b10000000 // 7 7 FifoNotEmpty (default) +#define RADIOLIB_RF69_FIFO_THRESH 0x1F // 6 0 default threshold to trigger FifoLevel interrupt + +// RADIOLIB_RF69_REG_PACKET_CONFIG_2 +#define RADIOLIB_RF69_INTER_PACKET_RX_DELAY 0b00000000 // 7 4 delay between FIFO empty and start of new RSSI phase +#define RADIOLIB_RF69_RESTART_RX 0b00000100 // 2 2 force receiver into wait mode +#define RADIOLIB_RF69_AUTO_RX_RESTART_OFF 0b00000000 // 1 1 auto Rx restart disabled +#define RADIOLIB_RF69_AUTO_RX_RESTART_ON 0b00000010 // 1 1 auto Rx restart enabled (default) +#define RADIOLIB_RF69_AES_OFF 0b00000000 // 0 0 AES encryption disabled (default) +#define RADIOLIB_RF69_AES_ON 0b00000001 // 0 0 AES encryption enabled, payload size limited to 66 bytes + +// RADIOLIB_RF69_REG_TEST_LNA +#define RADIOLIB_RF69_TEST_LNA_BOOST_NORMAL 0x1B // 7 0 +#define RADIOLIB_RF69_TEST_LNA_BOOST_HIGH 0x2D // 7 0 + +// RADIOLIB_RF69_REG_TEMP_1 +#define RADIOLIB_RF69_TEMP_MEAS_START 0b00001000 // 3 3 trigger temperature measurement +#define RADIOLIB_RF69_TEMP_MEAS_RUNNING 0b00000100 // 2 2 temperature measurement status: on-going +#define RADIOLIB_RF69_TEMP_MEAS_DONE 0b00000000 // 2 2 done + +// RADIOLIB_RF69_REG_TEST_DAGC +#define RADIOLIB_RF69_CONTINUOUS_DAGC_NORMAL 0x00 // 7 0 fading margin improvement: normal mode +#define RADIOLIB_RF69_CONTINUOUS_DAGC_LOW_BETA_ON 0x20 // 7 0 improved mode for AfcLowBetaOn +#define RADIOLIB_RF69_CONTINUOUS_DAGC_LOW_BETA_OFF 0x30 // 7 0 improved mode for AfcLowBetaOff (default) + +// RADIOLIB_RF69_REG_TEST_PA1 +#define RADIOLIB_RF69_PA1_NORMAL 0x55 // 7 0 PA_BOOST: none +#define RADIOLIB_RF69_PA1_20_DBM 0x5D // 7 0 +20 dBm + +// RADIOLIB_RF69_REG_TEST_PA2 +#define RADIOLIB_RF69_PA2_NORMAL 0x70 // 7 0 PA_BOOST: none +#define RADIOLIB_RF69_PA2_20_DBM 0x7C // 7 0 +20 dBm + +// RadioLib defaults +#define RADIOLIB_RF69_DEFAULT_FREQ 434.0 +#define RADIOLIB_RF69_DEFAULT_BR 4.8 +#define RADIOLIB_RF69_DEFAULT_FREQDEV 5.0 +#define RADIOLIB_RF69_DEFAULT_RXBW 125.0 +#define RADIOLIB_RF69_DEFAULT_POWER 10 +#define RADIOLIB_RF69_DEFAULT_PREAMBLELEN 16 +#define RADIOLIB_RF69_DEFAULT_SW {0x12, 0xAD} +#define RADIOLIB_RF69_DEFAULT_SW_LEN 2 + +/*! + \class RF69 + \brief Control class for %RF69 module. Also serves as base class for SX1231. +*/ +class RF69: public PhysicalLayer { + public: + // introduce PhysicalLayer overloads + using PhysicalLayer::transmit; + using PhysicalLayer::receive; + using PhysicalLayer::startTransmit; + using PhysicalLayer::readData; + + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + RF69(Module* module); + + // basic methods + + /*! + \brief Initialization method. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz. + \param pwr Output power in dBm. Defaults to 10 dBm. + \param preambleLen Preamble Length in bits. Defaults to 16 bits. + \returns \ref status_codes + */ + int16_t begin( + float freq = RADIOLIB_RF69_DEFAULT_FREQ, + float br = RADIOLIB_RF69_DEFAULT_BR, + float freqDev = RADIOLIB_RF69_DEFAULT_FREQDEV, + float rxBw = RADIOLIB_RF69_DEFAULT_RXBW, + int8_t pwr = RADIOLIB_RF69_DEFAULT_POWER, + uint8_t preambleLen = RADIOLIB_RF69_DEFAULT_PREAMBLELEN); + + /*! + \brief Reset method. Will reset the chip to the default state using RST pin. + */ + void reset(); + + /*! + \brief Blocking binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \param addr Address to send the data to. Will only be added if address filtering was enabled. + \returns \ref status_codes + */ + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Blocking binary receive method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \returns \ref status_codes + */ + int16_t receive(uint8_t* data, size_t len) override; + + /*! + \brief Sets the module to sleep mode. + \returns \ref status_codes + */ + int16_t sleep(); + + /*! + \brief Sets the module to standby mode. + \returns \ref status_codes + */ + int16_t standby() override; + + /*! + \brief Sets the module to standby. + \param mode Standby mode to be used. No effect, implemented only for PhysicalLayer compatibility. + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + + /*! + \brief Starts direct mode transmission. + \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. + \returns \ref status_codes + */ + int16_t transmitDirect(uint32_t frf = 0) override; + + /*! + \brief Starts direct mode reception. + \returns \ref status_codes + */ + int16_t receiveDirect() override; + + /*! + \brief Stops direct mode. It is required to call this method to switch from direct transmissions to packet-based transmissions. + */ + int16_t packetMode(); + + // hardware AES support + + /*! + \brief Sets AES key. + \param Key to be used for AES encryption. Must be exactly 16 bytes long. + */ + void setAESKey(uint8_t* key); + + /*! + \brief Enables AES encryption. + \returns \ref status_codes + */ + int16_t enableAES(); + + /*! + \brief Disables AES encryption. + \returns \ref status_codes + */ + int16_t disableAES(); + + // interrupt methods + + /*! + \brief Sets interrupt service routine to call when DIO0 activates. + \param func ISR to call. + */ + void setDio0Action(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when DIO0 activates. + */ + void clearDio0Action(); + + /*! + \brief Sets interrupt service routine to call when DIO1 activates. + \param func ISR to call. + */ + void setDio1Action(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when DIO1 activates. + */ + void clearDio1Action(); + + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + + /*! + \brief Set interrupt service routine function to call when FIFO is empty. + \param func Pointer to interrupt service routine. + */ + void setFifoEmptyAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when FIFO is empty. + */ + void clearFifoEmptyAction(); + + /*! + \brief Set interrupt service routine function to call when FIFO is full. + \param func Pointer to interrupt service routine. + */ + void setFifoFullAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when FIFO is full. + */ + void clearFifoFullAction(); + + /*! + \brief Set interrupt service routine function to call when FIFO is empty. + \param data Pointer to the transmission buffer. + \param totalLen Total number of bytes to transmit. + \param remLen Pointer to a counter holding the number of bytes that have been transmitted so far. + \returns True when a complete packet is sent, false if more data is needed. + */ + bool fifoAdd(uint8_t* data, int totalLen, int* remLen); + + /*! + \brief Set interrupt service routine function to call when FIFO is sufficiently full to read. + \param data Pointer to a buffer that stores the receive data. + \param totalLen Total number of bytes to receive. + \param rcvLen Pointer to a counter holding the number of bytes that have been received so far. + \returns True when a complete packet is received, false if more data is needed. + */ + bool fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen); + + /*! + \brief Interrupt-driven binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \param addr Address to send the data to. Will only be added if address filtering was enabled. + \returns \ref status_codes + */ + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Clean up after transmission is done. + \returns \ref status_codes + */ + int16_t finishTransmit() override; + + /*! + \brief Interrupt-driven receive method. GDO0 will be activated when full packet is received. + \returns \ref status_codes + */ + int16_t startReceive(); + + /*! + \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. + \param timeout Ignored. + \param irqFlags Ignored. + \param irqMask Ignored. + \param len Ignored. + \returns \ref status_codes + */ + int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + + /*! + \brief Reads data received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. + \returns \ref status_codes + */ + int16_t readData(uint8_t* data, size_t len) override; + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values are in bands 290.0 to 340.0 MHz, 431.0 to 510.0 MHz + and 862.0 to 1020.0 MHz. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Gets carrier frequency. + \param[out] freq Variable to write carrier frequency currently set, in MHz. + \returns \ref status_codes + */ + int16_t getFrequency(float *freq); + + /*! + \brief Sets bit rate. Allowed values range from 0.5 to 300.0 kbps. + \param br Bit rate to be set in kbps. + \returns \ref status_codes + */ + int16_t setBitRate(float br); + + /*! + \brief Sets receiver bandwidth. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, + 20.8, 25.0, 31.3, 41.7, 50.0, 62.5, 83.3, 100.0, 125.0, 166.7, 200.0, 250.0, 333.3, 400.0 and 500.0 kHz. + \param rxBw Receiver bandwidth to be set in kHz. + \returns \ref status_codes + */ + int16_t setRxBandwidth(float rxBw); + + /*! + \brief Sets frequency deviation. + \param freqDev Frequency deviation to be set in kHz. + \returns \ref status_codes + */ + int16_t setFrequencyDeviation(float freqDev) override; + + /*! + \brief Gets frequency deviation. + \param[out] freqDev Where to write the frequency deviation currently set, in kHz. + \returns \ref status_codes + */ + int16_t getFrequencyDeviation(float *freqDev); + + /*! + \brief Sets output power. Allowed values range from -18 to 13 dBm for + low power modules (RF69C/CW) or -2 to 20 dBm (RF69H/HC/HCW). + \param pwr Output power to be set in dBm. + \param highPower Set to true when using modules high power port (RF69H/HC/HCW). + Defaults to false (models without high power port - RF69C/CW). + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t pwr, bool highPower = false); + + /*! + \brief Sets sync word. Up to 8 bytes can be set as sync word. + \param syncWord Pointer to the array of sync word bytes. + \param len Sync word length in bytes. + \param maxErrBits Maximum allowed number of bit errors in received sync word. Defaults to 0. + */ + int16_t setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits = 0); + + /*! + \brief Sets preamble length. + \param preambleLen Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192. + \returns \ref status_codes + */ + int16_t setPreambleLength(uint8_t preambleLen); + + /*! + \brief Sets node address. Calling this method will also enable address filtering for node address only. + \param nodeAddr Node address to be set. + \returns \ref status_codes + */ + int16_t setNodeAddress(uint8_t nodeAddr); + + /*! + \brief Sets broadcast address. Calling this method will also enable address filtering for node and broadcast address. + \param broadAddr Node address to be set. + \returns \ref status_codes + */ + int16_t setBroadcastAddress(uint8_t broadAddr); + + /*! + \brief Disables address filtering. Calling this method will also erase previously set addresses. + \returns \ref status_codes + */ + int16_t disableAddressFiltering(); + + // measurement methods + + /*! + \brief Sets ambient temperature. Required to correct values from on-board temperature sensor. + \param tempAmbient Ambient temperature in degrees Celsius. + */ + void setAmbientTemperature(int16_t tempAmbient); + + /*! + \brief Measures temperature. + \returns Measured temperature in degrees Celsius. + */ + int16_t getTemperature(); + + /*! + \brief Query modem for the packet length of received payload. + \param update Update received packet length. Will return cached value when set to false. + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update = true) override; + + /*! + \brief Enables/disables OOK modulation instead of FSK. + Note: This function calls setRxBandwidth again, since register values differ based on OOK mode being enabled/disabled. + \param enable Enable (true) or disable (false) OOK. + \returns \ref status_codes + */ + int16_t setOOK(bool enable); + + /*! + \brief Selects the type of threshold in the OOK data slicer + \param type Threshold type: RADIOLIB_RF69_OOK_THRESH_PEAK(default), RADIOLIB_RF69_OOK_THRESH_FIXED or + RADIOLIB_RF69_OOK_THRESH_AVERAGE + \returns \ref status_codes + */ + int16_t setOokThresholdType(uint8_t type); + + /*! + \brief Fixed threshold for the Data Slicer in OOK mode or floor threshold for the Data Slicer + in OOK when Peak mode is used. + \param value Fixed threshold value (in dB) in the OOK demodulator. + Used when OokThresType = RADIOLIB_RF69_OOK_THRESH_FIXED. + \returns \ref status_codes + */ + int16_t setOokFixedThreshold(uint8_t value); + + /*! + \brief Period of decrement of the RSSI threshold in the OOK demodulator. + \param value Use defines RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_X_X_CHIP + \returns \ref status_codes + */ + int16_t setOokPeakThresholdDecrement(uint8_t value); + + /*! + \brief Set modem in fixed packet length mode. + \param len Packet length. + \returns \ref status_codes + */ + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_RF69_MAX_PACKET_LENGTH); + + /*! + \brief Set modem in variable packet length mode. + \param len Maximum packet length. + \returns \ref status_codes + */ + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_RF69_MAX_PACKET_LENGTH); + + /*! + \brief Enable sync word filtering and generation. + \param numBits Sync word length in bits. + \returns \ref status_codes + */ + int16_t enableSyncWordFiltering(uint8_t maxErrBits = 0); + + /*! + \brief Disable preamble and sync word filtering and generation. + \returns \ref status_codes + */ + int16_t disableSyncWordFiltering(); + + /*! + \brief Enable Bit synchronization in continuous mode. + \returns \ref status_codes + */ + int16_t enableContinuousModeBitSync(); + + /*! + \brief Disable Bit synchronization in continuous mode. + \returns \ref status_codes + */ + int16_t disableContinuousModeBitSync(); + + /*! + \brief Enable CRC filtering and generation. + \param crcOn Set or unset CRC filtering. + \returns \ref status_codes + */ + int16_t setCrcFiltering(bool crcOn = true); + + /*! + \brief Set modem in "sniff" mode: no packet filtering (e.g., no preamble, sync word, address, CRC). + \param enable Set or unset promiscuous mode. + \returns \ref status_codes + */ + int16_t setPromiscuousMode(bool enable = true); + + /*! + \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. + Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. + Set to RADIOLIB_SHAPING_NONE to disable data shaping. + \param sh Gaussian shaping bandwidth-time product that will be used for data shaping + \returns \ref status_codes + */ + int16_t setDataShaping(uint8_t sh) override; + + /*! + \brief Sets transmission encoding. + Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER and RADIOLIB_ENCODING_WHITENING. + \param encoding Encoding to be used. + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding) override; + + /*! + \brief Enable/disable LNA Boost mode (disabled by default). + \param value True to enable, false to disable. + \returns \ref status_codes + */ + int16_t setLnaTestBoost(bool value); + + /*! + \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. + \returns Last packet RSSI in dBm. + */ + float getRSSI(); + + /*! + \brief Sets the RSSI value above which the RSSI interrupt is signaled + \param dbm A dBm value between -127.5 and 0 inclusive + \returns \ref status_codes + */ + int16_t setRSSIThreshold(float dbm); + + /*! \copydoc Module::setRfSwitchPins */ + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); + + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + + /*! + \brief Get one truly random byte from RSSI noise. + \returns TRNG byte. + */ + uint8_t randomByte(); + + /*! + \brief Read version SPI register. Should return RF69_CHIP_VERSION (0x24) if SX127x is connected and working. + \returns Version register contents or \ref status_codes + */ + int16_t getChipVersion(); + + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE + /*! + \brief Set interrupt service routine function to call when data bit is received in direct mode. + \param func Pointer to interrupt service routine. + */ + void setDirectAction(void (*func)(void)); + + /*! + \brief Function to read and process data bit in direct reception mode. + \param pin Pin on which to read. + */ + void readBit(uint32_t pin); + #endif + + /*! + \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). + \param pin Pin number onto which a signal is to be placed. + \param value The value that indicates which function to place on that pin. See chip datasheet for details. + \returns \ref status_codes + */ + int16_t setDIOMapping(uint32_t pin, uint32_t value); + +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL + protected: +#endif + Module* getMod(); + +#if !RADIOLIB_GODMODE + protected: +#endif + float bitRate = RADIOLIB_RF69_DEFAULT_BR; + float rxBandwidth = RADIOLIB_RF69_DEFAULT_RXBW; + + int16_t config(); + int16_t setMode(uint8_t mode); + +#if !RADIOLIB_GODMODE + private: +#endif + Module* mod; + + float frequency = RADIOLIB_RF69_DEFAULT_FREQ; + bool ookEnabled = false; + int16_t tempOffset = 0; + int8_t power = RADIOLIB_RF69_DEFAULT_POWER; + + size_t packetLength = 0; + bool packetLengthQueried = false; + uint8_t packetLengthConfig = RADIOLIB_RF69_PACKET_FORMAT_VARIABLE; + + bool promiscuous = false; + + uint8_t syncWordLength = RADIOLIB_RF69_DEFAULT_SW_LEN; + + bool bitSync = true; + + int16_t directMode(); + int16_t setPacketMode(uint8_t mode, uint8_t len); + void clearIRQFlags(); + void clearFIFO(size_t count); +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/RFM2x/RFM22.h b/lib/lib_rf/RadioLib/src/modules/RFM2x/RFM22.h new file mode 100644 index 000000000..95a8177af --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/RFM2x/RFM22.h @@ -0,0 +1,20 @@ +#if !defined(_RADIOLIB_RFM22_H) +#define _RADIOLIB_RFM22_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_RFM2X + +#include "../../Module.h" +#include "../Si443x/Si443x.h" +#include "../Si443x/Si4432.h" + +/*! + \class RFM22 + \brief Only exists as alias for Si4432, since there seems to be no difference between %RFM22 and %Si4432 modules. +*/ +RADIOLIB_TYPE_ALIAS(Si4432, RFM22) + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/RFM2x/RFM23.h b/lib/lib_rf/RadioLib/src/modules/RFM2x/RFM23.h new file mode 100644 index 000000000..fa28a07e0 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/RFM2x/RFM23.h @@ -0,0 +1,20 @@ +#if !defined(_RADIOLIB_RFM23_H) +#define _RADIOLIB_RFM23_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_RFM2X + +#include "../../Module.h" +#include "../Si443x/Si443x.h" +#include "../Si443x/Si4431.h" + +/*! + \class RFM23 + \brief Only exists as alias for Si4431, since there seems to be no difference between %RFM23 and %Si4431 modules. +*/ +RADIOLIB_TYPE_ALIAS(Si4431, RFM23) + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX123x/SX1231.cpp b/lib/lib_rf/RadioLib/src/modules/SX123x/SX1231.cpp new file mode 100644 index 000000000..11424eed3 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX123x/SX1231.cpp @@ -0,0 +1,92 @@ +#include "SX1231.h" +#if !RADIOLIB_EXCLUDE_SX1231 + +SX1231::SX1231(Module* mod) : RF69(mod) { + +} + +int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { + // set module properties + Module* mod = this->getMod(); + mod->init(); + mod->hal->pinMode(mod->getIrq(), mod->hal->GpioModeInput); + mod->hal->pinMode(mod->getRst(), mod->hal->GpioModeOutput); + + // try to find the SX1231 chip + uint8_t i = 0; + bool flagFound = false; + while((i < 10) && !flagFound) { + int16_t version = getChipVersion(); + if((version == RADIOLIB_SX123X_CHIP_REVISION_2_A) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_B) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_C)) { + flagFound = true; + this->chipRevision = version; + } else { + RADIOLIB_DEBUG_BASIC_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); + mod->hal->delay(10); + i++; + } + } + + if(!flagFound) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX1231 found!"); + mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX1231"); + + // configure settings not accessible by API + int16_t state = config(); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tRF69"); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + // configure bitrate + this->rxBandwidth = 125.0; + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + // configure default RX bandwidth + state = setRxBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + // configure default frequency deviation + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + // configure default TX output power + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + // configure default preamble length + state = setPreambleLength(preambleLen); + RADIOLIB_ASSERT(state); + + // default sync word values 0x2D01 is the same as the default in LowPowerLab RFM69 library + uint8_t syncWord[] = {0x2D, 0x01}; + state = setSyncWord(syncWord, 2); + RADIOLIB_ASSERT(state); + + // set default packet length mode + state = variablePacketLengthMode(); + if (state != RADIOLIB_ERR_NONE) { + return(state); + } + + // SX123x V2a only + if(this->chipRevision == RADIOLIB_SX123X_CHIP_REVISION_2_A) { + // modify default OOK threshold value + state = mod->SPIsetRegValue(RADIOLIB_SX1231_REG_TEST_OOK, RADIOLIB_SX1231_OOK_DELTA_THRESHOLD); + RADIOLIB_ASSERT(state); + + // enable OCP with 95 mA limit + state = mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM, 4, 0); + RADIOLIB_ASSERT(state); + } + + return(RADIOLIB_ERR_NONE); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX123x/SX1231.h b/lib/lib_rf/RadioLib/src/modules/SX123x/SX1231.h new file mode 100644 index 000000000..569a8403a --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX123x/SX1231.h @@ -0,0 +1,121 @@ +#if !defined(_RADIOLIB_SX1231_H) +#define _RADIOLIB_SX1231_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX1231 + +#include "../../Module.h" +#include "../RF69/RF69.h" + +#define RADIOLIB_SX123X_CHIP_REVISION_2_A 0x21 +#define RADIOLIB_SX123X_CHIP_REVISION_2_B 0x22 +#define RADIOLIB_SX123X_CHIP_REVISION_2_C 0x23 + +// RADIOLIB_SX1231 specific register map +#define RADIOLIB_SX1231_REG_TEST_OOK 0x6E + +// RADIOLIB_SX1231_REG_TEST_OOK +#define RADIOLIB_SX1231_OOK_DELTA_THRESHOLD 0x0C + +// RADIOLIB_SX1231_REG_DIO_MAPPING_1 +#define RADIOLIB_SX1231_DIO0_CONT_LOW_BAT 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_PLL_LOCK 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_TIMEOUT 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_RSSI 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_LOW_BAT 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_CRC_OK 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_PAYLOAD_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_SYNC_ADDRESS 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_RSSI 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO1_CONT_LOW_BAT 0b00100000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_PLL_LOCK 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_DCLK 0b00000000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_RX_READY 0b00010000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_SYNC_ADDRESS 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_TX_READY 0b00010000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_FIFO_FULL 0b00010000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_FIFO_NOT_EMPTY 0b00100000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_PLL_LOCK 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_TIMEOUT 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO2_CONT_DATA 0b00000000 // 3 2 +#define RADIOLIB_SX1231_DIO2_PACK_FIFO_NOT_EMPTY 0b00000000 // 3 2 +#define RADIOLIB_SX1231_DIO2_PACK_LOW_BAT 0b00001000 // 3 2 +#define RADIOLIB_SX1231_DIO2_PACK_AUTO_MODE 0b00001100 // 3 2 +#define RADIOLIB_SX1231_DIO2_PACK_DATA 0b00000100 // 3 2 +#define RADIOLIB_SX1231_DIO3_CONT_AUTO_MODE 0b00000010 // 0 1 +#define RADIOLIB_SX1231_DIO3_CONT_RSSI 0b00000000 // 0 1 +#define RADIOLIB_SX1231_DIO3_CONT_RX_READY 0b00000001 // 0 1 +#define RADIOLIB_SX1231_DIO3_CONT_TIMEOUT 0b00000011 // 0 1 +#define RADIOLIB_SX1231_DIO3_CONT_TX_READY 0b00000001 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_FIFO_FULL 0b00000000 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_LOW_BAT 0b00000010 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_PLL_LOCK 0b00000011 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_RSSI 0b00000001 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_SYNC_ADDRESSS 0b00000010 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_TX_READY 0b00000001 // 0 1 + +// RADIOLIB_SX1231_REG_DIO_MAPPING_2 +#define RADIOLIB_SX1231_DIO4_CONT_LOW_BAT 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_TIMEOUT 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_RX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_SYNC_ADDRESS 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_LOW_BAT 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_TIMEOUT 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_RSSI 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_RX_READY 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_MODE_READY 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO5_CONT_LOW_BAT 0b00100000 // 5 4 +#define RADIOLIB_SX1231_DIO5_CONT_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX1231_DIO5_CONT_RSSI 0b00010000 // 5 4 +#define RADIOLIB_SX1231_DIO5_PACK_LOW_BAT 0b00100000 // 5 4 +#define RADIOLIB_SX1231_DIO5_PACK_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX1231_DIO5_PACK_DATA 0b00010000 // 5 4 + +/*! + \class SX1231 + \brief Control class for %SX1231 module. Overrides some methods from RF69 due to different register values. +*/ +class SX1231: public RF69 { + public: + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1231(Module* mod); + + /*! + \brief Initialization method. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz. + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLen Preamble Length in bits. Defaults to 16 bits. + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); + +#if !RADIOLIB_GODMODE + private: +#endif + uint8_t chipRevision = 0; +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX123x/SX1233.cpp b/lib/lib_rf/RadioLib/src/modules/SX123x/SX1233.cpp new file mode 100644 index 000000000..16c4bca14 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX123x/SX1233.cpp @@ -0,0 +1,127 @@ +#include "SX1233.h" +#include +#if !RADIOLIB_EXCLUDE_SX1231 + +SX1233::SX1233(Module* mod) : SX1231(mod) { + +} + +int16_t SX1233::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { + // set module properties + Module* mod = this->getMod(); + mod->init(); + mod->hal->pinMode(mod->getIrq(), mod->hal->GpioModeInput); + mod->hal->pinMode(mod->getRst(), mod->hal->GpioModeOutput); + + // try to find the SX1233 chip + uint8_t i = 0; + bool flagFound = false; + while((i < 10) && !flagFound) { + int16_t version = getChipVersion(); + if((version == RADIOLIB_SX123X_CHIP_REVISION_2_A) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_B) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_C)) { + flagFound = true; + this->chipRevision = version; + } else { + RADIOLIB_DEBUG_BASIC_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); + mod->hal->delay(10); + i++; + } + } + + if(!flagFound) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX1233 found!"); + mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX1233"); + + // configure settings not accessible by API + int16_t state = config(); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tRF69"); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + // configure bitrate + this->rxBandwidth = 125.0; + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + // configure default RX bandwidth + state = setRxBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + // configure default frequency deviation + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + // configure default TX output power + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + // configure default preamble length + state = setPreambleLength(preambleLen); + RADIOLIB_ASSERT(state); + + // default sync word values 0x2D01 is the same as the default in LowPowerLab RFM69 library + uint8_t syncWord[] = {0x2D, 0x01}; + state = setSyncWord(syncWord, 2); + RADIOLIB_ASSERT(state); + + // set default packet length mode + state = variablePacketLengthMode(); + if (state != RADIOLIB_ERR_NONE) { + return(state); + } + + // SX123x V2a only + if(this->chipRevision == RADIOLIB_SX123X_CHIP_REVISION_2_A) { + // modify default OOK threshold value + state = mod->SPIsetRegValue(RADIOLIB_SX1231_REG_TEST_OOK, RADIOLIB_SX1231_OOK_DELTA_THRESHOLD); + RADIOLIB_ASSERT(state); + + // enable OCP with 95 mA limit + state = mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM, 4, 0); + RADIOLIB_ASSERT(state); + } + + return(RADIOLIB_ERR_NONE); +} + +int16_t SX1233::setBitRate(float br) { + // check high bit-rate operation + uint8_t pllBandwidth = RADIOLIB_SX1233_PLL_BW_LOW_BIT_RATE; + if((fabs(br - 500.0f) < 0.1) || (fabs(br - 600.0f) < 0.1)) { + pllBandwidth = RADIOLIB_SX1233_PLL_BW_HIGH_BIT_RATE; + } else { + // datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine + RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + } + + + // check bitrate-bandwidth ratio + if(!(br < 2000 * this->rxBandwidth)) { + return(RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO); + } + + // set mode to standby + setMode(RADIOLIB_RF69_STANDBY); + + // set PLL bandwidth + Module* mod = this->getMod(); + int16_t state = mod->SPIsetRegValue(RADIOLIB_SX1233_REG_TEST_PLL, pllBandwidth, 7, 0); + RADIOLIB_ASSERT(state); + + // set bit rate + uint16_t bitRate = 32000 / br; + state = mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); + state |= mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); + if(state == RADIOLIB_ERR_NONE) { + this->bitRate = br; + } + return(state); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX123x/SX1233.h b/lib/lib_rf/RadioLib/src/modules/SX123x/SX1233.h new file mode 100644 index 000000000..029b0cc21 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX123x/SX1233.h @@ -0,0 +1,61 @@ +#if !defined(_RADIOLIB_SX1233_H) +#define _RADIOLIB_SX1233_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX1231 + +#include "../../Module.h" +#include "../RF69/RF69.h" +#include "SX1231.h" + +// RADIOLIB_SX1233 specific register map +#define RADIOLIB_SX1233_REG_TEST_PLL 0x5F + +// RADIOLIB_SX1233_REG_TEST_PLL +#define RADIOLIB_SX1233_PLL_BW_HIGH_BIT_RATE 0x0C +#define RADIOLIB_SX1233_PLL_BW_LOW_BIT_RATE 0x08 + +/*! + \class SX1233 + \brief Control class for %SX1233 module. Overrides some methods from SX1231/RF69 due to different register values. +*/ +class SX1233: public SX1231 { + public: + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1233(Module* mod); + + /*! + \brief Initialization method. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz. + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLen Preamble Length in bits. Defaults to 16 bits. + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); + + /*! + \brief Sets bit rate. Allowed values range from 0.5 to 300.0 kbps. + SX1233 also allows 500 kbps and 600 kbps operation. + NOTE: For 500 kbps rate, the receiver frequency should be offset by 50 kHz from the transmitter. + For 600 kbps rate, the receiver frequency should be offset by 40 kHz from the transmitter. + \param br Bit rate to be set in kbps. + \returns \ref status_codes + */ + int16_t setBitRate(float br); + +#if !RADIOLIB_GODMODE + private: +#endif + uint8_t chipRevision = 0; +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/STM32WLx.cpp b/lib/lib_rf/RadioLib/src/modules/SX126x/STM32WLx.cpp new file mode 100644 index 000000000..508ea4e59 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/STM32WLx.cpp @@ -0,0 +1,154 @@ +/* +Copyright (c) 2018 Jan Gromeš +Copyright (c) 2022 STMicroelectronics + +This file is licensed under the MIT License: https://opensource.org/licenses/MIT +*/ + +#include "STM32WLx.h" +#if !RADIOLIB_EXCLUDE_STM32WLX + +STM32WLx::STM32WLx(STM32WLx_Module* mod) : SX1262(mod) { } + +int16_t STM32WLx::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { + // Execute common part + int16_t state = SX1262::begin(freq, bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // This overrides the value in SX126x::begin() + // On STM32WL, DIO2 is hardwired to the radio IRQ on the MCU, so it + // should really not be used as RfSwitch control output. + state = setDio2AsRfSwitch(false); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t STM32WLx::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { + // Execute common part + int16_t state = SX1262::beginFSK(freq, br, freqDev, rxBw, power, preambleLength, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // This overrides the value in SX126x::beginFSK() + // On STM32WL, DIO2 is hardwired to the radio IRQ on the MCU, so it + // should really not be used as RfSwitch control output. + state = setDio2AsRfSwitch(false); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t STM32WLx::setOutputPower(int8_t power) { + // get current OCP configuration + uint8_t ocp = 0; + int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + RADIOLIB_ASSERT(state); + + // check the user did not request power output that is not possible + Module* mod = this->getMod(); + bool hp_supported = mod->findRfSwitchMode(MODE_TX_HP); + bool lp_supported = mod->findRfSwitchMode(MODE_TX_LP); + if((!lp_supported && (power < -9)) || (!hp_supported && (power > 14))) { + // LP not supported but requested power is below HP low bound or + // HP not supported but requested power is above LP high bound + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + + // set PA config based on which PAs are supported + bool use_hp = false; + if(hp_supported && lp_supported) { + // both PAs supported, use HP when above 14 dBm + if(power > 14) { + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + state = SX126x::setPaConfig(0x04, 0x00, 0x07); // HP output up to 22dBm + this->txMode = MODE_TX_HP; + use_hp = true; + } else { + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + state = SX126x::setPaConfig(0x04, 0x01, 0x00); // LP output up to 14dBm + this->txMode = MODE_TX_LP; + } + + } else if(!hp_supported && lp_supported) { + // only LP supported + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + state = SX126x::setPaConfig(0x04, 0x01, 0x00); + this->txMode = MODE_TX_LP; + + } else if(hp_supported && !lp_supported) { + // only HP supported + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + state = SX126x::setPaConfig(0x04, 0x00, 0x07); + this->txMode = MODE_TX_HP; + use_hp = true; + + } else { + // neither PA is supported + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + } + + // Apply workaround for HP only + state = SX126x::fixPaClamping(use_hp); + RADIOLIB_ASSERT(state); + + // set output power + /// \todo power ramp time configuration + state = SX126x::setTxParams(power); + RADIOLIB_ASSERT(state); + + // restore OCP configuration + return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); +} + +int16_t STM32WLx::clearIrqStatus(uint16_t clearIrqParams) { + int16_t res = SX126x::clearIrqStatus(clearIrqParams); + // The NVIC interrupt is level-sensitive, so clear away any pending + // flag that is only set because the radio IRQ status was not cleared + // in the interrupt (to prevent each IRQ triggering twice and allow + // reading the irq status through the pending flag). + SubGhz.clearPendingInterrupt(); + if(SubGhz.hasInterrupt()) + SubGhz.enableInterrupt(); + return(res); +} + +void STM32WLx::setDio1Action(void (*func)(void)) { + SubGhz.attachInterrupt([func]() { + // Because the interrupt is level-triggered, we disable it in the + // NVIC (otherwise we would need an SPI command to clear the IRQ in + // the radio, or it would trigger over and over again). + SubGhz.disableInterrupt(); + func(); + }); +} + +void STM32WLx::clearDio1Action() { + SubGhz.detachInterrupt(); +} + +void STM32WLx::setPacketReceivedAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void STM32WLx::clearPacketReceivedAction() { + this->clearDio1Action(); +} + +void STM32WLx::setPacketSentAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void STM32WLx::clearPacketSentAction() { + this->clearDio1Action(); +} + +void STM32WLx::setChannelScanAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void STM32WLx::clearChannelScanAction() { + this->clearDio1Action(); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/STM32WLx.h b/lib/lib_rf/RadioLib/src/modules/SX126x/STM32WLx.h new file mode 100644 index 000000000..16c88cc95 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/STM32WLx.h @@ -0,0 +1,168 @@ +/* +Copyright (c) 2018 Jan Gromeš +Copyright (c) 2022 STMicroelectronics + +This file is licensed under the MIT License: https://opensource.org/licenses/MIT +*/ + +#if !defined(_RADIOLIB_STM32WLx_H) +#define _RADIOLIB_STM32WLx_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_STM32WLX + +#include "../../Module.h" +#include "SX1262.h" +#include "STM32WLx_Module.h" + +/*! + \class STM32WLx + + \brief Derived class for STM32WL modules. + + The radio integrated into these modules is essentially the same as the + Semtech %SX126x external radio chips, so most of the documentation for + those also applies here. + + One notable difference with the %SX126x radios is that this radio + essentially combines the %SX1261 and %SX1262 by integrating both the + low-power (LP) and high-power (HP) amplifier. See setOutputPower() and + setRfSwitchTable() for details on how this is handled. +*/ +class STM32WLx : public SX1262 { + // NOTE: This class could not be named STM32WL (or STM32WLxx), since + // those are macros defined by + // system/Drivers/CMSIS/Device/ST/STM32WLxxx/Include/stm32wlxx.h + public: + /*! + \brief Default constructor. + \param mod Instance of STM32WLx_Module that will be used to communicate with the radio. + */ + STM32WLx(STM32WLx_Module* mod); + + /*! + \brief Custom operation modes for STMWLx. + + This splits the TX mode into two modes: Low-power and high-power. + These constants can be used with the setRfSwitchTable() method, + instead of the Module::OpMode_t constants. + */ + enum OpMode_t { + /*! End of table marker, use \ref END_OF_MODE_TABLE constant instead */ + MODE_END_OF_TABLE = Module::MODE_END_OF_TABLE, + /*! Idle mode */ + MODE_IDLE = Module::MODE_IDLE, + /*! Receive mode */ + MODE_RX = Module::MODE_RX, + /*! Low power transmission mode */ + MODE_TX_LP = Module::MODE_TX, + /*! High power transmission mode */ + MODE_TX_HP, + }; + + // basic methods + + /*! + \copydoc SX1262::begin + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + + /*! + \copydoc SX1262::beginFSK + */ + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + + // configuration methods + + /*! + \brief Sets output power. Allowed values are in range from -17 to 22 dBm. + + This automatically switches between the low-power (LP) and high-power (HP) amplifier. + + LP is preferred and supports -17 to +14dBm. When a higher power is + requested (or the LP amplifier is marked as unavailable using + setRfSwitchTable()), HP is used, which supports -9 to +22dBm. If the LP is marked as unavailable, + HP output will be used instead. + + \param power Output power to be set in dBm. + + \returns \ref status_codes + */ + virtual int16_t setOutputPower(int8_t power) override; + + /*! + \copybrief Module::setRfSwitchTable + + This method works like Module::setRfSwitchTable(), except that you + should use STM32WLx::OpMode_t constants for modes, which + distinguishes between a low-power (LP) and high-power (HP) TX mode. + + For boards that do not support both modes, just omit the + unsupported mode from the table and it will not be used (and the + valid power range is adjusted by setOutputPower() accordingly). + + Note that the setRfSwitchTable() method should be called *before* the + begin() method, to ensure the radio knows which modes are supported + during initialization. + */ + // Note: This explicitly inherits this method only to override docs + using SX126x::setRfSwitchTable; + + /*! + \brief Sets interrupt service routine to call when DIO1/2/3 activates. + \param func ISR to call. + */ + void setDio1Action(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when DIO1/2/3 activates. + */ + void clearDio1Action(); + + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + + /*! + \brief Sets interrupt service routine to call when a channel scan is finished. + \param func ISR to call. + */ + void setChannelScanAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a channel scan is finished. + */ + void clearChannelScanAction(); + +#if !RADIOLIB_GODMODE + protected: +#endif + virtual int16_t clearIrqStatus(uint16_t clearIrqParams) override; + +#if !RADIOLIB_GODMODE + private: +#endif +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/STM32WLx_Module.cpp b/lib/lib_rf/RadioLib/src/modules/SX126x/STM32WLx_Module.cpp new file mode 100644 index 000000000..57d0445cd --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/STM32WLx_Module.cpp @@ -0,0 +1,106 @@ +/* + +Copyright (c) 2022 STMicroelectronics + +This file is licensed under the MIT License: https://opensource.org/licenses/MIT +*/ + +#include "STM32WLx_Module.h" + +#if !RADIOLIB_EXCLUDE_STM32WLX + +#include "../../ArduinoHal.h" + +// This defines some dummy pin numbers (starting at NUM_DIGITAL_PINS to +// guarantee these are not valid regular pin numbers) that can be passed +// to the parent Module class, to be stored here and then passed back to +// the overridden callbacks when these are used. +enum { + RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS = NUM_DIGITAL_PINS, + RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY, + RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ, + RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET, +}; + +class Stm32wlxHal : public ArduinoHal { + public: + Stm32wlxHal(): ArduinoHal(SubGhz.SPI, SubGhz.spi_settings) {} + + void pinMode(uint32_t dwPin, uint32_t dwMode) { + switch(dwPin) { + case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: + case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: + case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ: + case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET: + // Nothing to do + break; + default: + ::pinMode(dwPin, dwMode); + break; + } + } + + void digitalWrite(uint32_t dwPin, uint32_t dwVal) { + switch (dwPin) { + case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: + SubGhz.setNssActive(dwVal == LOW); + break; + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET: + SubGhz.setResetActive(dwVal == LOW); + break; + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: + case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ: + // Should not (and cannot) be written, just ignore + break; + + default: + ::digitalWrite(dwPin, dwVal); + break; + } + } + + uint32_t digitalRead(uint32_t ulPin) { + switch (ulPin) { + case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: + return(SubGhz.isBusy() ? HIGH : LOW); + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ: + // We cannot use the radio IRQ output directly, but since: + // - the pending flag will be set whenever the IRQ output is set, + // and + // - the pending flag will be cleared (by + // STM32WLx::clearIrqStatus()) whenever the radio IRQ output is + // cleared, + // the pending flag should always reflect the current radio IRQ + // output. There is one exception: when the ISR starts the pending + // flag is cleared by hardware and not set again until after the + // ISR finishes, so the value is incorrect *inside* the ISR, but + // running RadioLib code inside the ISR (especially code that + // polls the IRQ flag) is not supported and probably broken in + // other ways too. + return(SubGhz.isInterruptPending() ? HIGH : LOW); + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: + return(SubGhz.isNssActive() ? LOW : HIGH); + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET: + return(SubGhz.isResetActive() ? LOW : HIGH); + + default: + return(::digitalRead(ulPin)); + } + } +}; + +STM32WLx_Module::STM32WLx_Module(): + Module( + new Stm32wlxHal, + RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS, + RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ, + RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET, + RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY + ) {} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/STM32WLx_Module.h b/lib/lib_rf/RadioLib/src/modules/SX126x/STM32WLx_Module.h new file mode 100644 index 000000000..878ba775e --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/STM32WLx_Module.h @@ -0,0 +1,38 @@ +/* + +Copyright (c) 2022 STMicroelectronics + +This file is licensed under the MIT License: https://opensource.org/licenses/MIT +*/ + +#if !defined(_RADIOLIB_STM32WLX_MODULE_H) +#define _RADIOLIB_STM32WLX_MODULE_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_STM32WLX + +#include "../../Module.h" + +/*! + * \class STM32WLx_Module + * + * This is a subclass of Module to be used with the STM32WLx driver. + * + * It is used to override some callbacks, allowing access to some of the + * radio control signals that are wired to internal registers instead of + * actual GPIO pins. + */ +class STM32WLx_Module : public Module { + // Note: We cannot easily override any methods here, since most calls + // are non-virtual and made through a Module*, so they would not be + // calling any overridden methods. This means this class works by + // overriding some of the callbacks in its constructor. + + public: + STM32WLx_Module(); +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/SX1261.cpp b/lib/lib_rf/RadioLib/src/modules/SX126x/SX1261.cpp new file mode 100644 index 000000000..dd39bfef0 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/SX1261.cpp @@ -0,0 +1,29 @@ +#include "SX1261.h" +#if !RADIOLIB_EXCLUDE_SX126X + +SX1261::SX1261(Module* mod): SX1262(mod) { + chipType = RADIOLIB_SX1261_CHIP_TYPE; +} + +int16_t SX1261::setOutputPower(int8_t power) { + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + // get current OCP configuration + uint8_t ocp = 0; + int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + RADIOLIB_ASSERT(state); + + // set PA config + state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1261, 0x00); + RADIOLIB_ASSERT(state); + + // set output power + /// \todo power ramp time configuration + state = SX126x::setTxParams(power); + RADIOLIB_ASSERT(state); + + // restore OCP configuration + return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/SX1261.h b/lib/lib_rf/RadioLib/src/modules/SX126x/SX1261.h new file mode 100644 index 000000000..01375d558 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/SX1261.h @@ -0,0 +1,45 @@ +#if !defined(_RADIOLIB_SX1261_H) +#define _RADIOLIB_SX1261_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX126X + +#include "../../Module.h" +#include "SX126x.h" +#include "SX1262.h" + +//RADIOLIB_SX126X_CMD_SET_PA_CONFIG +#define RADIOLIB_SX126X_PA_CONFIG_SX1261 0x01 + +//RADIOLIB_SX126X_REG_VERSION_STRING +#define RADIOLIB_SX1261_CHIP_TYPE "SX1261" + +/*! + \class SX1261 + \brief Derived class for %SX1261 modules. +*/ +class SX1261 : public SX1262 { + public: + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1261(Module* mod); + + /*! + \brief Sets output power. Allowed values are in range from -17 to 14 dBm. + \param power Output power to be set in dBm. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power); + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/SX1262.cpp b/lib/lib_rf/RadioLib/src/modules/SX126x/SX1262.cpp new file mode 100644 index 000000000..0bbce30d4 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/SX1262.cpp @@ -0,0 +1,88 @@ +#include "SX1262.h" +#if !RADIOLIB_EXCLUDE_SX126X + +SX1262::SX1262(Module* mod) : SX126x(mod) { + chipType = RADIOLIB_SX1262_CHIP_TYPE; +} + +int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { + // execute common part + int16_t state = SX126x::begin(cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { + // execute common part + int16_t state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX1262::setFrequency(float freq) { + return(setFrequency(freq, true)); +} + +int16_t SX1262::setFrequency(float freq, bool calibrate, float band) { + RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); + + // calibrate image rejection + if(calibrate) { + int16_t state = SX126x::calibrateImage(freq - band, freq + band); + RADIOLIB_ASSERT(state); + } + + // set frequency + return(SX126x::setFrequencyRaw(freq)); +} + +int16_t SX1262::setOutputPower(int8_t power) { + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + // get current OCP configuration + uint8_t ocp = 0; + int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + RADIOLIB_ASSERT(state); + + // set PA config + state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1262); + RADIOLIB_ASSERT(state); + + // set output power + /// \todo power ramp time configuration + state = SX126x::setTxParams(power); + RADIOLIB_ASSERT(state); + + // restore OCP configuration + return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/SX1262.h b/lib/lib_rf/RadioLib/src/modules/SX126x/SX1262.h new file mode 100644 index 000000000..61f8facc7 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/SX1262.h @@ -0,0 +1,101 @@ +#if !defined(_RADIOLIB_SX1262_H) +#define _RADIOLIB_SX1262_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX126X + +#include "../../Module.h" +#include "SX126x.h" + +//RADIOLIB_SX126X_CMD_SET_PA_CONFIG +#define RADIOLIB_SX126X_PA_CONFIG_SX1262 0x00 + +//RADIOLIB_SX126X_REG_VERSION_STRING +// Note: this should really be "2", however, it seems that all SX1262 devices report as SX1261 +#define RADIOLIB_SX1262_CHIP_TYPE "SX1261" + +/*! + \class SX1262 + \brief Derived class for %SX1262 modules. +*/ +class SX1262: public SX126x { + public: + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1262(Module* mod); + + // basic methods + + /*! + \brief Initialization method for LoRa modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. + \param sf LoRa spreading factor. Defaults to 9. + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + + /*! + \brief Initialization method for FSK modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br FSK bit rate in kbps. Defaults to 4.8 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 5.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLength FSK preamble length in bits. Defaults to 16 bits. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. + \param freq Carrier frequency to be set in MHz. + \param calibrate Run image calibration. + \param band Half bandwidth for image calibration. For example, + if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate + for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz + \returns \ref status_codes + */ + int16_t setFrequency(float freq, bool calibrate, float band = 4); + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm. + This method is virtual to allow override from the SX1261 class. + \param power Output power to be set in dBm. + \returns \ref status_codes + */ + virtual int16_t setOutputPower(int8_t power); + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/SX1268.cpp b/lib/lib_rf/RadioLib/src/modules/SX126x/SX1268.cpp new file mode 100644 index 000000000..7f14e9fae --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/SX1268.cpp @@ -0,0 +1,89 @@ +#include "SX1268.h" +#if !RADIOLIB_EXCLUDE_SX126X + +SX1268::SX1268(Module* mod) : SX126x(mod) { + chipType = RADIOLIB_SX1268_CHIP_TYPE; +} + +int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { + // execute common part + int16_t state = SX126x::begin(cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { + // execute common part + int16_t state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX1268::setFrequency(float freq) { + return(setFrequency(freq, true)); +} + +/// \todo integers only (all modules - frequency, data rate, bandwidth etc.) +int16_t SX1268::setFrequency(float freq, bool calibrate, float band) { + RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, RADIOLIB_ERR_INVALID_FREQUENCY); + + // calibrate image rejection + if(calibrate) { + int16_t state = SX126x::calibrateImage(freq - band, freq + band); + RADIOLIB_ASSERT(state); + } + + // set frequency + return(SX126x::setFrequencyRaw(freq)); +} + +int16_t SX1268::setOutputPower(int8_t power) { + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + // get current OCP configuration + uint8_t ocp = 0; + int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + RADIOLIB_ASSERT(state); + + // set PA config + state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1268); + RADIOLIB_ASSERT(state); + + // set output power + /// \todo power ramp time configuration + state = SX126x::setTxParams(power); + RADIOLIB_ASSERT(state); + + // restore OCP configuration + return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/SX1268.h b/lib/lib_rf/RadioLib/src/modules/SX126x/SX1268.h new file mode 100644 index 000000000..f3f61dc86 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/SX1268.h @@ -0,0 +1,99 @@ +#if !defined(_RADIOLIB_SX1268_H) +#define _RADIOLIB_SX1268_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX126X + +#include "../../Module.h" +#include "SX126x.h" + +//RADIOLIB_SX126X_CMD_SET_PA_CONFIG +#define RADIOLIB_SX126X_PA_CONFIG_SX1268 0x00 + +//RADIOLIB_SX126X_REG_VERSION_STRING +#define RADIOLIB_SX1268_CHIP_TYPE "SX1268" + +/*! + \class SX1268 + \brief Derived class for %SX1268 modules. +*/ +class SX1268: public SX126x { + public: + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1268(Module* mod); + + // basic methods + + /*! + \brief Initialization method for LoRa modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. + \param sf LoRa spreading factor. Defaults to 9. + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + + /*! + \brief Initialization method for FSK modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br FSK bit rate in kbps. Defaults to 4.8 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 5.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLength FSK preamble length in bits. Defaults to 16 bits. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values are in range from 410.0 to 810.0 MHz. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. + \param freq Carrier frequency to be set in MHz. + \param calibrate Run image calibration. + \param band Half bandwidth for image calibration. For example, + if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate + for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz + \returns \ref status_codes + */ + int16_t setFrequency(float freq, bool calibrate, float band = 4); + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm. + \param power Output power to be set in dBm. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power); + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.cpp b/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.cpp new file mode 100644 index 000000000..161a52453 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.cpp @@ -0,0 +1,2181 @@ +#include "SX126x.h" +#include +#include +#if !RADIOLIB_EXCLUDE_SX126X + +SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, RADIOLIB_SX126X_MAX_PACKET_LENGTH) { + this->mod = mod; + this->XTAL = false; + this->standbyXOSC = false; +} + +int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; + this->mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; + this->mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; + this->mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS; + this->mod->SPIstreamType = true; + this->mod->SPIparseStatusCb = SPIparseStatus; + + // try to find the SX126x chip + if(!SX126x::findChip(this->chipType)) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX126x found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX126x"); + + // BW in kHz and SF are required in order to calculate LDRO for setModulationParams + // set the defaults, this will get overwritten later anyway + this->bandwidthKhz = 500.0; + this->spreadingFactor = 9; + + // initialize configuration variables (will be overwritten during public settings configuration) + this->bandwidth = RADIOLIB_SX126X_LORA_BW_500_0; // initialized to 500 kHz, since lower valeus will interfere with LLCC68 + this->codingRate = RADIOLIB_SX126X_LORA_CR_4_7; + this->ldrOptimize = 0x00; + this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON; + this->preambleLengthLoRa = preambleLength; + this->tcxoDelay = 0; + this->headerType = RADIOLIB_SX126X_LORA_HEADER_EXPLICIT; + this->implicitLen = 0xFF; + + // reset the module and verify startup + int16_t state = reset(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // set TCXO control, if requested + if(!this->XTAL && tcxoVoltage > 0.0) { + state = setTCXO(tcxoVoltage); + RADIOLIB_ASSERT(state); + } + + // configure settings not accessible by API + state = config(RADIOLIB_SX126X_PACKET_TYPE_LORA); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setSyncWord(syncWord); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + if (useRegulatorLDO) { + state = setRegulatorLDO(); + } else { + state = setRegulatorDCDC(); + } + + // set publicly accessible settings that are not a part of begin method + state = setCurrentLimit(60.0); + RADIOLIB_ASSERT(state); + + state = setDio2AsRfSwitch(true); + RADIOLIB_ASSERT(state); + + state = setCRC(2); + RADIOLIB_ASSERT(state); + + state = invertIQ(false); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; + this->mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; + this->mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; + this->mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS; + this->mod->SPIstreamType = true; + this->mod->SPIparseStatusCb = SPIparseStatus; + + // try to find the SX126x chip + if(!SX126x::findChip(this->chipType)) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX126x found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX126x"); + + // initialize configuration variables (will be overwritten during public settings configuration) + this->bitRate = 21333; // 48.0 kbps + this->frequencyDev = 52428; // 50.0 kHz + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2; + this->rxBandwidthKhz = 156.2; + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5; + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV; // CCIT CRC configuration + this->preambleLengthFSK = preambleLength; + this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF; + + // reset the module and verify startup + int16_t state = reset(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // set TCXO control, if requested + if(!this->XTAL && tcxoVoltage > 0.0) { + state = setTCXO(tcxoVoltage); + RADIOLIB_ASSERT(state); + } + + // configure settings not accessible by API + state = config(RADIOLIB_SX126X_PACKET_TYPE_GFSK); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + state = setRxBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + state = setCurrentLimit(60.0); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + if(useRegulatorLDO) { + state = setRegulatorLDO(); + } else { + state = setRegulatorDCDC(); + } + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + uint8_t sync[] = {0x12, 0xAD}; + state = setSyncWord(sync, 2); + RADIOLIB_ASSERT(state); + + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + + state = setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + + state = variablePacketLengthMode(RADIOLIB_SX126X_MAX_PACKET_LENGTH); + RADIOLIB_ASSERT(state); + + state = setCRC(2); + RADIOLIB_ASSERT(state); + + state = setDio2AsRfSwitch(true); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX126x::reset(bool verify) { + // run the reset sequence + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + this->mod->hal->delay(1); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + + // return immediately when verification is disabled + if(!verify) { + return(RADIOLIB_ERR_NONE); + } + + // set mode to standby - SX126x often refuses first few commands after reset + uint32_t start = this->mod->hal->millis(); + while(true) { + // try to set mode to standby + int16_t state = standby(); + if(state == RADIOLIB_ERR_NONE) { + // standby command successful + return(RADIOLIB_ERR_NONE); + } + + // standby command failed, check timeout and try again + if(this->mod->hal->millis() - start >= 1000) { + // timed out, possibly incorrect wiring + return(state); + } + + // wait a bit to not spam the module + this->mod->hal->delay(10); + } +} + +int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // check packet length + if(len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + uint32_t timeout = 0; + + // get currently active modem + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + // calculate timeout (150% of expected time-on-air) + timeout = (getTimeOnAir(len) * 3) / 2; + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // calculate timeout (500% of expected time-on-air) + timeout = getTimeOnAir(len) * 5; + + } else { + return(RADIOLIB_ERR_UNKNOWN); + } + + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); + + // start transmission + state = startTransmit(data, len, addr); + RADIOLIB_ASSERT(state); + + // wait for packet transmission or timeout + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { + finishTransmit(); + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + uint32_t elapsed = this->mod->hal->micros() - start; + + // update data rate + this->dataRateMeasured = (len*8.0)/((float)elapsed/1000000.0); + + return(finishTransmit()); +} + +int16_t SX126x::receive(uint8_t* data, size_t len) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + uint32_t timeout = 0; + + // get currently active modem + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + // calculate timeout (100 LoRa symbols, the default for SX127x series) + float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; + timeout = (uint32_t)(symbolLength * 100.0 * 1000.0); + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // calculate timeout (500 % of expected time-one-air) + size_t maxLen = len; + if(len == 0) { + maxLen = 0xFF; + } + float brBps = ((float)(RADIOLIB_SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)this->bitRate; + timeout = (uint32_t)(((maxLen * 8.0) / brBps) * 1000000.0 * 5.0); + + } else { + return(RADIOLIB_ERR_UNKNOWN); + } + + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); + + // start reception + uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); + state = startReceive(timeoutValue); + RADIOLIB_ASSERT(state); + + // wait for packet reception or timeout + bool softTimeout = false; + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + // safety check, the timeout should be done by the radio + if(this->mod->hal->micros() - start > timeout) { + softTimeout = true; + break; + } + } + + // if it was a timeout, this will return an error code + state = standby(); + if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) { + return(state); + } + + // check whether this was a timeout or not + if((getIrqStatus() & RADIOLIB_SX126X_IRQ_TIMEOUT) || softTimeout) { + standby(); + fixImplicitTimeout(); + clearIrqStatus(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + + // fix timeout in implicit LoRa mode + if(((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) { + state = fixImplicitTimeout(); + RADIOLIB_ASSERT(state); + } + + // read the received data + return(readData(data, len)); +} + +int16_t SX126x::transmitDirect(uint32_t frf) { + // set RF switch (if present) + this->mod->setRfSwitchState(this->txMode); + + // user requested to start transmitting immediately (required for RTTY) + int16_t state = RADIOLIB_ERR_NONE; + if(frf != 0) { + state = setRfFrequency(frf); + } + RADIOLIB_ASSERT(state); + + // start transmitting + uint8_t data[] = {RADIOLIB_SX126X_CMD_NOP}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1)); +} + +int16_t SX126x::receiveDirect() { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // SX126x is unable to output received data directly + return(RADIOLIB_ERR_UNKNOWN); +} + +int16_t SX126x::directMode() { + // check modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // disable DIO2 RF switch + state = setDio2AsRfSwitch(false); + RADIOLIB_ASSERT(state); + + // set DIO2 to clock output and DIO3 to data input + // this is done exclusively by writing magic values to even more magic registers + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1, RADIOLIB_SX126X_TX_BITBANG_1_ENABLED, 6, 4); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0, RADIOLIB_SX126X_TX_BITBANG_0_ENABLED, 3, 0); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE, RADIOLIB_SX126X_DIO3_OUT_DISABLED, 3, 3); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_IN_ENABLE, RADIOLIB_SX126X_DIO3_IN_ENABLED, 3, 3); + RADIOLIB_ASSERT(state); + + // enable TxDone interrupt + state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE, RADIOLIB_SX126X_IRQ_TX_DONE); + RADIOLIB_ASSERT(state); + + // set preamble length to the maximum to prevent SX126x from exiting Tx mode for a while + state = setPreambleLength(0xFFFF); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX126x::packetMode() { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set preamble length to the default + state = setPreambleLength(16); + RADIOLIB_ASSERT(state); + + // disable TxDone interrupt + state = setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE); + RADIOLIB_ASSERT(state); + + // restore the magic registers + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_IN_ENABLE, RADIOLIB_SX126X_DIO3_IN_DISABLED, 3, 3); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE, RADIOLIB_SX126X_DIO3_OUT_ENABLED, 3, 3); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0, RADIOLIB_SX126X_TX_BITBANG_0_DISABLED, 3, 0); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1, RADIOLIB_SX126X_TX_BITBANG_1_DISABLED, 6, 4); + RADIOLIB_ASSERT(state); + + // enable DIO2 RF switch + state = setDio2AsRfSwitch(true); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX126x::scanChannel() { + return(this->scanChannel(RADIOLIB_SX126X_CAD_PARAM_DEFAULT, RADIOLIB_SX126X_CAD_PARAM_DEFAULT, RADIOLIB_SX126X_CAD_PARAM_DEFAULT)); +} + +int16_t SX126x::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { + // set mode to CAD + int state = startChannelScan(symbolNum, detPeak, detMin); + RADIOLIB_ASSERT(state); + + // wait for channel activity detected or timeout + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + } + + // check CAD result + return(getChannelScanResult()); +} + +int16_t SX126x::sleep(bool retainConfig) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + uint8_t sleepMode = RADIOLIB_SX126X_SLEEP_START_WARM | RADIOLIB_SX126X_SLEEP_RTC_OFF; + if(!retainConfig) { + sleepMode = RADIOLIB_SX126X_SLEEP_START_COLD | RADIOLIB_SX126X_SLEEP_RTC_OFF; + } + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false, false); + + // wait for SX126x to safely enter sleep mode + this->mod->hal->delay(1); + + return(state); +} + +int16_t SX126x::standby() { + return(SX126x::standby(this->standbyXOSC ? RADIOLIB_SX126X_STANDBY_XOSC : RADIOLIB_SX126X_STANDBY_RC)); +} + +int16_t SX126x::standby(uint8_t mode, bool wakeup) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + if(wakeup) { + // pull NSS low to wake up + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + } + + uint8_t data[] = { mode }; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); +} + +void SX126x::setDio1Action(void (*func)(void)) { + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising); +} + +void SX126x::clearDio1Action() { + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); +} + +void SX126x::setPacketReceivedAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void SX126x::clearPacketReceivedAction() { + this->clearDio1Action(); +} + +void SX126x::setPacketSentAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void SX126x::clearPacketSentAction() { + this->clearDio1Action(); +} + +void SX126x::setChannelScanAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void SX126x::clearChannelScanAction() { + this->clearDio1Action(); +} + + +int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { + // suppress unused variable warning + (void)addr; + + // check packet length + if(len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // maximum packet length is decreased by 1 when address filtering is active + if((this->addrComp != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) && (len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 1)) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set packet Length + int16_t state = RADIOLIB_ERR_NONE; + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, this->headerType, this->invertIQEnabled); + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType, len); + } else { + return(RADIOLIB_ERR_UNKNOWN); + } + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT, RADIOLIB_SX126X_IRQ_TX_DONE); + RADIOLIB_ASSERT(state); + + // set buffer pointers + state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // write packet to buffer + state = writeBuffer(data, len); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // fix sensitivity + state = fixSensitivity(); + RADIOLIB_ASSERT(state); + + // set RF switch (if present) + this->mod->setRfSwitchState(this->txMode); + + // start transmission + state = setTx(RADIOLIB_SX126X_TX_TIMEOUT_NONE); + RADIOLIB_ASSERT(state); + + // wait for BUSY to go low (= PA ramp up done) + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + } + + return(state); +} + +int16_t SX126x::finishTransmit() { + // clear interrupt flags + clearIrqStatus(); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + +int16_t SX126x::startReceive() { + return(this->startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, RADIOLIB_SX126X_IRQ_RX_DEFAULT, RADIOLIB_SX126X_IRQ_RX_DONE, 0)); +} + +int16_t SX126x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)len; + int16_t state = startReceiveCommon(timeout, irqFlags, irqMask); + RADIOLIB_ASSERT(state); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // set mode to receive + state = setRx(timeout); + + return(state); +} + +int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint16_t irqFlags, uint16_t irqMask) { + // datasheet claims time to go to sleep is ~500us, same to wake up, compensate for that with 1 ms + TCXO delay + uint32_t transitionTime = this->tcxoDelay + 1000; + sleepPeriod -= transitionTime; + + // divide by 15.625 + uint32_t rxPeriodRaw = (rxPeriod * 8) / 125; + uint32_t sleepPeriodRaw = (sleepPeriod * 8) / 125; + + // check 24 bit limit and zero value (likely not intended) + if((rxPeriodRaw & 0xFF000000) || (rxPeriodRaw == 0)) { + return(RADIOLIB_ERR_INVALID_RX_PERIOD); + } + + // this check of the high byte also catches underflow when we subtracted transitionTime + if((sleepPeriodRaw & 0xFF000000) || (sleepPeriodRaw == 0)) { + return(RADIOLIB_ERR_INVALID_SLEEP_PERIOD); + } + + int16_t state = startReceiveCommon(RADIOLIB_SX126X_RX_TIMEOUT_INF, irqFlags, irqMask); + RADIOLIB_ASSERT(state); + + uint8_t data[6] = {(uint8_t)((rxPeriodRaw >> 16) & 0xFF), (uint8_t)((rxPeriodRaw >> 8) & 0xFF), (uint8_t)(rxPeriodRaw & 0xFF), + (uint8_t)((sleepPeriodRaw >> 16) & 0xFF), (uint8_t)((sleepPeriodRaw >> 8) & 0xFF), (uint8_t)(sleepPeriodRaw & 0xFF)}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE, data, 6)); +} + +int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols, uint16_t irqFlags, uint16_t irqMask) { + if(senderPreambleLength == 0) { + senderPreambleLength = this->preambleLengthLoRa; + } + + // worst case is that the sender starts transmitting when we're just less than minSymbols from going back to sleep. + // in this case, we don't catch minSymbols before going to sleep, + // so we must be awake for at least that long before the sender stops transmitting. + uint16_t sleepSymbols = senderPreambleLength - 2 * minSymbols; + + // if we're not to sleep at all, just use the standard startReceive. + if(2 * minSymbols > senderPreambleLength) { + return(startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, irqFlags, irqMask)); + } + + uint32_t symbolLength = ((uint32_t)(10 * 1000) << this->spreadingFactor) / (10 * this->bandwidthKhz); + uint32_t sleepPeriod = symbolLength * sleepSymbols; + RADIOLIB_DEBUG_BASIC_PRINTLN("Auto sleep period: %lu", sleepPeriod); + + // when the unit detects a preamble, it starts a timer that will timeout if it doesn't receive a header in time. + // the duration is sleepPeriod + 2 * wakePeriod. + // The sleepPeriod doesn't take into account shutdown and startup time for the unit (~1ms) + // We need to ensure that the timeout is longer than senderPreambleLength. + // So we must satisfy: wakePeriod > (preamblePeriod - (sleepPeriod - 1000)) / 2. (A) + // we also need to ensure the unit is awake to see at least minSymbols. (B) + uint32_t wakePeriod = RADIOLIB_MAX( + (symbolLength * (senderPreambleLength + 1) - (sleepPeriod - 1000)) / 2, // (A) + symbolLength * (minSymbols + 1)); //(B) + RADIOLIB_DEBUG_BASIC_PRINTLN("Auto wake period: %lu", wakePeriod); + + // If our sleep period is shorter than our transition time, just use the standard startReceive + if(sleepPeriod < this->tcxoDelay + 1016) { + return(startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, irqFlags, irqMask)); + } + + return(startReceiveDutyCycle(wakePeriod, sleepPeriod, irqFlags, irqMask)); +} + +int16_t SX126x::startReceiveCommon(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask) { + // set DIO mapping + if(timeout != RADIOLIB_SX126X_RX_TIMEOUT_INF) { + irqMask |= RADIOLIB_SX126X_IRQ_TIMEOUT; + } + int16_t state = setDioIrqParams(irqFlags, irqMask); + RADIOLIB_ASSERT(state); + + // set buffer pointers + state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + + // restore original packet length + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled); + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + } else { + return(RADIOLIB_ERR_UNKNOWN); + } + + return(state); +} + +int16_t SX126x::readData(uint8_t* data, size_t len) { + // this method may get called from receive() after Rx timeout + // if that's the case, the first call will return "SPI command timeout error" + // check the IRQ to be sure this really originated from timeout event + int16_t state = this->mod->SPIcheckStream(); + if((state == RADIOLIB_ERR_SPI_CMD_TIMEOUT) && (getIrqStatus() & RADIOLIB_SX126X_IRQ_TIMEOUT)) { + // this is definitely Rx timeout + return(RADIOLIB_ERR_RX_TIMEOUT); + } + RADIOLIB_ASSERT(state); + + // check integrity CRC + uint16_t irq = getIrqStatus(); + int16_t crcState = RADIOLIB_ERR_NONE; + if((irq & RADIOLIB_SX126X_IRQ_CRC_ERR) || (irq & RADIOLIB_SX126X_IRQ_HEADER_ERR)) { + crcState = RADIOLIB_ERR_CRC_MISMATCH; + } + + // get packet length + size_t length = getPacketLength(); + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + length = len; + } + + // read packet data + state = readBuffer(data, length); + RADIOLIB_ASSERT(state); + + // reset the base addresses + state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + + // check if CRC failed - this is done after reading data to give user the option to keep them + RADIOLIB_ASSERT(crcState); + + return(state); +} + +int16_t SX126x::startChannelScan() { + return(this->startChannelScan(RADIOLIB_SX126X_CAD_PARAM_DEFAULT, RADIOLIB_SX126X_CAD_PARAM_DEFAULT, RADIOLIB_SX126X_CAD_PARAM_DEFAULT)); +} + +int16_t SX126x::startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // set DIO pin mapping + state = setDioIrqParams(RADIOLIB_SX126X_IRQ_CAD_DETECTED | RADIOLIB_SX126X_IRQ_CAD_DONE, RADIOLIB_SX126X_IRQ_CAD_DETECTED | RADIOLIB_SX126X_IRQ_CAD_DONE); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // set mode to CAD + state = setCad(symbolNum, detPeak, detMin); + return(state); +} + +int16_t SX126x::getChannelScanResult() { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check CAD result + uint16_t cadResult = getIrqStatus(); + if(cadResult & RADIOLIB_SX126X_IRQ_CAD_DETECTED) { + // detected some LoRa activity + return(RADIOLIB_LORA_DETECTED); + } else if(cadResult & RADIOLIB_SX126X_IRQ_CAD_DONE) { + // channel is free + return(RADIOLIB_CHANNEL_FREE); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + +int16_t SX126x::setBandwidth(float bw) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // ensure byte conversion doesn't overflow + RADIOLIB_CHECK_RANGE(bw, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + + // check allowed bandwidth values + uint8_t bw_div2 = bw / 2 + 0.01; + switch (bw_div2) { + case 3: // 7.8: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_7_8; + break; + case 5: // 10.4: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_10_4; + break; + case 7: // 15.6: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_15_6; + break; + case 10: // 20.8: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_20_8; + break; + case 15: // 31.25: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_31_25; + break; + case 20: // 41.7: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_41_7; + break; + case 31: // 62.5: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_62_5; + break; + case 62: // 125.0: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_125_0; + break; + case 125: // 250.0 + this->bandwidth = RADIOLIB_SX126X_LORA_BW_250_0; + break; + case 250: // 500.0 + this->bandwidth = RADIOLIB_SX126X_LORA_BW_500_0; + break; + default: + return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } + + // update modulation parameters + this->bandwidthKhz = bw; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t SX126x::setSpreadingFactor(uint8_t sf) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + + // update modulation parameters + this->spreadingFactor = sf; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t SX126x::setCodingRate(uint8_t cr) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + RADIOLIB_CHECK_RANGE(cr, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + + // update modulation parameters + this->codingRate = cr - 4; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // update register + uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))}; + return(writeRegister(RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB, data, 2)); +} + +int16_t SX126x::setCurrentLimit(float currentLimit) { + // check allowed range + if(!((currentLimit >= 0) && (currentLimit <= 140))) { + return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT); + } + + // calculate raw value + uint8_t rawLimit = (uint8_t)(currentLimit / 2.5); + + // update register + return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1)); +} + +float SX126x::getCurrentLimit() { + // get the raw value + uint8_t ocp = 0; + readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + + // return the actual value + return((float)ocp * 2.5); +} + +int16_t SX126x::setPreambleLength(size_t preambleLength) { + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + this->preambleLengthLoRa = preambleLength; + return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + this->preambleLengthFSK = preambleLength; + return(setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType)); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + +int16_t SX126x::setFrequencyDeviation(float freqDev) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set frequency deviation to lowest available setting (required for digimodes) + float newFreqDev = freqDev; + if(freqDev < 0.0) { + newFreqDev = 0.6; + } + + RADIOLIB_CHECK_RANGE(newFreqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + + // calculate raw frequency deviation value + uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0)); + + // check modulation parameters + this->frequencyDev = freqDevRaw; + + // update modulation parameters + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); +} + +int16_t SX126x::setBitRate(float br) { + // check active modem + uint8_t modem = getPacketType(); + if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + RADIOLIB_CHECK_RANGE(br, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + } + + // calculate raw bit rate value + uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0)); + + // check modulation parameters + this->bitRate = brRaw; + + // update modulation parameters + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); +} + +int16_t SX126x::setDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + RADIOLIB_ASSERT(state); + + // set the coding rate + state = this->setCodingRate(dr.lora.codingRate); + } + + return(state); +} + +int16_t SX126x::checkDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + return(RADIOLIB_ERR_NONE); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); + + } + + return(state); +} + +int16_t SX126x::setRxBandwidth(float rxBw) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check modulation parameters + /*if(2 * this->frequencyDev + this->bitRate > rxBw * 1000.0) { + return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); + }*/ + this->rxBandwidthKhz = rxBw; + + // check allowed receiver bandwidth values + if(fabs(rxBw - 4.8) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_4_8; + } else if(fabs(rxBw - 5.8) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_5_8; + } else if(fabs(rxBw - 7.3) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_7_3; + } else if(fabs(rxBw - 9.7) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_9_7; + } else if(fabs(rxBw - 11.7) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_11_7; + } else if(fabs(rxBw - 14.6) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_14_6; + } else if(fabs(rxBw - 19.5) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_19_5; + } else if(fabs(rxBw - 23.4) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_23_4; + } else if(fabs(rxBw - 29.3) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_29_3; + } else if(fabs(rxBw - 39.0) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_39_0; + } else if(fabs(rxBw - 46.9) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_46_9; + } else if(fabs(rxBw - 58.6) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_58_6; + } else if(fabs(rxBw - 78.2) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_78_2; + } else if(fabs(rxBw - 93.8) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_93_8; + } else if(fabs(rxBw - 117.3) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_117_3; + } else if(fabs(rxBw - 156.2) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2; + } else if(fabs(rxBw - 187.2) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_187_2; + } else if(fabs(rxBw - 234.3) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_234_3; + } else if(fabs(rxBw - 312.0) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_312_0; + } else if(fabs(rxBw - 373.6) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_373_6; + } else if(fabs(rxBw - 467.0) <= 0.001) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_467_0; + } else { + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); + } + + // update modulation parameters + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); +} + +int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) { + // read the current register value + uint8_t rxGain = 0; + int16_t state = readRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1); + RADIOLIB_ASSERT(state); + + // gain mode register value (SX1261/2 datasheet v2.1 section 9.6) + if(rxbgm) { + rxGain = RADIOLIB_SX126X_RX_GAIN_BOOSTED; + } else { + rxGain = RADIOLIB_SX126X_RX_GAIN_POWER_SAVING; + } + + // update RX gain setting register + state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1); + RADIOLIB_ASSERT(state); + + // add Rx Gain register to retention memory if requested + if(persist) { + // values and registers below are specified in SX126x datasheet v2.1 section 9.6, just below table 9-3 + uint8_t value0 = 0x01; + uint8_t value1 = 0x08; + uint8_t value2 = 0xAC; + + state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, &value0, 1); + RADIOLIB_ASSERT(state); + + state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1, &value1, 1); + RADIOLIB_ASSERT(state); + + state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2, &value2, 1); + RADIOLIB_ASSERT(state); + } + + return(state); +} + +int16_t SX126x::setDataShaping(uint8_t sh) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set data shaping + switch(sh) { + case RADIOLIB_SHAPING_NONE: + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE; + break; + case RADIOLIB_SHAPING_0_3: + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3; + break; + case RADIOLIB_SHAPING_0_5: + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5; + break; + case RADIOLIB_SHAPING_0_7: + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7; + break; + case RADIOLIB_SHAPING_1_0: + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1; + break; + default: + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); + } + + // update modulation parameters + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); +} + +int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) { + // check active modem + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // check sync word Length + if(len > 8) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + + // write sync word + int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len); + RADIOLIB_ASSERT(state); + + // update packet parameters + this->syncWordLength = len * 8; + state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + + return(state); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + // with length set to 1 and LoRa modem active, assume it is the LoRa sync word + if(len > 1) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + return(setSyncWord(syncWord[0])); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + +int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check sync word Length + if(bitsLen > 0x40) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + + uint8_t bytesLen = bitsLen / 8; + if ((bitsLen % 8) != 0) { + bytesLen++; + } + + // write sync word + int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, bytesLen); + RADIOLIB_ASSERT(state); + + // update packet parameters + this->syncWordLength = bitsLen; + state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + + return(state); +} + +int16_t SX126x::setNodeAddress(uint8_t nodeAddr) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // enable address filtering (node only) + this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE; + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + RADIOLIB_ASSERT(state); + + // set node address + state = writeRegister(RADIOLIB_SX126X_REG_NODE_ADDRESS, &nodeAddr, 1); + + return(state); +} + +int16_t SX126x::setBroadcastAddress(uint8_t broadAddr) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // enable address filtering (node and broadcast) + this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST; + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + RADIOLIB_ASSERT(state); + + // set broadcast address + state = writeRegister(RADIOLIB_SX126X_REG_BROADCAST_ADDRESS, &broadAddr, 1); + + return(state); +} + +int16_t SX126x::disableAddressFiltering() { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // disable address filtering + this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF; + return(setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening)); +} + +int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) { + // check active modem + uint8_t modem = getPacketType(); + + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // update packet parameters + switch(len) { + case 0: + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF; + break; + case 1: + if(inverted) { + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV; + } else { + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE; + } + break; + case 2: + if(inverted) { + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV; + } else { + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE; + } + break; + default: + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); + } + + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + RADIOLIB_ASSERT(state); + + // write initial CRC value + uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)}; + state = writeRegister(RADIOLIB_SX126X_REG_CRC_INITIAL_MSB, data, 2); + RADIOLIB_ASSERT(state); + + // write CRC polynomial value + data[0] = (uint8_t)((polynomial >> 8) & 0xFF); + data[1] = (uint8_t)(polynomial & 0xFF); + state = writeRegister(RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2); + + return(state); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion + + // update packet parameters + if(len) { + this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON; + } else { + this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_OFF; + } + + return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + +int16_t SX126x::setWhitening(bool enabled, uint16_t initial) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + int16_t state = RADIOLIB_ERR_NONE; + if(!enabled) { + // disable whitening + this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF; + + state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + RADIOLIB_ASSERT(state); + + } else { + // enable whitening + this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON; + + // write initial whitening value + // as per note on pg. 65 of datasheet v1.2: "The user should not change the value of the 7 MSB's of this register" + uint8_t data[2]; + // first read the actual value and mask 7 MSB which we can not change + // if different value is written in 7 MSB, the Rx won't even work (tested on HW) + state = readRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 1); + RADIOLIB_ASSERT(state); + + data[0] = (data[0] & 0xFE) | (uint8_t)((initial >> 8) & 0x01); + data[1] = (uint8_t)(initial & 0xFF); + state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2); + RADIOLIB_ASSERT(state); + + state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + RADIOLIB_ASSERT(state); + } + return(state); +} + +float SX126x::getDataRate() const { + return(this->dataRateMeasured); +} + +float SX126x::getRSSI(bool packet) { + if(packet) { + // get last packet RSSI from packet status + uint32_t packetStatus = getPacketStatus(); + uint8_t rssiPkt = packetStatus & 0xFF; + return(-1.0 * rssiPkt/2.0); + } else { + // get instantaneous RSSI value + uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RSSI_INST, data, 3); + return((float)data[0] / (-2.0)); + } +} + +float SX126x::getSNR() { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // get last packet SNR from packet status + uint32_t packetStatus = getPacketStatus(); + uint8_t snrPkt = (packetStatus >> 8) & 0xFF; + if(snrPkt < 128) { + return(snrPkt/4.0); + } else { + return((snrPkt - 256)/4.0); + } +} + +float SX126x::getFrequencyError() { + // check active modem + uint8_t modem = getPacketType(); + if(modem != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(0.0); + } + + // read the raw frequency error register values + uint8_t efeRaw[3] = {0}; + int16_t state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR, &efeRaw[0], 1); + RADIOLIB_ASSERT(state); + state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR + 1, &efeRaw[1], 1); + RADIOLIB_ASSERT(state); + state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR + 2, &efeRaw[2], 1); + RADIOLIB_ASSERT(state); + uint32_t efe = ((uint32_t) efeRaw[0] << 16) | ((uint32_t) efeRaw[1] << 8) | efeRaw[2]; + efe &= 0x0FFFFF; + + float error = 0; + + // check the first bit + if (efe & 0x80000) { + // frequency error is negative + efe |= (uint32_t) 0xFFF00000; + efe = ~efe + 1; + error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz) * -1.0; + } else { + error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz); + } + + return(error); +} + +size_t SX126x::getPacketLength(bool update) { + (void)update; + + // in implicit mode, return the cached value + if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT)) { + return(this->implicitLen); + } + + uint8_t rxBufStatus[2] = {0, 0}; + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); + return((size_t)rxBufStatus[0]); +} + +int16_t SX126x::fixedPacketLengthMode(uint8_t len) { + return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_FIXED, len)); +} + +int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) { + return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen)); +} + +uint32_t SX126x::getTimeOnAir(size_t len) { + // everything is in microseconds to allow integer arithmetic + // some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact + if(getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << this->spreadingFactor) / (this->bandwidthKhz * 10) ; + uint8_t sfCoeff1_x4 = 17; // (4.25 * 4) + uint8_t sfCoeff2 = 8; + if(this->spreadingFactor == 5 || this->spreadingFactor == 6) { + sfCoeff1_x4 = 25; // 6.25 * 4 + sfCoeff2 = 0; + } + uint8_t sfDivisor = 4*this->spreadingFactor; + if(symbolLength_us >= 16000) { + sfDivisor = 4*(this->spreadingFactor - 2); + } + const int8_t bitsPerCrc = 16; + const int8_t N_symbol_header = this->headerType == RADIOLIB_SX126X_LORA_HEADER_EXPLICIT ? 20 : 0; + + // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8) + int16_t bitCount = (int16_t) 8 * len + this->crcTypeLoRa * bitsPerCrc - 4 * this->spreadingFactor + sfCoeff2 + N_symbol_header; + if(bitCount < 0) { + bitCount = 0; + } + // add (sfDivisor) - 1 to the numerator to give integer CEIL(...) + uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor); + + // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit + uint32_t nSymbol_x4 = (this->preambleLengthLoRa + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * (this->codingRate + 4) * 4; + + return((symbolLength_us * nSymbol_x4) / 4); + } else { + return((len * 8 * this->bitRate) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 32)); + } +} + +uint32_t SX126x::calculateRxTimeout(uint32_t timeoutUs) { + // the timeout value is given in units of 15.625 microseconds + // the calling function should provide some extra width, as this number of units is truncated to integer + uint32_t timeout = timeoutUs / 15.625; + return(timeout); +} + +int16_t SX126x::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) { + irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT; // flags that can appear in the IRQ register + irqMask = RADIOLIB_SX126X_IRQ_RX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT; // flags that will trigger DIO0 + return(RADIOLIB_ERR_NONE); +} + +bool SX126x::isRxTimeout() { + uint16_t irq = getIrqStatus(); + bool rxTimedOut = irq & RADIOLIB_SX126X_IRQ_TIMEOUT; + return(rxTimedOut); +} + +int16_t SX126x::implicitHeader(size_t len) { + return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len)); +} + +int16_t SX126x::explicitHeader() { + return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_EXPLICIT)); +} + +int16_t SX126x::setRegulatorLDO() { + return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_LDO)); +} + +int16_t SX126x::setRegulatorDCDC() { + return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_DC_DC)); +} + +int16_t SX126x::setEncoding(uint8_t encoding) { + return(setWhitening(encoding)); +} + +void SX126x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { + this->mod->setRfSwitchPins(rxEn, txEn); +} + +void SX126x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + this->mod->setRfSwitchTable(pins, table); +} + +int16_t SX126x::forceLDRO(bool enable) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // update modulation parameters + this->ldroAuto = false; + this->ldrOptimize = (uint8_t)enable; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t SX126x::autoLDRO() { + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + this->ldroAuto = true; + return(RADIOLIB_ERR_NONE); +} + +uint8_t SX126x::randomByte() { + // set some magic registers + this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_LNA, RADIOLIB_SX126X_LNA_RNG_ENABLED, 0, 0); + this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_MIXER, RADIOLIB_SX126X_MIXER_RNG_ENABLED, 0, 0); + + // set mode to Rx + setRx(RADIOLIB_SX126X_RX_TIMEOUT_INF); + + // wait a bit for the RSSI reading to stabilise + this->mod->hal->delay(10); + + // read RSSI value 8 times, always keep just the least significant bit + uint8_t randByte = 0x00; + for(uint8_t i = 0; i < 8; i++) { + uint8_t val = 0x00; + readRegister(RADIOLIB_SX126X_REG_RANDOM_NUMBER_0, &val, sizeof(uint8_t)); + randByte |= ((val & 0x01) << i); + } + + // set mode to standby + standby(); + + // restore the magic registers + this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_LNA, RADIOLIB_SX126X_LNA_RNG_DISABLED, 0, 0); + this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_MIXER, RADIOLIB_SX126X_MIXER_RNG_DISABLED, 0, 0); + + return(randByte); +} + +int16_t SX126x::invertIQ(bool enable) { + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + if(enable) { + this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_INVERTED; + } else { + this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; + } + + return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); +} + +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE +void SX126x::setDirectAction(void (*func)(void)) { + setDio1Action(func); +} + +void SX126x::readBit(uint32_t pin) { + updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin)); +} +#endif + +int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) { + // set to standby RC mode + int16_t state = standby(RADIOLIB_SX126X_STANDBY_RC); + RADIOLIB_ASSERT(state); + + // check the version + #if RADIOLIB_DEBUG_BASIC + char ver_pre[16]; + this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_pre); + RADIOLIB_DEBUG_BASIC_PRINTLN("Pre-update version string: %s", ver_pre); + #endif + + // enable patch update + this->mod->SPIwriteRegister(RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE, RADIOLIB_SX126X_PATCH_UPDATE_ENABLED); + + // upload the patch + uint8_t data[4]; + for(uint32_t i = 0; i < len / sizeof(uint32_t); i++) { + uint32_t bin = 0; + if(nonvolatile) { + bin = RADIOLIB_NONVOLATILE_READ_DWORD(patch + i); + } else { + bin = patch[i]; + } + data[0] = (bin >> 24) & 0xFF; + data[1] = (bin >> 16) & 0xFF; + data[2] = (bin >> 8) & 0xFF; + data[3] = bin & 0xFF; + this->mod->SPIwriteRegisterBurst(RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE + i*sizeof(uint32_t), data, sizeof(uint32_t)); + } + + // disable patch update + this->mod->SPIwriteRegister(RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE, RADIOLIB_SX126X_PATCH_UPDATE_DISABLED); + + // update + this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_PRAM_UPDATE, NULL, 0); + + // check the version again + #if RADIOLIB_DEBUG_BASIC + char ver_post[16]; + this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_post); + RADIOLIB_DEBUG_BASIC_PRINTLN("Post-update version string: %s", ver_post); + #endif + + return(state); +} + +int16_t SX126x::spectralScanStart(uint16_t numSamples, uint8_t window, uint8_t interval) { + // abort first - not sure if this is strictly needed, but the example code does this + spectralScanAbort(); + + // set the RSSI window size + this->mod->SPIwriteRegister(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, window); + + // start Rx with infinite timeout + int16_t state = setRx(RADIOLIB_SX126X_RX_TIMEOUT_INF); + RADIOLIB_ASSERT(state); + + // now set the actual spectral scan parameters + uint8_t data[3] = { (uint8_t)((numSamples >> 8) & 0xFF), (uint8_t)(numSamples & 0xFF), interval }; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS, data, 3)); +} + +void SX126x::spectralScanAbort() { + this->mod->SPIwriteRegister(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, 0x00); +} + +int16_t SX126x::spectralScanGetStatus() { + uint8_t status = this->mod->SPIreadRegister(RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS); + if(status == RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED) { + return(RADIOLIB_ERR_NONE); + } + return(RADIOLIB_ERR_RANGING_TIMEOUT); +} + +int16_t SX126x::spectralScanGetResult(uint16_t* results) { + // read the raw results + uint8_t data[2*RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; + this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT, 2*RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE, data); + + // convert it + for(uint8_t i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) { + results[i] = ((uint16_t)data[i*2] << 8) | ((uint16_t)data[i*2 + 1]); + } + return(RADIOLIB_ERR_NONE); +} + +int16_t SX126x::setTCXO(float voltage, uint32_t delay) { + // check if TCXO is enabled at all + if(this->XTAL) { + return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); + } + + // set mode to standby + standby(); + + // check RADIOLIB_SX126X_XOSC_START_ERR flag and clear it + if(getDeviceErrors() & RADIOLIB_SX126X_XOSC_START_ERR) { + clearDeviceErrors(); + } + + // check 0 V disable + if(fabs(voltage - 0.0) <= 0.001) { + return(reset(true)); + } + + // check alowed voltage values + uint8_t data[4]; + if(fabs(voltage - 1.6) <= 0.001) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_6; + } else if(fabs(voltage - 1.7) <= 0.001) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_7; + } else if(fabs(voltage - 1.8) <= 0.001) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_8; + } else if(fabs(voltage - 2.2) <= 0.001) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_2; + } else if(fabs(voltage - 2.4) <= 0.001) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_4; + } else if(fabs(voltage - 2.7) <= 0.001) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_7; + } else if(fabs(voltage - 3.0) <= 0.001) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_0; + } else if(fabs(voltage - 3.3) <= 0.001) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_3; + } else { + return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); + } + + // calculate delay + uint32_t delayValue = (float)delay / 15.625; + data[1] = (uint8_t)((delayValue >> 16) & 0xFF); + data[2] = (uint8_t)((delayValue >> 8) & 0xFF); + data[3] = (uint8_t)(delayValue & 0xFF); + + this->tcxoDelay = delay; + + // enable TCXO control on DIO3 + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4)); +} + +int16_t SX126x::setDio2AsRfSwitch(bool enable) { + uint8_t data = 0; + if(enable) { + data = RADIOLIB_SX126X_DIO2_AS_RF_SWITCH; + } else { + data = RADIOLIB_SX126X_DIO2_AS_IRQ; + } + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); +} + +int16_t SX126x::setFs() { + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_FS, NULL, 0)); +} + +int16_t SX126x::setTx(uint32_t timeout) { + uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)} ; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX, data, 3)); +} + +int16_t SX126x::setRx(uint32_t timeout) { + uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) }; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false)); +} + + +int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { + // default CAD parameters are shown in Semtech AN1200.48, page 41. + uint8_t detPeakValues[6] = { 22, 22, 24, 25, 26, 30}; + + // CAD parameters aren't available for SF-6. Just to be safe. + if(this->spreadingFactor < 7) { + this->spreadingFactor = 7; + } else if(this->spreadingFactor > 12) { + this->spreadingFactor = 12; + } + + // build the packet + uint8_t data[7]; + data[0] = RADIOLIB_SX126X_CAD_ON_2_SYMB; + data[1] = detPeakValues[this->spreadingFactor - 7]; + data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; + data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; + data[4] = 0x00; + data[5] = 0x00; + data[6] = 0x00; + + + /* + CAD Configuration Note: + The default CAD configuration applied by `scanChannel` overrides the optimal SF-specific configurations, leading to suboptimal detection. + I.e., anything that is not RADIOLIB_SX126X_CAD_PARAM_DEFAULT is overridden. But CAD settings are SF specific. + To address this, the user override has been commented out, ensuring consistent application of the optimal CAD settings as + per Semtech's Application Note AN1200.48 (page 41) for the 125KHz setting. This approach significantly reduces false CAD occurrences. + Testing has shown that there is no reason for a user to change CAD settings for anything other than most optimal ones described in AN1200.48 . + However, this change does not respect CAD configs from the LoRaWAN layer. Future considerations or use cases might require revisiting this decision. + Hence this note. +*/ + +/* + // set user-provided values + if(symbolNum != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { + data[0] = symbolNum; + } + + if(detPeak != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { + data[1] = detPeak; + } + + if(detMin != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { + data[2] = detMin; + } + +*/ + (void)symbolNum; + (void)detPeak; + (void)detMin; + + // configure parameters + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); + RADIOLIB_ASSERT(state); + + // start CAD + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0)); +} + +int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax, uint8_t paLut) { + uint8_t data[] = { paDutyCycle, hpMax, deviceSel, paLut }; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PA_CONFIG, data, 4)); +} + +int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { + this->mod->SPIwriteRegisterBurst(addr, data, numBytes); + return(RADIOLIB_ERR_NONE); +} + +int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { + // send the command + this->mod->SPIreadRegisterBurst(addr, numBytes, data); + + // check the status + int16_t state = this->mod->SPIcheckStream(); + return(state); +} + +int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { + uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_BUFFER, offset }; + return(this->mod->SPIwriteStream(cmd, 2, data, numBytes)); +} + +int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { + uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_BUFFER, offset }; + return(this->mod->SPIreadStream(cmd, 2, data, numBytes)); +} + +int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { + uint8_t data[8] = {(uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF), + (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), + (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), + (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF)}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); +} + +uint16_t SX126x::getIrqStatus() { + uint8_t data[] = { 0x00, 0x00 }; + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_IRQ_STATUS, data, 2); + return(((uint16_t)(data[0]) << 8) | data[1]); +} + +int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) { + uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS, data, 2)); +} + +int16_t SX126x::setRfFrequency(uint32_t frf) { + uint8_t data[] = { (uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4)); +} + +int16_t SX126x::calibrateImage(float freqMin, float freqMax) { + uint8_t data[] = { (uint8_t)floor((freqMin - 1.0f) / 4.0f), (uint8_t)ceil((freqMax + 1.0f) / 4.0f) }; + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); + + // if something failed, show the device errors + #if RADIOLIB_DEBUG_BASIC + if(state != RADIOLIB_ERR_NONE) { + // unless mode is forced to standby, device errors will be 0 + standby(); + uint16_t errors = getDeviceErrors(); + RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); + } + #endif + return(state); +} + +uint8_t SX126x::getPacketType() { + uint8_t data = 0xFF; + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_TYPE, &data, 1); + return(data); +} + +int16_t SX126x::setTxParams(uint8_t pwr, uint8_t rampTime) { + uint8_t data[] = { pwr, rampTime }; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2)); +} + +int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set requested packet mode + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, mode, len); + RADIOLIB_ASSERT(state); + + // update cached value + this->packetType = mode; + return(state); +} + +int16_t SX126x::setHeaderType(uint8_t hdrType, size_t len) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set requested packet mode + int16_t state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, hdrType, this->invertIQEnabled); + RADIOLIB_ASSERT(state); + + // update cached value + this->headerType = hdrType; + this->implicitLen = len; + + return(state); +} + +int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) { + // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; + if(symbolLength >= 16.0) { + this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON; + } else { + this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF; + } + } else { + this->ldrOptimize = ldro; + } + // 500/9/8 - 0x09 0x04 0x03 0x00 - SF9, BW125, 4/8 + // 500/11/8 - 0x0B 0x04 0x03 0x00 - SF11 BW125, 4/7 + uint8_t data[4] = {sf, bw, cr, this->ldrOptimize}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4)); +} + +int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev) { + uint8_t data[8] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), + sh, rxBw, + (uint8_t)((freqDev >> 16) & 0xFF), (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8)); +} + +int16_t SX126x::setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ) { + int16_t state = fixInvertedIQ(invertIQ); + RADIOLIB_ASSERT(state); + uint8_t data[6] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), hdrType, payloadLen, crcType, invertIQ}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 6)); +} + +int16_t SX126x::setPacketParamsFSK(uint16_t preambleLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType, uint8_t payloadLen, uint8_t preambleDetectorLen) { + uint8_t data[9] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), + preambleDetectorLen, syncWordLen, addrCmp, + packType, payloadLen, crcType, whiten}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9)); +} + +int16_t SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { + uint8_t data[2] = {txBaseAddress, rxBaseAddress}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); +} + +int16_t SX126x::setRegulatorMode(uint8_t mode) { + uint8_t data[1] = {mode}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE, data, 1)); +} + +uint8_t SX126x::getStatus() { + uint8_t data = 0; + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_STATUS, &data, 0); + return(data); +} + +uint32_t SX126x::getPacketStatus() { + uint8_t data[3] = {0, 0, 0}; + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_STATUS, data, 3); + return((((uint32_t)data[0]) << 16) | (((uint32_t)data[1]) << 8) | (uint32_t)data[2]); +} + +uint16_t SX126x::getDeviceErrors() { + uint8_t data[2] = {0, 0}; + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS, data, 2); + uint16_t opError = (((uint16_t)data[0] & 0xFF) << 8) | ((uint16_t)data[1]); + return(opError); +} + +int16_t SX126x::clearDeviceErrors() { + uint8_t data[2] = {RADIOLIB_SX126X_CMD_NOP, RADIOLIB_SX126X_CMD_NOP}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2)); +} + +int16_t SX126x::setFrequencyRaw(float freq) { + // calculate raw value + uint32_t frf = (freq * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ; + return(setRfFrequency(frf)); +} + +int16_t SX126x::fixSensitivity() { + // fix receiver sensitivity for 500 kHz LoRa + // see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.1 for details + + // read current sensitivity configuration + uint8_t sensitivityConfig = 0; + int16_t state = readRegister(RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG, &sensitivityConfig, 1); + RADIOLIB_ASSERT(state); + + // fix the value for LoRa with 500 kHz bandwidth + if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (fabs(this->bandwidthKhz - 500.0) <= 0.001)) { + sensitivityConfig &= 0xFB; + } else { + sensitivityConfig |= 0x04; + } + return(writeRegister(RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG, &sensitivityConfig, 1)); +} + +int16_t SX126x::fixPaClamping(bool enable) { + // fixes overly eager PA clamping + // see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.2 for details + + // read current clamping configuration + uint8_t clampConfig = 0; + int16_t state = readRegister(RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1); + RADIOLIB_ASSERT(state); + + // apply or undo workaround + if (enable) + clampConfig |= 0x1E; + else + clampConfig = (clampConfig & ~0x1E) | 0x08; + + return(writeRegister(RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1)); +} + +int16_t SX126x::fixImplicitTimeout() { + // fixes timeout in implicit header mode + // see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.3 for details + + //check if we're in implicit LoRa mode + if(!((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // stop RTC counter + uint8_t rtcStop = 0x00; + int16_t state = writeRegister(RADIOLIB_SX126X_REG_RTC_CTRL, &rtcStop, 1); + RADIOLIB_ASSERT(state); + + // read currently active event + uint8_t rtcEvent = 0; + state = readRegister(RADIOLIB_SX126X_REG_EVENT_MASK, &rtcEvent, 1); + RADIOLIB_ASSERT(state); + + // clear events + rtcEvent |= 0x02; + return(writeRegister(RADIOLIB_SX126X_REG_EVENT_MASK, &rtcEvent, 1)); +} + +int16_t SX126x::fixInvertedIQ(uint8_t iqConfig) { + // fixes IQ configuration for inverted IQ + // see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.4 for details + + // read current IQ configuration + uint8_t iqConfigCurrent = 0; + int16_t state = readRegister(RADIOLIB_SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1); + RADIOLIB_ASSERT(state); + + // set correct IQ configuration + if(iqConfig == RADIOLIB_SX126X_LORA_IQ_INVERTED) { + iqConfigCurrent &= 0xFB; + } else { + iqConfigCurrent |= 0x04; + } + + // update with the new value + return(writeRegister(RADIOLIB_SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1)); +} + +Module* SX126x::getMod() { + return(this->mod); +} + +int16_t SX126x::config(uint8_t modem) { + // reset buffer base address + int16_t state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // set modem + uint8_t data[7]; + data[0] = modem; + state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1); + RADIOLIB_ASSERT(state); + + // set Rx/Tx fallback mode to STDBY_RC + data[0] = this->standbyXOSC ? RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC : RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC; + state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); + RADIOLIB_ASSERT(state); + + // set some CAD parameters - will be overwritten when calling CAD anyway + data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB; + data[1] = this->spreadingFactor + 13; + data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; + data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; + data[4] = 0x00; + data[5] = 0x00; + data[6] = 0x00; + state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); + RADIOLIB_ASSERT(state); + + // clear IRQ + state = clearIrqStatus(); + state |= setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE); + RADIOLIB_ASSERT(state); + + // calibrate all blocks + data[0] = RADIOLIB_SX126X_CALIBRATE_ALL; + state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false); + RADIOLIB_ASSERT(state); + + // wait for calibration completion + this->mod->hal->delay(5); + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + } + + // check calibration result + state = this->mod->SPIcheckStream(); + + // if something failed, show the device errors + #if RADIOLIB_DEBUG_BASIC + if(state != RADIOLIB_ERR_NONE) { + // unless mode is forced to standby, device errors will be 0 + standby(); + uint16_t errors = getDeviceErrors(); + RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); + } + #endif + + return(state); +} + +int16_t SX126x::SPIparseStatus(uint8_t in) { + if((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_TIMEOUT) { + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + } else if((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_INVALID) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } else if((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_FAILED) { + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } else if((in == 0x00) || (in == 0xFF)) { + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + return(RADIOLIB_ERR_NONE); +} + +bool SX126x::findChip(const char* verStr) { + uint8_t i = 0; + bool flagFound = false; + while((i < 10) && !flagFound) { + // reset the module + reset(); + + // read the version string + char version[16]; + this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)version); + + // check version register + if(strncmp(verStr, version, 6) == 0) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Found SX126x: RADIOLIB_SX126X_REG_VERSION_STRING:"); + RADIOLIB_DEBUG_BASIC_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + RADIOLIB_DEBUG_BASIC_PRINTLN(); + flagFound = true; + } else { + #if RADIOLIB_DEBUG_BASIC + RADIOLIB_DEBUG_BASIC_PRINTLN("SX126x not found! (%d of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:", i + 1); + RADIOLIB_DEBUG_BASIC_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + RADIOLIB_DEBUG_BASIC_PRINTLN("Expected string: %s", verStr); + #endif + this->mod->hal->delay(10); + i++; + } + } + + return(flagFound); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.h b/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.h new file mode 100644 index 000000000..848433b8c --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/SX126x.h @@ -0,0 +1,1195 @@ +#if !defined(_RADIOLIB_SX126X_H) +#define _RADIOLIB_SX126X_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX126X + +#include "../../Module.h" + +#include "../../protocols/PhysicalLayer/PhysicalLayer.h" + +// SX126X physical layer properties +#define RADIOLIB_SX126X_FREQUENCY_STEP_SIZE 0.9536743164 +#define RADIOLIB_SX126X_MAX_PACKET_LENGTH 255 +#define RADIOLIB_SX126X_CRYSTAL_FREQ 32.0 +#define RADIOLIB_SX126X_DIV_EXPONENT 25 + +// SX126X SPI commands +// operational modes commands +#define RADIOLIB_SX126X_CMD_NOP 0x00 +#define RADIOLIB_SX126X_CMD_SET_SLEEP 0x84 +#define RADIOLIB_SX126X_CMD_SET_STANDBY 0x80 +#define RADIOLIB_SX126X_CMD_SET_FS 0xC1 +#define RADIOLIB_SX126X_CMD_SET_TX 0x83 +#define RADIOLIB_SX126X_CMD_SET_RX 0x82 +#define RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE 0x9F +#define RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE 0x94 +#define RADIOLIB_SX126X_CMD_SET_CAD 0xC5 +#define RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1 +#define RADIOLIB_SX126X_CMD_SET_TX_INFINITE_PREAMBLE 0xD2 +#define RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE 0x96 +#define RADIOLIB_SX126X_CMD_CALIBRATE 0x89 +#define RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE 0x98 +#define RADIOLIB_SX126X_CMD_SET_PA_CONFIG 0x95 +#define RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE 0x93 + +// register and buffer access commands +#define RADIOLIB_SX126X_CMD_WRITE_REGISTER 0x0D +#define RADIOLIB_SX126X_CMD_READ_REGISTER 0x1D +#define RADIOLIB_SX126X_CMD_WRITE_BUFFER 0x0E +#define RADIOLIB_SX126X_CMD_READ_BUFFER 0x1E + +// DIO and IRQ control +#define RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS 0x08 +#define RADIOLIB_SX126X_CMD_GET_IRQ_STATUS 0x12 +#define RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS 0x02 +#define RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL 0x9D +#define RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL 0x97 + +// RF, modulation and packet commands +#define RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY 0x86 +#define RADIOLIB_SX126X_CMD_SET_PACKET_TYPE 0x8A +#define RADIOLIB_SX126X_CMD_GET_PACKET_TYPE 0x11 +#define RADIOLIB_SX126X_CMD_SET_TX_PARAMS 0x8E +#define RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS 0x8B +#define RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS 0x8C +#define RADIOLIB_SX126X_CMD_SET_CAD_PARAMS 0x88 +#define RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F +#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0xA0 + +// status commands +#define RADIOLIB_SX126X_CMD_GET_STATUS 0xC0 +#define RADIOLIB_SX126X_CMD_GET_RSSI_INST 0x15 +#define RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS 0x13 +#define RADIOLIB_SX126X_CMD_GET_PACKET_STATUS 0x14 +#define RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS 0x17 +#define RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS 0x07 +#define RADIOLIB_SX126X_CMD_GET_STATS 0x10 +#define RADIOLIB_SX126X_CMD_RESET_STATS 0x00 + +#define RADIOLIB_SX126X_CMD_PRAM_UPDATE 0xD9 +#define RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS 0x9A +#define RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS 0x9B + +// SX126X register map +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_VERSION_STRING 0x0320 +#define RADIOLIB_SX126X_REG_HOPPING_ENABLE 0x0385 +#define RADIOLIB_SX126X_REG_LR_FHSS_PACKET_LENGTH 0x0386 +#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_HOPPING_BLOCKS 0x0387 +#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_MSB(X) (0x0388 + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_LSB(X) (0x0389 + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_0(X) (0x038A + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_1(X) (0x038B + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_2(X) (0x038C + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_3(X) (0x038D + (X)*6) +#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT 0x0401 +#define RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE 0x0580 +#define RADIOLIB_SX126X_REG_DIOX_DRIVE_STRENGTH 0x0582 +#define RADIOLIB_SX126X_REG_DIOX_IN_ENABLE 0x0583 +#define RADIOLIB_SX126X_REG_DIOX_PULL_UP_CTRL 0x0584 +#define RADIOLIB_SX126X_REG_DIOX_PULL_DOWN_CTRL 0x0585 +#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 0x0587 +#define RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE 0x0610 +#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 0x0680 +#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB 0x06B8 +#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_LSB 0x06B9 +#define RADIOLIB_SX126X_REG_RX_TX_PLD_LEN 0x06BB +#define RADIOLIB_SX126X_REG_CRC_INITIAL_MSB 0x06BC +#define RADIOLIB_SX126X_REG_CRC_INITIAL_LSB 0x06BD +#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB 0x06BE +#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_LSB 0x06BF +#define RADIOLIB_SX126X_REG_SYNC_WORD_0 0x06C0 +#define RADIOLIB_SX126X_REG_SYNC_WORD_1 0x06C1 +#define RADIOLIB_SX126X_REG_SYNC_WORD_2 0x06C2 +#define RADIOLIB_SX126X_REG_SYNC_WORD_3 0x06C3 +#define RADIOLIB_SX126X_REG_SYNC_WORD_4 0x06C4 +#define RADIOLIB_SX126X_REG_SYNC_WORD_5 0x06C5 +#define RADIOLIB_SX126X_REG_SYNC_WORD_6 0x06C6 +#define RADIOLIB_SX126X_REG_SYNC_WORD_7 0x06C7 +#define RADIOLIB_SX126X_REG_NODE_ADDRESS 0x06CD +#define RADIOLIB_SX126X_REG_BROADCAST_ADDRESS 0x06CE +#define RADIOLIB_SX126X_REG_PAYLOAD_LENGTH 0x0702 +#define RADIOLIB_SX126X_REG_PACKET_PARAMS 0x0704 +#define RADIOLIB_SX126X_REG_LORA_SYNC_TIMEOUT 0x0706 +#define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736 +#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB 0x0740 +#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_LSB 0x0741 +#define RADIOLIB_SX126X_REG_FREQ_ERROR 0x076B +#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS 0x07CD +#define RADIOLIB_SX126X_REG_RX_ADDR_PTR 0x0803 +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_0 0x0819 +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_1 0x081A +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_2 0x081B +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_3 0x081C +#define RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1 +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_0 0x088B +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_1 0x088C +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_2 0x088D +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_3 0x088E +#define RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW 0x089B +#define RADIOLIB_SX126X_REG_RX_GAIN 0x08AC +#define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8 +#define RADIOLIB_SX126X_REG_ANA_LNA 0x08E2 +#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_N 0x08E3 +#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_P 0x08E4 +#define RADIOLIB_SX126X_REG_ANA_MIXER 0x08E5 +#define RADIOLIB_SX126X_REG_OCP_CONFIGURATION 0x08E7 +#define RADIOLIB_SX126X_REG_RTC_CTRL 0x0902 +#define RADIOLIB_SX126X_REG_XTA_TRIM 0x0911 +#define RADIOLIB_SX126X_REG_XTB_TRIM 0x0912 +#define RADIOLIB_SX126X_REG_DIO3_OUT_VOLTAGE_CTRL 0x0920 +#define RADIOLIB_SX126X_REG_EVENT_MASK 0x0944 +#define RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE 0x8000 + +// SX126X SPI command variables +//RADIOLIB_SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION +#define RADIOLIB_SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default) +#define RADIOLIB_SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained +#define RADIOLIB_SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled +#define RADIOLIB_SX126X_SLEEP_RTC_ON 0b00000001 // 0 0 enabled + +//RADIOLIB_SX126X_CMD_SET_STANDBY +#define RADIOLIB_SX126X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator +#define RADIOLIB_SX126X_STANDBY_XOSC 0x01 // 7 0 32 MHz crystal oscillator + +//RADIOLIB_SX126X_CMD_SET_RX +#define RADIOLIB_SX126X_RX_TIMEOUT_NONE 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode) +#define RADIOLIB_SX126X_RX_TIMEOUT_INF 0xFFFFFF // 23 0 infinite (Rx continuous mode) + +//RADIOLIB_SX126X_CMD_SET_TX +#define RADIOLIB_SX126X_TX_TIMEOUT_NONE 0x000000 // 23 0 Tx timeout duration: no timeout (Tx single mode) + +//RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE +#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_OFF 0x00 // 7 0 stop timer on: sync word or header (default) +#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_ON 0x01 // 7 0 preamble detection + +//RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE +#define RADIOLIB_SX126X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) +#define RADIOLIB_SX126X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC + +//RADIOLIB_SX126X_CMD_CALIBRATE +#define RADIOLIB_SX126X_CALIBRATE_IMAGE_OFF 0b00000000 // 6 6 image calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_IMAGE_ON 0b01000000 // 6 6 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_OFF 0b00000000 // 5 5 ADC bulk P calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_OFF 0b00000000 // 4 4 ADC bulk N calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_OFF 0b00000000 // 3 3 ADC pulse calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SX126X_CALIBRATE_PLL_OFF 0b00000000 // 2 2 PLL calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_PLL_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_SX126X_CALIBRATE_RC13M_OFF 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_RC13M_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_SX126X_CALIBRATE_RC64K_OFF 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled +#define RADIOLIB_SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks + +//RADIOLIB_SX126X_CMD_SET_PA_CONFIG +#define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07 +#define RADIOLIB_SX126X_PA_CONFIG_PA_LUT 0x01 +#define RADIOLIB_SX126X_PA_CONFIG_SX1262_8 0x00 + +//RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC 0x30 // 7 0 standby with crystal oscillator +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default) + +//RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS +#define RADIOLIB_SX126X_IRQ_LR_FHSS_HOP 0b0100000000000000 // 14 14 PA ramped up during LR-FHSS hop +#define RADIOLIB_SX126X_IRQ_TIMEOUT 0b0000001000000000 // 9 9 Rx or Tx timeout +#define RADIOLIB_SX126X_IRQ_CAD_DETECTED 0b0000000100000000 // 8 8 channel activity detected +#define RADIOLIB_SX126X_IRQ_CAD_DONE 0b0000000010000000 // 7 7 channel activity detection finished +#define RADIOLIB_SX126X_IRQ_CRC_ERR 0b0000000001000000 // 6 6 wrong CRC received +#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error +#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received +#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected +#define RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected +#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received +#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed +#define RADIOLIB_SX126X_IRQ_RX_DEFAULT 0b0000001001100010 // 14 0 default for Rx (RX_DONE, TIMEOUT, CRC_ERR and HEADER_ERR) +#define RADIOLIB_SX126X_IRQ_ALL 0b0100001111111111 // 14 0 all interrupts +#define RADIOLIB_SX126X_IRQ_NONE 0b0000000000000000 // 14 0 no interrupts + +//RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL +#define RADIOLIB_SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ +#define RADIOLIB_SX126X_DIO2_AS_RF_SWITCH 0x01 // 7 0 RF switch control + +//RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_6 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_7 0x01 // 7 0 1.7 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_8 0x02 // 7 0 1.8 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_2 0x03 // 7 0 2.2 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_4 0x04 // 7 0 2.4 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_7 0x05 // 7 0 2.7 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_3_0 0x06 // 7 0 3.0 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_3_3 0x07 // 7 0 3.3 V + +//RADIOLIB_SX126X_CMD_SET_PACKET_TYPE +#define RADIOLIB_SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK +#define RADIOLIB_SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa +#define RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS 0x03 // 7 0 LR-FHSS + +//RADIOLIB_SX126X_CMD_SET_TX_PARAMS +#define RADIOLIB_SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us +#define RADIOLIB_SX126X_PA_RAMP_20U 0x01 // 7 0 20 us +#define RADIOLIB_SX126X_PA_RAMP_40U 0x02 // 7 0 40 us +#define RADIOLIB_SX126X_PA_RAMP_80U 0x03 // 7 0 80 us +#define RADIOLIB_SX126X_PA_RAMP_200U 0x04 // 7 0 200 us +#define RADIOLIB_SX126X_PA_RAMP_800U 0x05 // 7 0 800 us +#define RADIOLIB_SX126X_PA_RAMP_1700U 0x06 // 7 0 1700 us +#define RADIOLIB_SX126X_PA_RAMP_3400U 0x07 // 7 0 3400 us + +//RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS +#define RADIOLIB_SX126X_GFSK_FILTER_NONE 0x00 // 7 0 GFSK filter: none +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3 0x08 // 7 0 Gaussian, BT = 0.3 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5 0x09 // 7 0 Gaussian, BT = 0.5 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7 0x0A // 7 0 Gaussian, BT = 0.7 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1 0x0B // 7 0 Gaussian, BT = 1 +#define RADIOLIB_SX126X_GFSK_RX_BW_4_8 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_5_8 0x17 // 7 0 5.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_7_3 0x0F // 7 0 7.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_9_7 0x1E // 7 0 9.7 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_11_7 0x16 // 7 0 11.7 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_14_6 0x0E // 7 0 14.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_19_5 0x1D // 7 0 19.5 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_23_4 0x15 // 7 0 23.4 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_29_3 0x0D // 7 0 29.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_39_0 0x1C // 7 0 39.0 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_46_9 0x14 // 7 0 46.9 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_58_6 0x0C // 7 0 58.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_78_2 0x1B // 7 0 78.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_93_8 0x13 // 7 0 93.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz +#define RADIOLIB_SX126X_LORA_BW_7_8 0x00 // 7 0 LoRa bandwidth: 7.8 kHz +#define RADIOLIB_SX126X_LORA_BW_10_4 0x08 // 7 0 10.4 kHz +#define RADIOLIB_SX126X_LORA_BW_15_6 0x01 // 7 0 15.6 kHz +#define RADIOLIB_SX126X_LORA_BW_20_8 0x09 // 7 0 20.8 kHz +#define RADIOLIB_SX126X_LORA_BW_31_25 0x02 // 7 0 31.25 kHz +#define RADIOLIB_SX126X_LORA_BW_41_7 0x0A // 7 0 41.7 kHz +#define RADIOLIB_SX126X_LORA_BW_62_5 0x03 // 7 0 62.5 kHz +#define RADIOLIB_SX126X_LORA_BW_125_0 0x04 // 7 0 125.0 kHz +#define RADIOLIB_SX126X_LORA_BW_250_0 0x05 // 7 0 250.0 kHz +#define RADIOLIB_SX126X_LORA_BW_500_0 0x06 // 7 0 500.0 kHz +#define RADIOLIB_SX126X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 +#define RADIOLIB_SX126X_LORA_CR_4_6 0x02 // 7 0 4/6 +#define RADIOLIB_SX126X_LORA_CR_4_7 0x03 // 7 0 4/7 +#define RADIOLIB_SX126X_LORA_CR_4_8 0x04 // 7 0 4/8 +#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled +#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled + +//RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 0x04 // 7 0 8 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 0x05 // 7 0 16 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 0x06 // 7 0 24 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 0x07 // 7 0 32 bits +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF 0x00 // 7 0 GFSK address filtering: disabled +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE 0x01 // 7 0 node only +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST 0x02 // 7 0 node and broadcast +#define RADIOLIB_SX126X_GFSK_PACKET_FIXED 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides) +#define RADIOLIB_SX126X_GFSK_PACKET_VARIABLE 0x01 // 7 0 variable (payload length added to packet) +#define RADIOLIB_SX126X_GFSK_CRC_OFF 0x01 // 7 0 GFSK packet CRC: disabled +#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE 0x00 // 7 0 1 byte +#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE 0x02 // 7 0 2 byte +#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV 0x04 // 7 0 1 byte, inverted +#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV 0x06 // 7 0 2 byte, inverted +#define RADIOLIB_SX126X_GFSK_WHITENING_OFF 0x00 // 7 0 GFSK data whitening: disabled +#define RADIOLIB_SX126X_GFSK_WHITENING_ON 0x01 // 7 0 enabled +#define RADIOLIB_SX126X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit +#define RADIOLIB_SX126X_LORA_HEADER_IMPLICIT 0x01 // 7 0 implicit +#define RADIOLIB_SX126X_LORA_CRC_OFF 0x00 // 7 0 LoRa CRC mode: disabled +#define RADIOLIB_SX126X_LORA_CRC_ON 0x01 // 7 0 enabled +#define RADIOLIB_SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard +#define RADIOLIB_SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted + +//RADIOLIB_SX126X_CMD_SET_CAD_PARAMS +#define RADIOLIB_SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 +#define RADIOLIB_SX126X_CAD_ON_2_SYMB 0x01 // 7 0 2 +#define RADIOLIB_SX126X_CAD_ON_4_SYMB 0x02 // 7 0 4 +#define RADIOLIB_SX126X_CAD_ON_8_SYMB 0x03 // 7 0 8 +#define RADIOLIB_SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16 +#define RADIOLIB_SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode +#define RADIOLIB_SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected +#define RADIOLIB_SX126X_CAD_PARAM_DEFAULT 0xFF // 7 0 used by the CAD methods to specify default parameter value +#define RADIOLIB_SX126X_CAD_PARAM_DET_MIN 10 // 7 0 default detMin CAD parameter + +//RADIOLIB_SX126X_CMD_GET_STATUS +#define RADIOLIB_SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC +#define RADIOLIB_SX126X_STATUS_MODE_STDBY_XOSC 0b00110000 // 6 4 STDBY_XOSC +#define RADIOLIB_SX126X_STATUS_MODE_FS 0b01000000 // 6 4 FS +#define RADIOLIB_SX126X_STATUS_MODE_RX 0b01010000 // 6 4 RX +#define RADIOLIB_SX126X_STATUS_MODE_TX 0b01100000 // 6 4 TX +#define RADIOLIB_SX126X_STATUS_DATA_AVAILABLE 0b00000100 // 3 1 command status: packet received and data can be retrieved +#define RADIOLIB_SX126X_STATUS_CMD_TIMEOUT 0b00000110 // 3 1 SPI command timed out +#define RADIOLIB_SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command +#define RADIOLIB_SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute +#define RADIOLIB_SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done +#define RADIOLIB_SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed + +//RADIOLIB_SX126X_CMD_GET_PACKET_STATUS +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_SYNC_ERR 0b01000000 // 6 6 sync word error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_ADRS_ERR 0b00100000 // 5 5 address error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_CRC_ERR 0b00010000 // 4 4 CRC error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_LENGTH_ERR 0b00001000 // 3 3 length error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_ABORT_ERR 0b00000100 // 2 2 abort error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_RECEIVED 0b00000010 // 2 2 packet received +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_SENT 0b00000001 // 2 2 packet sent + +//RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS +#define RADIOLIB_SX126X_PA_RAMP_ERR 0b100000000 // 8 8 device errors: PA ramping failed +#define RADIOLIB_SX126X_PLL_LOCK_ERR 0b001000000 // 6 6 PLL failed to lock +#define RADIOLIB_SX126X_XOSC_START_ERR 0b000100000 // 5 5 crystal oscillator failed to start +#define RADIOLIB_SX126X_IMG_CALIB_ERR 0b000010000 // 4 4 image calibration failed +#define RADIOLIB_SX126X_ADC_CALIB_ERR 0b000001000 // 3 3 ADC calibration failed +#define RADIOLIB_SX126X_PLL_CALIB_ERR 0b000000100 // 2 2 PLL calibration failed +#define RADIOLIB_SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed +#define RADIOLIB_SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed + +//RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS + RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS +#define RADIOLIB_SX126X_SCAN_INTERVAL_7_68_US 10 // 7 0 RSSI reading interval: 7.68 us +#define RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US 11 // 7 0 8.20 us +#define RADIOLIB_SX126X_SCAN_INTERVAL_8_68_US 12 // 7 0 8.68 us + +// SX126X SPI register variables +//RADIOLIB_SX126X_REG_HOPPING_ENABLE +#define RADIOLIB_SX126X_HOPPING_ENABLED 0b00000001 // 0 0 intra-packet hopping for LR-FHSS: enabled +#define RADIOLIB_SX126X_HOPPING_DISABLED 0b00000000 // 0 0 (disabled) + +//RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB + LSB +#define RADIOLIB_SX126X_SYNC_WORD_PUBLIC 0x34 // actually 0x3444 NOTE: The low nibbles in each byte (0x_4_4) are masked out since apparently, they're reserved. +#define RADIOLIB_SX126X_SYNC_WORD_PRIVATE 0x12 // actually 0x1424 You couldn't make this up if you tried. + +// RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 +#define RADIOLIB_SX126X_TX_BITBANG_1_DISABLED 0b00000000 // 6 4 Tx bitbang: disabled (default) +#define RADIOLIB_SX126X_TX_BITBANG_1_ENABLED 0b00010000 // 6 4 enabled + +// RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 +#define RADIOLIB_SX126X_TX_BITBANG_0_DISABLED 0b00000000 // 3 0 Tx bitbang: disabled (default) +#define RADIOLIB_SX126X_TX_BITBANG_0_ENABLED 0b00001100 // 3 0 enabled + +// RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE +#define RADIOLIB_SX126X_DIO1_OUT_DISABLED 0b00000010 // 1 1 DIO1 output: disabled +#define RADIOLIB_SX126X_DIO1_OUT_ENABLED 0b00000000 // 1 1 enabled +#define RADIOLIB_SX126X_DIO2_OUT_DISABLED 0b00000100 // 2 2 DIO2 output: disabled +#define RADIOLIB_SX126X_DIO2_OUT_ENABLED 0b00000000 // 2 2 enabled +#define RADIOLIB_SX126X_DIO3_OUT_DISABLED 0b00001000 // 3 3 DIO3 output: disabled +#define RADIOLIB_SX126X_DIO3_OUT_ENABLED 0b00000000 // 3 3 enabled + +// RADIOLIB_SX126X_REG_DIOX_IN_ENABLE +#define RADIOLIB_SX126X_DIO1_IN_DISABLED 0b00000000 // 1 1 DIO1 input: disabled +#define RADIOLIB_SX126X_DIO1_IN_ENABLED 0b00000010 // 1 1 enabled +#define RADIOLIB_SX126X_DIO2_IN_DISABLED 0b00000000 // 2 2 DIO2 input: disabled +#define RADIOLIB_SX126X_DIO2_IN_ENABLED 0b00000100 // 2 2 enabled +#define RADIOLIB_SX126X_DIO3_IN_DISABLED 0b00000000 // 3 3 DIO3 input: disabled +#define RADIOLIB_SX126X_DIO3_IN_ENABLED 0b00001000 // 3 3 enabled + +// RADIOLIB_SX126X_REG_RX_GAIN +#define RADIOLIB_SX126X_RX_GAIN_BOOSTED 0x96 // 7 0 Rx gain: boosted +#define RADIOLIB_SX126X_RX_GAIN_POWER_SAVING 0x94 // 7 0 power saving +#define RADIOLIB_SX126X_RX_GAIN_SPECTRAL_SCAN 0xCB // 7 0 spectral scan + +// RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE +#define RADIOLIB_SX126X_PATCH_UPDATE_DISABLED 0b00000000 // 4 4 patch update: disabled +#define RADIOLIB_SX126X_PATCH_UPDATE_ENABLED 0b00010000 // 4 4 enabled + +// RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS +#define RADIOLIB_SX126X_SPECTRAL_SCAN_NONE 0x00 // 7 0 spectral scan status: none +#define RADIOLIB_SX126X_SPECTRAL_SCAN_ONGOING 0x0F // 7 0 ongoing +#define RADIOLIB_SX126X_SPECTRAL_SCAN_ABORTED 0xF0 // 7 0 aborted +#define RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED 0xFF // 7 0 completed + +// RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW +#define RADIOLIB_SX126X_SPECTRAL_SCAN_WINDOW_DEFAULT (0x05 << 2) // 7 0 default RSSI average window + +// RADIOLIB_SX126X_REG_ANA_LNA +#define RADIOLIB_SX126X_LNA_RNG_DISABLED 0b00000001 // 0 0 random number: disabled +#define RADIOLIB_SX126X_LNA_RNG_ENABLED 0b00000000 // 0 0 enabled + +// RADIOLIB_SX126X_REG_ANA_MIXER +#define RADIOLIB_SX126X_MIXER_RNG_DISABLED 0b00000001 // 7 7 random number: disabled +#define RADIOLIB_SX126X_MIXER_RNG_ENABLED 0b00000000 // 7 7 enabled + +// size of the spectral scan result +#define RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE (33) + +/*! + \class SX126x + \brief Base class for %SX126x series. All derived classes for %SX126x (e.g. SX1262 or SX1268) inherit from this base class. + This class should not be instantiated directly from Arduino sketch, only from its derived classes. +*/ +class SX126x: public PhysicalLayer { + public: + // introduce PhysicalLayer overloads + using PhysicalLayer::transmit; + using PhysicalLayer::receive; + using PhysicalLayer::startTransmit; + using PhysicalLayer::readData; + + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX126x(Module* mod); + + /*! + \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. + */ + bool XTAL; + + /*! + \brief Whether to use XOSC (true) or RC (false) oscillator in standby mode. Defaults to false. + */ + bool standbyXOSC; + + // basic methods + + /*! + \brief Initialization method for LoRa modem. + \param cr LoRa coding rate denominator. Allowed values range from 5 to 8. + \param syncWord 1-byte LoRa sync word. + \param preambleLength LoRa preamble length in symbols. Allowed values range from 1 to 65535. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + int16_t begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false); + + /*! + \brief Initialization method for FSK modem. + \param br FSK bit rate in kbps. Allowed values range from 0.6 to 300.0 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz. Allowed values range from 0.0 to 200.0 kHz. + \param rxBw Receiver bandwidth in kHz. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, + 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz. + \param preambleLength FSK preamble length in bits. Allowed values range from 0 to 65535. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + int16_t beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false); + + /*! + \brief Reset method. Will reset the chip to the default state using RST pin. + \param verify Whether correct module startup should be verified. When set to true, RadioLib will attempt to verify the module has started correctly + by repeatedly issuing setStandby command. Enabled by default. + \returns \ref status_codes + */ + int16_t reset(bool verify = true); + + /*! + \brief Blocking binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \param addr Address to send the data to. Will only be added if address filtering was enabled. + \returns \ref status_codes + */ + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Blocking binary receive method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \returns \ref status_codes + */ + int16_t receive(uint8_t* data, size_t len) override; + + /*! + \brief Starts direct mode transmission. + \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. + \returns \ref status_codes + */ + int16_t transmitDirect(uint32_t frf = 0) override; + + /*! + \brief Starts direct mode reception. Only implemented for PhysicalLayer compatibility, as %SX126x series does not support direct mode reception. + Will always return RADIOLIB_ERR_UNKNOWN. + \returns \ref status_codes + */ + int16_t receiveDirect() override; + + /*! + \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. + \returns \ref status_codes + */ + int16_t scanChannel() override; + + /*! + \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. + \param symbolNum Number of symbols for CAD detection. Defaults to the value recommended by AN1200.48. + \param detPeak Peak value for CAD detection. Defaults to the value recommended by AN1200.48. + \param detMin Minimum value for CAD detection. Defaults to the value recommended by AN1200.48. + \returns \ref status_codes + */ + int16_t scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); + + /*! + \brief Sets the module to sleep mode. To wake the device up, call standby(). + \param retainConfig Set to true to retain configuration of the currently active modem ("warm start") + or to false to discard current configuration ("cold start"). Defaults to true. + \returns \ref status_codes + */ + int16_t sleep(bool retainConfig = true); + + /*! + \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). + \returns \ref status_codes + */ + int16_t standby() override; + + /*! + \brief Sets the module to standby mode. + \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX126X_STANDBY_RC (13 MHz RC oscillator) + or RADIOLIB_SX126X_STANDBY_XOSC (32 MHz external crystal oscillator). + \param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module. + \returns \ref status_codes + */ + int16_t standby(uint8_t mode, bool wakeup = true); + + // interrupt methods + + /*! + \brief Sets interrupt service routine to call when DIO1 activates. + \param func ISR to call. + */ + void setDio1Action(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when DIO1 activates. + */ + void clearDio1Action(); + + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + + /*! + \brief Sets interrupt service routine to call when a channel scan is finished. + \param func ISR to call. + */ + void setChannelScanAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a channel scan is finished. + */ + void clearChannelScanAction(); + + /*! + \brief Interrupt-driven binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \param addr Address to send the data to. Will only be added if address filtering was enabled. + \returns \ref status_codes + */ + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Clean up after transmission is done. + \returns \ref status_codes + */ + int16_t finishTransmit() override; + + /*! + \brief Interrupt-driven receive method with default parameters. + Implemented for compatibility with PhysicalLayer. + + \returns \ref status_codes + */ + int16_t startReceive(); + + /*! + \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. + \param timeout Receive mode type and/or raw timeout value, expressed as multiples of 15.625 us. + When set to RADIOLIB_SX126X_RX_TIMEOUT_INF, the timeout will be infinite and the device will remain + in Rx mode until explicitly commanded to stop (Rx continuous mode). + When set to RADIOLIB_SX126X_RX_TIMEOUT_NONE, there will be no timeout and the device will return + to standby when a packet is received (Rx single mode). + For any other value, timeout will be applied and signal will be generated on DIO1 for conditions + defined by irqFlags and irqMask. + + \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. + \param len Only for PhysicalLayer compatibility, not used. + \returns \ref status_codes + */ + int16_t startReceive(uint32_t timeout, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE, size_t len = 0); + + /*! + \brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen. + Note that this function assumes the unit will take 500us + TCXO_delay to change state. + See datasheet section 13.1.7, version 1.2. + \param rxPeriod The duration the receiver will be in Rx mode, in microseconds. + \param sleepPeriod The duration the receiver will not be in Rx mode, in microseconds. + \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. + \returns \ref status_codes + */ + int16_t startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); + + /*! + \brief Calls \ref startReceiveDutyCycle with rxPeriod and sleepPeriod set so the unit shouldn't miss any messages. + \param senderPreambleLength Expected preamble length of the messages to receive. + If set to zero, the currently configured preamble length will be used. Defaults to zero. + + \param minSymbols Parameters will be chosen to ensure that the unit will catch at least this many symbols + of any preamble of the specified length. Defaults to 8. + According to Semtech, receiver requires 8 symbols to reliably latch a preamble. + This makes this method redundant when transmitter preamble length is less than 17 (2*minSymbols + 1). + + \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. + \returns \ref status_codes + */ + int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 8, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); + + /*! + \brief Reads the current IRQ status. + \returns IRQ status bits + */ + uint16_t getIrqStatus(); + + /*! + \brief Reads data received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. + \returns \ref status_codes + */ + int16_t readData(uint8_t* data, size_t len) override; + + /*! + \brief Interrupt-driven channel activity detection method. DIO1 will be activated + when LoRa preamble is detected, or upon timeout. Defaults to CAD parameter values recommended by AN1200.48. + \returns \ref status_codes + */ + int16_t startChannelScan() override; + + /*! + \brief Interrupt-driven channel activity detection method. DIO1 will be activated + when LoRa preamble is detected, or upon timeout. + \param symbolNum Number of symbols for CAD detection. + \param detPeak Peak value for CAD detection. + \param detMin Minimum value for CAD detection. + \returns \ref status_codes + */ + int16_t startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); + + /*! + \brief Read the channel scan result + \returns \ref status_codes + */ + int16_t getChannelScanResult() override; + + // configuration methods + + /*! + \brief Sets LoRa bandwidth. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0, 250.0 and 500.0 kHz. + \param bw LoRa bandwidth to be set in kHz. + \returns \ref status_codes + */ + int16_t setBandwidth(float bw); + + /*! + \brief Sets LoRa spreading factor. Allowed values range from 5 to 12. + \param sf LoRa spreading factor to be set. + \returns \ref status_codes + */ + int16_t setSpreadingFactor(uint8_t sf); + + /*! + \brief Sets LoRa coding rate denominator. Allowed values range from 5 to 8. + \param cr LoRa coding rate denominator to be set. + \returns \ref status_codes + */ + int16_t setCodingRate(uint8_t cr); + + /*! + \brief Sets LoRa sync word. + \param syncWord LoRa sync word to be set. + \param controlBits Undocumented control bits, required for compatibility purposes. + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t syncWord, uint8_t controlBits = 0x44); + + /*! + \brief Sets current protection limit. Can be set in 2.5 mA steps. + \param currentLimit current protection limit to be set in mA. Allowed values range from 0 to 140. + \returns \ref status_codes + */ + int16_t setCurrentLimit(float currentLimit); + + /*! + \brief Reads current protection limit. + \returns Currently configured overcurrent protection limit in mA. + */ + float getCurrentLimit(); + + /*! + \brief Sets preamble length for LoRa or FSK modem. Allowed values range from 1 to 65535. + \param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK). + \returns \ref status_codes + */ + int16_t setPreambleLength(size_t preambleLength) override; + + /*! + \brief Sets FSK frequency deviation. Allowed values range from 0.0 to 200.0 kHz. + \param freqDev FSK frequency deviation to be set in kHz. + \returns \ref status_codes + */ + int16_t setFrequencyDeviation(float freqDev) override; + + /*! + \brief Sets FSK bit rate. Allowed values range from 0.6 to 300.0 kbps. + \param br FSK bit rate to be set in kbps. + \returns \ref status_codes + */ + int16_t setBitRate(float br); + + /*! + \brief Set data. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr) override; + + /*! + \brief Sets FSK receiver bandwidth. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, + 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz. + \param rxBw FSK receiver bandwidth to be set in kHz. + \returns \ref status_codes + */ + int16_t setRxBandwidth(float rxBw); + + /*! + \brief Enables or disables Rx Boosted Gain mode as described in SX126x datasheet + section 9.6 (SX1261/2 v2.1, SX1268 v1.1) + \param rxbgm True for Rx Boosted Gain, false for Rx Power Saving Gain + \param persist True to persist Rx gain setting when waking up from warm-start mode + (e.g. when using Rx duty cycle mode). + \returns \ref status_codes + */ + int16_t setRxBoostedGainMode(bool rxbgm, bool persist = true); + + /*! + \brief Sets time-bandwidth product of Gaussian filter applied for shaping. + Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5, RADIOLIB_SHAPING_0_7 or RADIOLIB_SHAPING_1_0. + Set to RADIOLIB_SHAPING_NONE to disable data shaping. + \param sh Time-bandwidth product of Gaussian filter to be set. + \returns \ref status_codes + */ + int16_t setDataShaping(uint8_t sh) override; + + /*! + \brief Sets FSK sync word in the form of array of up to 8 bytes. + \param syncWord FSK sync word to be set. + \param len FSK sync word length in bytes. + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t* syncWord, size_t len) override; + + /*! + \brief Sets FSK sync word in the form of array of up to 8 bytes. + \param syncWord FSK sync word to be set. + \param bitsLen FSK sync word length in bits. If length is not divisible by 8, + least significant bits of syncWord will be ignored. + \returns \ref status_codes + */ + int16_t setSyncBits(uint8_t *syncWord, uint8_t bitsLen); + + /*! + \brief Sets node address. Calling this method will also enable address filtering for node address only. + \param nodeAddr Node address to be set. + \returns \ref status_codes + */ + int16_t setNodeAddress(uint8_t nodeAddr); + + /*! + \brief Sets broadcast address. Calling this method will also enable address + filtering for node and broadcast address. + \param broadAddr Node address to be set. + \returns \ref status_codes + */ + int16_t setBroadcastAddress(uint8_t broadAddr); + + /*! + \brief Disables address filtering. Calling this method will also erase previously set addresses. + \returns \ref status_codes + */ + int16_t disableAddressFiltering(); + + /*! + \brief Sets CRC configuration. + \param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable CRC. + \param initial Initial CRC value. FSK only. Defaults to 0x1D0F (CCIT CRC). + \param polynomial Polynomial for CRC calculation. FSK only. Defaults to 0x1021 (CCIT CRC). + \param inverted Invert CRC bytes. FSK only. Defaults to true (CCIT CRC). + \returns \ref status_codes + */ + int16_t setCRC(uint8_t len, uint16_t initial = 0x1D0F, uint16_t polynomial = 0x1021, bool inverted = true); + + /*! + \brief Sets FSK whitening parameters. + \param enabled True = Whitening enabled + \param initial Initial value used for the whitening LFSR in FSK mode. + By default set to 0x01FF for compatibility with SX127x and LoRaWAN. + \returns \ref status_codes + */ + int16_t setWhitening(bool enabled, uint16_t initial = 0x01FF); + + /*! + \brief Sets TCXO (Temperature Compensated Crystal Oscillator) configuration. + \param voltage TCXO reference voltage in volts. Allowed values are 1.6, 1.7, 1.8, 2.2. 2.4, 2.7, 3.0 and 3.3 V. + Set to 0 to disable TCXO. + NOTE: After setting this parameter to 0, the module will be reset (since there's no other way to disable TCXO). + + \param delay TCXO timeout in us. Defaults to 5000 us. + \returns \ref status_codes + */ + int16_t setTCXO(float voltage, uint32_t delay = 5000); + + /*! + \brief Set DIO2 to function as RF switch (default in Semtech example designs). + \returns \ref status_codes + */ + int16_t setDio2AsRfSwitch(bool enable = true); + + /*! + \brief Gets effective data rate for the last transmitted packet. The value is calculated only for payload bytes. + \returns Effective data rate in bps. + */ + float getDataRate() const; + + /*! + \brief GetsRSSI (Recorded Signal Strength Indicator). + \param packet Whether to read last packet RSSI, or the current value. + \returns RSSI value in dBm. + */ + float getRSSI(bool packet = true); + + /*! + \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem. + \returns SNR of the last received packet in dB. + */ + float getSNR(); + + /*! + \brief Gets frequency error of the latest received packet. + WARNING: This functionality is based on SX128x implementation and not documented on SX126x. + While it seems to be working, it should be used with caution! + + \returns Frequency error in Hz. + */ + float getFrequencyError(); + + /*! + \brief Query modem for the packet length of received payload. + \param update Update received packet length. Will return cached value when set to false. + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update = true) override; + + /*! + \brief Set modem in fixed packet length mode. Available in FSK mode only. + \param len Packet length. + \returns \ref status_codes + */ + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SX126X_MAX_PACKET_LENGTH); + + /*! + \brief Set modem in variable packet length mode. Available in FSK mode only. + \param len Maximum packet length. + \returns \ref status_codes + */ + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX126X_MAX_PACKET_LENGTH); + + /*! + \brief Get expected time-on-air for a given size of payload + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + uint32_t getTimeOnAir(size_t len) override; + + /*! + \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) + \param timeoutUs Timeout in microseconds to listen for + \returns Timeout value in a unit that is specific for the used module + */ + uint32_t calculateRxTimeout(uint32_t timeoutUs); + + /*! + \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks + \param irqFlags The flags for which IRQs must be triggered + \param irqMask Mask indicating which IRQ triggers a DIO + \returns \ref status_codes + */ + int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask); + + /*! + \brief Check whether the IRQ bit for RxTimeout is set + \returns \ref RxTimeout IRQ is set + */ + bool isRxTimeout(); + + /*! + \brief Set implicit header mode for future reception/transmission. + \param len Payload length in bytes. + \returns \ref status_codes + */ + int16_t implicitHeader(size_t len); + + /*! + \brief Set explicit header mode for future reception/transmission. + \returns \ref status_codes + */ + int16_t explicitHeader(); + + /*! + \brief Set regulator mode to LDO. + \returns \ref status_codes + */ + int16_t setRegulatorLDO(); + + /*! + \brief Set regulator mode to DC-DC. + \returns \ref status_codes + */ + int16_t setRegulatorDCDC(); + + /*! + \brief Sets transmission encoding. Available in FSK mode only. Serves only as alias for PhysicalLayer compatibility. + \param encoding Encoding to be used. Set to 0 for NRZ, and 2 for whitening. + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding) override; + + /*! \copydoc Module::setRfSwitchPins */ + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); + + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + + /*! + \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, + LDRO will always be set to the provided value, regardless of symbol length. + To re-enable automatic LDRO configuration, call SX126x::autoLDRO() + + \param enable Force LDRO to be always enabled (true) or disabled (false). + \returns \ref status_codes + */ + int16_t forceLDRO(bool enable); + + /*! + \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. + After calling this method, LDRO will be enabled automatically when symbol length exceeds 16 ms. + + \returns \ref status_codes + */ + int16_t autoLDRO(); + + /*! + \brief Get one truly random byte from RSSI noise. + \returns TRNG byte. + */ + uint8_t randomByte(); + + /*! + \brief Enable/disable inversion of the I and Q signals + \param enable QI inversion enabled (true) or disabled (false); + \returns \ref status_codes + */ + int16_t invertIQ(bool enable) override; + + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE + /*! + \brief Set interrupt service routine function to call when data bit is received in direct mode. + \param func Pointer to interrupt service routine. + */ + void setDirectAction(void (*func)(void)); + + /*! + \brief Function to read and process data bit in direct reception mode. + \param pin Pin on which to read. + */ + void readBit(uint32_t pin); + #endif + + /*! + \brief Upload binary patch into the SX126x device RAM. + Patch is needed to e.g., enable spectral scan and must be uploaded again on every power cycle. + \param patch Binary patch to upload. + \param len Length of the binary patch in 4-byte words. + \param nonvolatile Set to true when the patch is saved in non-volatile memory of the host processor, + or to false when the patch is in its RAM. + \returns \ref status_codes + */ + int16_t uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile = true); + + /*! + \brief Start spectral scan. Requires binary path to be uploaded. + \param numSamples Number of samples for each scan. Fewer samples = better temporal resolution. + \param window RSSI averaging window size. + \param interval Scan interval length, one of RADIOLIB_SX126X_SCAN_INTERVAL_* macros. + \returns \ref status_codes + */ + int16_t spectralScanStart(uint16_t numSamples, uint8_t window = RADIOLIB_SX126X_SPECTRAL_SCAN_WINDOW_DEFAULT, uint8_t interval = RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US); + + /*! + \brief Abort an ongoing spectral scan. + */ + void spectralScanAbort(); + + /*! + \brief Read the status of spectral scan. + \returns \ref status_codes + */ + int16_t spectralScanGetStatus(); + + /*! + \brief Read the result of spectral scan. + \param results Array to which the results will be saved, must be RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE long. + \returns \ref status_codes + */ + int16_t spectralScanGetResult(uint16_t* results); + + /*! + \brief Set the PA configuration. Allows user to optimize PA for a specific output power + and matching network. Any calls to this method must be done after calling begin/beginFSK and/or setOutputPower. + WARNING: Use at your own risk! Setting invalid values can and will lead to permanent damage! + \param paDutyCycle PA duty cycle raw value. + \param deviceSel Device select, usually RADIOLIB_SX126X_PA_CONFIG_SX1261, + RADIOLIB_SX126X_PA_CONFIG_SX1262 or RADIOLIB_SX126X_PA_CONFIG_SX1268. + \param hpMax hpMax raw value. + \param paLut paLut PA lookup table raw value. + \returns \ref status_codes + */ + int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = RADIOLIB_SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = RADIOLIB_SX126X_PA_CONFIG_PA_LUT); + +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL + protected: +#endif + Module* getMod(); + + // SX126x SPI command implementations + int16_t setFs(); + int16_t setTx(uint32_t timeout = 0); + int16_t setRx(uint32_t timeout); + int16_t setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); + int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); + int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); + int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); + int16_t readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); + int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX126X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX126X_IRQ_NONE); + virtual int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX126X_IRQ_ALL); + int16_t setRfFrequency(uint32_t frf); + int16_t calibrateImage(float freqMin, float freqMax); + uint8_t getPacketType(); + int16_t setTxParams(uint8_t power, uint8_t rampTime = RADIOLIB_SX126X_PA_RAMP_200U); + int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); + int16_t setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev); + int16_t setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ); + int16_t setPacketParamsFSK(uint16_t preambleLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType = RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLen = 0xFF, uint8_t preambleDetectorLen = RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16); + int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00); + int16_t setRegulatorMode(uint8_t mode); + uint8_t getStatus(); + uint32_t getPacketStatus(); + uint16_t getDeviceErrors(); + int16_t clearDeviceErrors(); + +#if !RADIOLIB_GODMODE + protected: +#endif + const char* chipType; + uint8_t bandwidth = 0; + + // Allow subclasses to define different TX modes + uint8_t txMode = Module::MODE_TX; + + int16_t setFrequencyRaw(float freq); + int16_t fixPaClamping(bool enable = true); + + // common low-level SPI interface + static int16_t SPIparseStatus(uint8_t in); + +#if !RADIOLIB_GODMODE + private: +#endif + Module* mod; + + uint8_t spreadingFactor = 0, codingRate = 0, ldrOptimize = 0, crcTypeLoRa = 0, headerType = 0; + uint16_t preambleLengthLoRa = 0; + float bandwidthKhz = 0; + bool ldroAuto = true; + + uint32_t bitRate = 0, frequencyDev = 0; + uint8_t rxBandwidth = 0, pulseShape = 0, crcTypeFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0; + uint16_t preambleLengthFSK = 0; + float rxBandwidthKhz = 0; + + float dataRateMeasured = 0; + + uint32_t tcxoDelay = 0; + + size_t implicitLen = 0; + uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; + + int16_t config(uint8_t modem); + bool findChip(const char* verStr); + int16_t startReceiveCommon(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); + int16_t setPacketMode(uint8_t mode, uint8_t len); + int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); + int16_t directMode(); + int16_t packetMode(); + + // fixes to errata + int16_t fixSensitivity(); + int16_t fixImplicitTimeout(); + int16_t fixInvertedIQ(uint8_t iqConfig); + + + void regdump(); + void effectEvalPre(uint8_t* buff, uint32_t start); + void effectEvalPost(uint8_t* buff, uint32_t start); + void effectEval(); +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX126x/patches/SX126x_patch_scan.h b/lib/lib_rf/RadioLib/src/modules/SX126x/patches/SX126x_patch_scan.h new file mode 100644 index 000000000..bc918749a --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX126x/patches/SX126x_patch_scan.h @@ -0,0 +1,110 @@ +/* +Binary in this file originates from https://github.com/Lora-net/sx1302_hal/tree/master +As such, license of the above repository is reproduced here. + +Copyright (c) 2019, SEMTECH S.A. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Semtech corporation nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_RADIOLIB_SX126X_PATCH_SCAN_H) +#define _RADIOLIB_SX126X_PATCH_SCAN_H + +#include "../../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX126X + +// the following is a binary patch to the SX1262 +// this patch is needed to enable spectral scan functionality +const uint32_t sx126x_patch_scan[] RADIOLIB_NONVOLATILE = { + 0x337fe1, 0x337fdb, 0x337fd5, 0x337fcf, 0x3a7fc8, 0x3f3fff, + 0x0378ff, 0x0379ff, 0x3a7fb7, 0x16a901, 0x16a801, 0x23ffff, + 0x0378ff, 0x0379ff, 0x3a7faf, 0x16a901, 0x16a801, 0x23ffff, + 0x0378ff, 0x0379ff, 0x3a7f34, 0x16a901, 0x16a801, 0x23ffff, + 0x0378ff, 0x0379ff, 0x3a7e80, 0x16a901, 0x16a801, 0x23ffff, + 0x0378ff, 0x0379ff, 0x3a7fc3, 0x16a901, 0x16a801, 0x337fc9, + 0x0378ff, 0x0379ff, 0x3a7fc0, 0x16a901, 0x16a801, 0x337fc9, + 0x0378ff, 0x0379ff, 0x3a7fbd, 0x16a901, 0x16a801, 0x337fc9, + 0x0378ff, 0x0379ff, 0x3a7fba, 0x16a901, 0x16a801, 0x337fc9, + 0x23ffff, 0x0ea1fc, 0x0ea0df, 0x0eafc9, 0x02cf0e, 0x23ffff, + 0x0eacff, 0x0eabff, 0x23ffff, 0x0eacff, 0x0eabff, 0x23ffff, + 0x0eacff, 0x0eabff, 0x23ffff, 0x0eacff, 0x0eabff, 0x23ffff, + 0x0378ff, 0x0379ff, 0x3a7fc8, 0x0eacfd, 0x0eabff, 0x16a901, + 0x16a801, 0x23ffff, 0x0374ff, 0x0375ff, 0x0378ff, 0x0379ff, + 0x16affe, 0x0ea5ff, 0x0ea465, 0x1dbb04, 0x0e1bfd, 0x307fa3, + 0x1caf00, 0x327fa0, 0x0eacf7, 0x0eabff, 0x337f3a, 0x1cad04, + 0x0eacfe, 0x0eabff, 0x0dbfdd, 0x307f97, 0x0dafcc, 0x0defbb, + 0x0dbfdd, 0x347f9b, 0x0eecef, 0x0caffc, 0x04ade8, 0x0cbdcd, + 0x01bde8, 0x04abe8, 0x0ebbbf, 0x01bbe8, 0x04abe8, 0x0ebbdf, + 0x01bbe8, 0x1ca800, 0x0ea9ff, 0x04abe3, 0x0e2b01, 0x01bbe3, + 0x04abee, 0x0e2b01, 0x01bbee, 0x1ca202, 0x1ca301, 0x02f300, + 0x02f201, 0x0ea064, 0x0ea1f7, 0x18ab00, 0x367f58, 0x0ea041, + 0x0ea1f7, 0x18ab00, 0x1c1b03, 0x317f3f, 0x1ea201, 0x1ea300, + 0x0cb23f, 0x327f4a, 0x1cab04, 0x0eaefe, 0x0dbfbb, 0x307f6c, + 0x0dafee, 0x0dbfbb, 0x347f6f, 0x04abee, 0x0cbbeb, 0x01bbee, + 0x0eacff, 0x0eabff, 0x0c1b9f, 0x327f64, 0x0c1c8f, 0x317f5c, + 0x3fffff, 0x0d1fcc, 0x0d5fbb, 0x0c1b9f, 0x327f5d, 0x0c1c8f, + 0x357f63, 0x0ea064, 0x0ea1f7, 0x18ab00, 0x327f7c, 0x1cad04, + 0x0eacfe, 0x0dbfdd, 0x307f51, 0x0dafcc, 0x0dbfdd, 0x347f54, + 0x0d8fcb, 0x04acee, 0x0c2bcb, 0x01bbee, 0x0eacfd, 0x0eabff, + 0x337f3a, 0x1cad04, 0x0eacfe, 0x0dbfdd, 0x307f43, 0x0dafcc, + 0x0dbfdd, 0x347f46, 0x0d8fcb, 0x04acee, 0x0c2bcb, 0x337f6a, + 0x0cb23f, 0x367f75, 0x0dbf22, 0x0dff33, 0x337f75, 0x16af02, + 0x16a901, 0x16a801, 0x16a501, 0x16a401, 0x23ffff, 0x0374ff, + 0x0375ff, 0x0378ff, 0x0379ff, 0x16afe0, 0x0ea5ff, 0x0ea465, + 0x1ca802, 0x0ea9ff, 0x0eafff, 0x02ff00, 0x0eaff7, 0x02ff01, + 0x0eafef, 0x02ff02, 0x0eafe7, 0x02ff03, 0x0eafdf, 0x02ff04, + 0x0eafd7, 0x02ff05, 0x0eafcf, 0x02ff06, 0x0eafc7, 0x02ff07, + 0x0eafbf, 0x02ff08, 0x0eafb7, 0x02ff09, 0x0eafaf, 0x02ff0a, + 0x0eafa7, 0x02ff0b, 0x0eaf9f, 0x02ff0c, 0x0eaf97, 0x02ff0d, + 0x0eaf8f, 0x02ff0e, 0x0eaf87, 0x02ff0f, 0x0eaf7f, 0x02ff10, + 0x0eaf77, 0x02ff11, 0x0eaf6f, 0x02ff12, 0x0eaf67, 0x02ff13, + 0x0eaf5f, 0x02ff14, 0x0eaf57, 0x02ff15, 0x0eaf4f, 0x02ff16, + 0x0eaf47, 0x02ff17, 0x0eaf3f, 0x02ff18, 0x0eaf37, 0x02ff19, + 0x0eaf2f, 0x02ff1a, 0x0eaf27, 0x02ff1b, 0x0eaf1f, 0x02ff1c, + 0x0eaf17, 0x02ff1d, 0x0eaf0f, 0x02ff1e, 0x0eaf07, 0x02ff1f, + 0x04abee, 0x0e2b01, 0x01bbee, 0x0eacff, 0x0eabff, 0x0cafc0, + 0x0ec0ff, 0x0cafb1, 0x0ed1fb, 0x0eafff, 0x02cf00, 0x0d1fcc, + 0x0d5fbb, 0x0e1bff, 0x327edb, 0x0e1c00, 0x347ee6, 0x0ea2ff, + 0x0ea3ff, 0x0ea032, 0x0ea1f8, 0x0eaff0, 0x02cf00, 0x0ea064, + 0x0ea1f7, 0x18ad00, 0x1c1300, 0x327ece, 0x1c1201, 0x317e9b, + 0x0e1dff, 0x367e9b, 0x0ea041, 0x0ea1f7, 0x18ab00, 0x0eebdf, + 0x0cafbc, 0x0eabff, 0x0ccccc, 0x0cdbbb, 0x0cafc0, 0x0ec0ff, + 0x0cafb1, 0x0ed1fb, 0x18ab01, 0x0eacff, 0x18ae02, 0x0eadff, + 0x0ccecc, 0x0cddbb, 0x0d1fcc, 0x0d5fbb, 0x0cafbe, 0x0eadff, + 0x02ce01, 0x02cc02, 0x0d1f22, 0x0d5f33, 0x0ea064, 0x0ea1f7, + 0x18ad00, 0x0eacff, 0x0eabff, 0x0c1b9f, 0x327ea9, 0x0c1c8f, + 0x317ea1, 0x3fffff, 0x0d1fcc, 0x0d5fbb, 0x0c1b9f, 0x327ea2, + 0x0c1c8f, 0x357ea8, 0x1c1300, 0x327e9e, 0x1c1201, 0x317e9b, + 0x0e1dff, 0x327ecb, 0x0e1dff, 0x367e90, 0x0ea032, 0x0ea1f8, + 0x0eaf00, 0x02cf00, 0x0ea1fb, 0x0ea0ff, 0x0eaf00, 0x02cf00, + 0x337e88, 0x0ea032, 0x0ea1f8, 0x0eaf0f, 0x02cf00, 0x0ea1fb, + 0x0ea0ff, 0x0eaf0f, 0x02cf00, 0x0eacfd, 0x0eabff, 0x16af20, + 0x16a901, 0x16a801, 0x16a501, 0x16a401, 0x23ffff, 0x0eacf7, + 0x0eabff, 0x23ffff +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX1272.cpp b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1272.cpp new file mode 100644 index 000000000..808d55d24 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1272.cpp @@ -0,0 +1,567 @@ +#include "SX1272.h" +#include +#if !RADIOLIB_EXCLUDE_SX127X + +SX1272::SX1272(Module* mod) : SX127x(mod) { + +} + +int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { + // execute common part + uint8_t version = RADIOLIB_SX1272_CHIP_VERSION; + int16_t state = SX127x::begin(&version, 1, syncWord, preambleLength); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setGain(gain); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX1272::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { + // execute common part + uint8_t version = RADIOLIB_SX1272_CHIP_VERSION; + int16_t state = SX127x::beginFSK(&version, 1, freqDev, rxBw, preambleLength, enableOOK); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = configFSK(); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + if(enableOOK) { + state = setDataShapingOOK(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } else { + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } + + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + + return(state); +} + +void SX1272::reset() { + Module* mod = this->getMod(); + mod->hal->pinMode(mod->getRst(), mod->hal->GpioModeOutput); + mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelHigh); + mod->hal->delay(1); + mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelLow); + mod->hal->delay(5); +} + +int16_t SX1272::setFrequency(float freq) { + RADIOLIB_CHECK_RANGE(freq, 860.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY); + + // set frequency and if successful, save the new setting + int16_t state = SX127x::setFrequencyRaw(freq); + if(state == RADIOLIB_ERR_NONE) { + SX127x::frequency = freq; + } + return(state); +} + +int16_t SX1272::setBandwidth(float bw) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + uint8_t newBandwidth; + + // check allowed bandwidth values + if(fabs(bw - 125.0) <= 0.001) { + newBandwidth = RADIOLIB_SX1272_BW_125_00_KHZ; + } else if(fabs(bw - 250.0) <= 0.001) { + newBandwidth = RADIOLIB_SX1272_BW_250_00_KHZ; + } else if(fabs(bw - 500.0) <= 0.001) { + newBandwidth = RADIOLIB_SX1272_BW_500_00_KHZ; + } else { + return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } + + // set bandwidth and if successful, save the new setting + int16_t state = SX1272::setBandwidthRaw(newBandwidth); + if(state == RADIOLIB_ERR_NONE) { + SX127x::bandwidth = bw; + + // calculate symbol length and set low data rate optimization, if auto-configuration is enabled + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; + Module* mod = this->getMod(); + if(symbolLength >= 16.0) { + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); + } else { + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); + } + } + } + return(state); +} + +int16_t SX1272::setSpreadingFactor(uint8_t sf) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + uint8_t newSpreadingFactor; + + // check allowed spreading factor values + switch(sf) { + case 6: + newSpreadingFactor = RADIOLIB_SX127X_SF_6; + break; + case 7: + newSpreadingFactor = RADIOLIB_SX127X_SF_7; + break; + case 8: + newSpreadingFactor = RADIOLIB_SX127X_SF_8; + break; + case 9: + newSpreadingFactor = RADIOLIB_SX127X_SF_9; + break; + case 10: + newSpreadingFactor = RADIOLIB_SX127X_SF_10; + break; + case 11: + newSpreadingFactor = RADIOLIB_SX127X_SF_11; + break; + case 12: + newSpreadingFactor = RADIOLIB_SX127X_SF_12; + break; + default: + return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + } + + // set spreading factor and if successful, save the new setting + int16_t state = SX1272::setSpreadingFactorRaw(newSpreadingFactor); + if(state == RADIOLIB_ERR_NONE) { + SX127x::spreadingFactor = sf; + + // calculate symbol length and set low data rate optimization, if auto-configuration is enabled + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; + Module* mod = this->getMod(); + if(symbolLength >= 16.0) { + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); + } else { + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); + } + } + } + return(state); +} + +int16_t SX1272::setCodingRate(uint8_t cr) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + uint8_t newCodingRate; + + // check allowed coding rate values + switch(cr) { + case 5: + newCodingRate = RADIOLIB_SX1272_CR_4_5; + break; + case 6: + newCodingRate = RADIOLIB_SX1272_CR_4_6; + break; + case 7: + newCodingRate = RADIOLIB_SX1272_CR_4_7; + break; + case 8: + newCodingRate = RADIOLIB_SX1272_CR_4_8; + break; + default: + return(RADIOLIB_ERR_INVALID_CODING_RATE); + } + + // set coding rate and if successful, save the new setting + int16_t state = SX1272::setCodingRateRaw(newCodingRate); + if(state == RADIOLIB_ERR_NONE) { + SX127x::codingRate = cr; + } + return(state); +} + +int16_t SX1272::setBitRate(float br) { + return(SX127x::setBitRateCommon(br, RADIOLIB_SX1272_REG_BIT_RATE_FRAC)); +} + +int16_t SX1272::setDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_SX127X_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + RADIOLIB_ASSERT(state); + + // set the coding rate + state = this->setCodingRate(dr.lora.codingRate); + } + + return(state); +} + +int16_t SX1272::checkDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + } + return(RADIOLIB_ERR_NONE); + + } else if(modem == RADIOLIB_SX127X_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); + + } + + return(state); +} + +int16_t SX1272::setOutputPower(int8_t power) { + return(this->setOutputPower(power, false)); +} + +int16_t SX1272::setOutputPower(int8_t power, bool useRfo) { + // check allowed power range + if(useRfo) { + RADIOLIB_CHECK_RANGE(power, -1, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } else { + RADIOLIB_CHECK_RANGE(power, 2, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + + // set mode to standby + int16_t state = SX127x::standby(); + Module* mod = this->getMod(); + + if(useRfo) { + // RFO output + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power + 1), 3, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); + + } else { + if(power <= 17) { + // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 2), 3, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); + + } else { + // power is 18 - 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 5), 3, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0); + + } + + } + + return(state); +} + +int16_t SX1272::setGain(uint8_t gain) { + // check allowed range + if(gain > 6) { + return(RADIOLIB_ERR_INVALID_GAIN); + } + + // set mode to standby + int16_t state = SX127x::standby(); + Module* mod = this->getMod(); + + // get modem + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + // set gain + if(gain == 0) { + // gain set to 0, enable AGC loop + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_ON, 2, 2); + } else { + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_OFF, 2, 2); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); + } + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set gain + if(gain == 0) { + // gain set to 0, enable AGC loop + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); + } else { + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); + } + + } + + return(state); +} + +int16_t SX1272::setDataShaping(uint8_t sh) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check modulation + if(SX127x::ookEnabled) { + return(RADIOLIB_ERR_INVALID_MODULATION); + } + + // set mode to standby + int16_t state = SX127x::standby(); + RADIOLIB_ASSERT(state); + + // set data shaping + Module* mod = this->getMod(); + switch(sh) { + case RADIOLIB_SHAPING_NONE: + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3)); + case RADIOLIB_SHAPING_0_3: + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_3, 4, 3)); + case RADIOLIB_SHAPING_0_5: + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_5, 4, 3)); + case RADIOLIB_SHAPING_1_0: + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_1_0, 4, 3)); + default: + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); + } +} + +int16_t SX1272::setDataShapingOOK(uint8_t sh) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check modulation + if(!SX127x::ookEnabled) { + return(RADIOLIB_ERR_INVALID_MODULATION); + } + + // set mode to standby + int16_t state = SX127x::standby(); + + // set data shaping + Module* mod = this->getMod(); + switch(sh) { + case 0: + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3); + break; + case 1: + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_BR, 4, 3); + break; + case 2: + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_2BR, 4, 3); + break; + default: + state = RADIOLIB_ERR_INVALID_DATA_SHAPING; + break; + } + + return(state); +} + +float SX1272::getRSSI(bool packet, bool skipReceive) { + return(SX127x::getRSSI(packet, skipReceive, -139)); +} + +int16_t SX1272::setCRC(bool enable, bool mode) { + Module* mod = this->getMod(); + if(getActiveModem() == RADIOLIB_SX127X_LORA) { + // set LoRa CRC + SX127x::crcEnabled = enable; + if(enable) { + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_RX_CRC_MODE_ON, 1, 1)); + } else { + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_RX_CRC_MODE_OFF, 1, 1)); + } + } else { + // set FSK CRC + int16_t state = RADIOLIB_ERR_NONE; + if(enable) { + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4); + } else { + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4); + } + RADIOLIB_ASSERT(state); + + // set FSK CRC mode + if(mode) { + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); + } else { + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); + } + } +} + +int16_t SX1272::forceLDRO(bool enable) { + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + this->ldroAuto = false; + Module* mod = this->getMod(); + if(enable) { + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0)); + } else { + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0)); + } +} + +int16_t SX1272::autoLDRO() { + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + this->ldroAuto = true; + return(RADIOLIB_ERR_NONE); +} + +int16_t SX1272::implicitHeader(size_t len) { + return(setHeaderType(RADIOLIB_SX1272_HEADER_IMPL_MODE, len)); +} + +int16_t SX1272::explicitHeader() { + return(setHeaderType(RADIOLIB_SX1272_HEADER_EXPL_MODE)); +} + +int16_t SX1272::setBandwidthRaw(uint8_t newBandwidth) { + // set mode to standby + int16_t state = SX127x::standby(); + + // write register + Module* mod = this->getMod(); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 6); + return(state); +} + +int16_t SX1272::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { + // set mode to standby + int16_t state = SX127x::standby(); + + // write registers + Module* mod = this->getMod(); + if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) { + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_IMPL_MODE | (SX127x::crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); + } else { + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_EXPL_MODE | (SX127x::crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); + } + return(state); +} + +int16_t SX1272::setCodingRateRaw(uint8_t newCodingRate) { + // set mode to standby + int16_t state = SX127x::standby(); + + // write register + Module* mod = this->getMod(); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 5, 3); + return(state); +} + +int16_t SX1272::setHeaderType(uint8_t headerType, size_t len) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set requested packet mode + Module* mod = this->getMod(); + int16_t state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 2, 2); + RADIOLIB_ASSERT(state); + + // set length to register + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); + RADIOLIB_ASSERT(state); + + // update cached value + SX127x::packetLength = len; + + return(state); +} + +int16_t SX1272::configFSK() { + // configure common registers + int16_t state = SX127x::configFSK(); + RADIOLIB_ASSERT(state); + + // set fast PLL hop + Module* mod = this->getMod(); + state = mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7); + return(state); +} + +void SX1272::errataFix(bool rx) { + (void)rx; + + // mitigation of receiver spurious response + // see SX1272/73 Errata, section 2.2 for details + Module* mod = this->getMod(); + mod->SPIsetRegValue(0x31, 0b10000000, 7, 7); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX1272.h b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1272.h new file mode 100644 index 000000000..3ea740acb --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1272.h @@ -0,0 +1,302 @@ +#if !defined(_RADIOLIB_SX1272_H) +#define _RADIOLIB_SX1272_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX127X + +#include "../../Module.h" +#include "SX127x.h" + +// SX1272 specific register map +#define RADIOLIB_SX1272_REG_AGC_REF 0x43 +#define RADIOLIB_SX1272_REG_AGC_THRESH_1 0x44 +#define RADIOLIB_SX1272_REG_AGC_THRESH_2 0x45 +#define RADIOLIB_SX1272_REG_AGC_THRESH_3 0x46 +#define RADIOLIB_SX1272_REG_PLL_HOP 0x4B +#define RADIOLIB_SX1272_REG_TCXO 0x58 +#define RADIOLIB_SX1272_REG_PA_DAC 0x5A +#define RADIOLIB_SX1272_REG_PLL 0x5C +#define RADIOLIB_SX1272_REG_PLL_LOW_PN 0x5E +#define RADIOLIB_SX1272_REG_FORMER_TEMP 0x6C +#define RADIOLIB_SX1272_REG_BIT_RATE_FRAC 0x70 + +// SX1272 LoRa modem settings +// RADIOLIB_SX1272_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB +#define RADIOLIB_SX1272_FRF_MSB 0xE4 // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 +#define RADIOLIB_SX1272_FRF_MID 0xC0 // 7 0 where F(XOSC) = 32 MHz +#define RADIOLIB_SX1272_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers + +// RADIOLIB_SX127X_REG_MODEM_CONFIG_1 +#define RADIOLIB_SX1272_BW_125_00_KHZ 0b00000000 // 7 6 bandwidth: 125 kHz +#define RADIOLIB_SX1272_BW_250_00_KHZ 0b01000000 // 7 6 250 kHz +#define RADIOLIB_SX1272_BW_500_00_KHZ 0b10000000 // 7 6 500 kHz +#define RADIOLIB_SX1272_CR_4_5 0b00001000 // 5 3 error coding rate: 4/5 +#define RADIOLIB_SX1272_CR_4_6 0b00010000 // 5 3 4/6 +#define RADIOLIB_SX1272_CR_4_7 0b00011000 // 5 3 4/7 +#define RADIOLIB_SX1272_CR_4_8 0b00100000 // 5 3 4/8 +#define RADIOLIB_SX1272_HEADER_EXPL_MODE 0b00000000 // 2 2 explicit header mode +#define RADIOLIB_SX1272_HEADER_IMPL_MODE 0b00000100 // 2 2 implicit header mode +#define RADIOLIB_SX1272_RX_CRC_MODE_OFF 0b00000000 // 1 1 CRC disabled +#define RADIOLIB_SX1272_RX_CRC_MODE_ON 0b00000010 // 1 1 CRC enabled +#define RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF 0b00000000 // 0 0 low data rate optimization disabled +#define RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON 0b00000001 // 0 0 low data rate optimization enabled, mandatory for SF 11 and 12 with BW 125 kHz + +// RADIOLIB_SX127X_REG_MODEM_CONFIG_2 +#define RADIOLIB_SX1272_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA +#define RADIOLIB_SX1272_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop + +// RADIOLIB_SX127X_REG_VERSION +#define RADIOLIB_SX1272_CHIP_VERSION 0x22 + +// SX1272 FSK modem settings +// RADIOLIB_SX127X_REG_OP_MODE +#define RADIOLIB_SX1272_NO_SHAPING 0b00000000 // 4 3 data shaping: no shaping (default) +#define RADIOLIB_SX1272_FSK_GAUSSIAN_1_0 0b00001000 // 4 3 FSK modulation Gaussian filter, BT = 1.0 +#define RADIOLIB_SX1272_FSK_GAUSSIAN_0_5 0b00010000 // 4 3 FSK modulation Gaussian filter, BT = 0.5 +#define RADIOLIB_SX1272_FSK_GAUSSIAN_0_3 0b00011000 // 4 3 FSK modulation Gaussian filter, BT = 0.3 +#define RADIOLIB_SX1272_OOK_FILTER_BR 0b00001000 // 4 3 OOK modulation filter, f_cutoff = BR +#define RADIOLIB_SX1272_OOK_FILTER_2BR 0b00010000 // 4 3 OOK modulation filter, f_cutoff = 2*BR + +// RADIOLIB_SX127X_REG_PA_RAMP +#define RADIOLIB_SX1272_LOW_PN_TX_PLL_OFF 0b00010000 // 4 4 use standard PLL in transmit mode (default) +#define RADIOLIB_SX1272_LOW_PN_TX_PLL_ON 0b00000000 // 4 4 use lower phase noise PLL in transmit mode + +// RADIOLIB_SX127X_REG_SYNC_CONFIG +#define RADIOLIB_SX1272_FIFO_FILL_CONDITION_SYNC_ADDRESS 0b00000000 // 3 3 FIFO will be filled when sync address interrupt occurs (default) +#define RADIOLIB_SX1272_FIFO_FILL_CONDITION_ALWAYS 0b00001000 // 3 3 FIFO will be filled as long as this bit is set + +// RADIOLIB_SX1272_REG_AGC_REF +#define RADIOLIB_SX1272_AGC_REFERENCE_LEVEL 0x13 // 5 0 floor reference for AGC thresholds: AgcRef = -174 + 10*log(2*RxBw) + 8 + AGC_REFERENCE_LEVEL [dBm] + +// RADIOLIB_SX1272_REG_AGC_THRESH_1 +#define RADIOLIB_SX1272_AGC_STEP_1 0x0E // 4 0 1st AGC threshold + +// RADIOLIB_SX1272_REG_AGC_THRESH_2 +#define RADIOLIB_SX1272_AGC_STEP_2 0x50 // 7 4 2nd AGC threshold +#define RADIOLIB_SX1272_AGC_STEP_3 0x0B // 4 0 3rd AGC threshold + +// RADIOLIB_SX1272_REG_AGC_THRESH_3 +#define RADIOLIB_SX1272_AGC_STEP_4 0xD0 // 7 4 4th AGC threshold +#define RADIOLIB_SX1272_AGC_STEP_5 0x0B // 4 0 5th AGC threshold + +// RADIOLIB_SX1272_REG_PLL_LOW_PN +#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_75_KHZ 0b00000000 // 7 6 low phase noise PLL bandwidth: 75 kHz +#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_150_KHZ 0b01000000 // 7 6 150 kHz +#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_225_KHZ 0b10000000 // 7 6 225 kHz +#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_300_KHZ 0b11000000 // 7 6 300 kHz (default) + +/*! + \class SX1272 + \brief Derived class for %SX1272 modules. Also used as base class for SX1273. + Both modules use the same basic hardware and only differ in parameter ranges. +*/ +class SX1272: public SX127x { + public: + + // constructor + + /*! + \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. + \param mod Instance of Module that will be used to communicate with the %LoRa chip. + */ + SX1272(Module* mod); + + // basic methods + + /*! + \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz. + \param bw %LoRa link bandwidth in kHz. Allowed values are 125, 250 and 500 kHz. + \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. + \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. + \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. + \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. + Set to 0 to disable OCP (not recommended). + \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. + Allowed values range from 6 to 65535. + \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. + Set to 0 to enable automatic gain control (recommended). + \returns \ref status_codes + */ + int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + + /*! + \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz. + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. + Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. + \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + \param preambleLength Length of FSK preamble in bits. + \param enableOOK Use OOK modulation instead of FSK. + \returns \ref status_codes + */ + int16_t beginFSK(float freq = 915.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + + /*! + \brief Reset method. Will reset the chip to the default state using RST pin. + */ + void reset() override; + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values range from 860.0 MHz to 1020.0 MHz. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets %LoRa link bandwidth. Allowed values are 125, 250 and 500 kHz. Only available in %LoRa mode. + \param bw %LoRa link bandwidth to be set in kHz. + \returns \ref status_codes + */ + int16_t setBandwidth(float bw); + + /*! + \brief Sets %LoRa link spreading factor. Allowed values range from 6 to 12. Only available in %LoRa mode. + \param sf %LoRa link spreading factor to be set. + \returns \ref status_codes + */ + int16_t setSpreadingFactor(uint8_t sf); + + /*! + \brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode. + \param cr %LoRa link coding rate denominator to be set. + \returns \ref status_codes + */ + int16_t setCodingRate(uint8_t cr); + + /*! + \brief Sets FSK bit rate. Allowed values range from 0.5 to 300 kbps. Only available in FSK mode. + \param br Bit rate to be set (in kbps). + \returns \ref status_codes + */ + int16_t setBitRate(float br) override; + + /*! + \brief Set data. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr) override; + + /*! + \brief Sets transmission output power. Allowed values range from -1 to 14 dBm (RFO pin) or +2 to +20 dBm (PA_BOOST pin). + High power +20 dBm operation is also supported, on the PA_BOOST pin. Defaults to PA_BOOST. + \param power Transmission output power in dBm. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power) override; + + /*! + \brief Sets transmission output power. Allowed values range from -1 to 14 dBm (RFO pin) or +2 to +20 dBm (PA_BOOST pin). + \param power Transmission output power in dBm. + \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power, bool useRfo); + + /*! + \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. + Set to 0 to enable automatic gain control (recommended). + \param gain Gain of receiver LNA (low-noise amplifier) to be set. + \returns \ref status_codes + */ + int16_t setGain(uint8_t gain); + + /*! + \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. Only available in FSK mode with FSK modulation. + Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. + \param sh Gaussian shaping bandwidth-time product that will be used for data shaping + \returns \ref status_codes + */ + int16_t setDataShaping(uint8_t sh) override; + + /*! + \brief Sets filter cutoff frequency that will be used for data shaping. + Allowed values are 1 for frequency equal to bit rate and 2 for frequency equal to 2x bit rate. Set to 0 to disable data shaping. + Only available in FSK mode with OOK modulation. + \param sh Cutoff frequency that will be used for data shaping + \returns \ref status_codes + */ + int16_t setDataShapingOOK(uint8_t sh); + + /*! + \brief Gets recorded signal strength indicator. + \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. + \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. + \returns RSSI value in dBm. + */ + float getRSSI(bool packet = true, bool skipReceive = false); + + /*! + \brief Enables/disables CRC check of received packets. + \param enable Enable (true) or disable (false) CRC. + \param mode Set CRC mode to RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT for CCITT, + polynomial X16 + X12 + X5 + 1 (false) or RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM for IBM, + polynomial X16 + X15 + X2 + 1 (true). Only valid in FSK mode. + \returns \ref status_codes + */ + int16_t setCRC(bool enable, bool mode = false); + + /*! + \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to + the provided value, regardless of symbol length. To re-enable automatic LDRO configuration, call SX1278::autoLDRO() + \param enable Force LDRO to be always enabled (true) or disabled (false). + \returns \ref status_codes + */ + int16_t forceLDRO(bool enable); + + /*! + \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. After calling this method, LDRO will be enabled automatically + when symbol length exceeds 16 ms. + \returns \ref status_codes + */ + int16_t autoLDRO(); + + /*! + \brief Set implicit header mode for future reception/transmission. Required for spreading factor 6. + \param len Payload length in bytes. + \returns \ref status_codes + */ + int16_t implicitHeader(size_t len); + + /*! + \brief Set explicit header mode for future reception/transmission. + \returns \ref status_codes + */ + int16_t explicitHeader(); + +#if !RADIOLIB_GODMODE + protected: +#endif + int16_t setBandwidthRaw(uint8_t newBandwidth); + int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor); + int16_t setCodingRateRaw(uint8_t newCodingRate); + int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); + + int16_t configFSK(); + void errataFix(bool rx); + +#if !RADIOLIB_GODMODE + private: +#endif + bool ldroAuto = true; + bool ldroEnabled = false; + +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX1273.cpp b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1273.cpp new file mode 100644 index 000000000..9ef7c1755 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1273.cpp @@ -0,0 +1,118 @@ +#include "SX1273.h" +#if !RADIOLIB_EXCLUDE_SX127X + +SX1273::SX1273(Module* mod) : SX1272(mod) { + +} + +int16_t SX1273::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { + // execute common part + uint8_t version = RADIOLIB_SX1272_CHIP_VERSION; + int16_t state = SX127x::begin(&version, 1, syncWord, preambleLength); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setGain(gain); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX1273::setSpreadingFactor(uint8_t sf) { + uint8_t newSpreadingFactor; + + // check allowed spreading factor values + switch(sf) { + case 6: + newSpreadingFactor = RADIOLIB_SX127X_SF_6; + break; + case 7: + newSpreadingFactor = RADIOLIB_SX127X_SF_7; + break; + case 8: + newSpreadingFactor = RADIOLIB_SX127X_SF_8; + break; + case 9: + newSpreadingFactor = RADIOLIB_SX127X_SF_9; + break; + default: + return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + } + + // set spreading factor and if successful, save the new setting + int16_t state = setSpreadingFactorRaw(newSpreadingFactor); + if(state == RADIOLIB_ERR_NONE) { + SX127x::spreadingFactor = sf; + } + + return(state); +} + +int16_t SX1273::setDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_SX127X_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + } + + return(state); +} + +int16_t SX1273::checkDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + } + return(RADIOLIB_ERR_NONE); + + } else if(modem == RADIOLIB_SX127X_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); + + } + + return(state); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX1273.h b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1273.h new file mode 100644 index 000000000..610bbccf7 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1273.h @@ -0,0 +1,74 @@ +#if !defined(_RADIOLIB_SX1273_H) +#define _RADIOLIB_SX1273_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX127X + +#include "SX1272.h" + +/*! + \class SX1273 + \brief Derived class for %SX1273 modules. Overrides some methods from SX1272 due to different parameter ranges. +*/ +class SX1273: public SX1272 { + public: + + // constructor + + /*! + \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. + \param mod Instance of Module that will be used to communicate with the %LoRa chip. + */ + SX1273(Module* mod); + + // basic methods + + /*! + \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz. + \param bw %LoRa link bandwidth in kHz. Allowed values are 125, 250 and 500 kHz. + \param sf %LoRa link spreading factor. Allowed values range from 6 to 9. + \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. + \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. + Allowed values range from 6 to 65535. + \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. + Set to 0 to enable automatic gain control (recommended). + \returns \ref status_codes + */ + int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + + // configuration methods + + /*! + \brief Sets %LoRa link spreading factor. Allowed values range from 6 to 9. Only available in %LoRa mode. + \param sf %LoRa link spreading factor to be set. + \returns \ref status_codes + */ + int16_t setSpreadingFactor(uint8_t sf); + + /*! + \brief Set data. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr) override; + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX1276.cpp b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1276.cpp new file mode 100644 index 000000000..d45826fcc --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1276.cpp @@ -0,0 +1,82 @@ +#include "SX1276.h" +#if !RADIOLIB_EXCLUDE_SX127X + +SX1276::SX1276(Module* mod) : SX1278(mod) { + +} + +int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { + // execute common part + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setGain(gain); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { + // execute common part + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = configFSK(); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + if(enableOOK) { + state = setDataShapingOOK(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } else { + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } + + return(state); +} + +int16_t SX1276::setFrequency(float freq) { + RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY); + + // set frequency and if successful, save the new setting + int16_t state = SX127x::setFrequencyRaw(freq); + if(state == RADIOLIB_ERR_NONE) { + SX127x::frequency = freq; + } + return(state); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX1276.h b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1276.h new file mode 100644 index 000000000..c15f98128 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1276.h @@ -0,0 +1,86 @@ +#if !defined(_RADIOLIB_SX1276_H) +#define _RADIOLIB_SX1276_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX127X + +#include "SX1278.h" + +/*! + \class SX1276 + \brief Derived class for %SX1276 modules. Overrides some methods from SX1278 due to different parameter ranges. +*/ +class SX1276: public SX1278 { + public: + + // constructor + + /*! + \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. + \param mod Instance of Module that will be used to communicate with the %LoRa chip. + */ + SX1276(Module* mod); + + // basic methods + + /*! + \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz. + \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. + \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. + \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. + \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. + Allowed values range from 6 to 65535. + \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. + Set to 0 to enable automatic gain control (recommended). + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + + /*! + \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz. + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. + Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. + \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + \param preambleLength Length of FSK preamble in bits. + \param enableOOK Use OOK modulation instead of FSK. + \returns \ref status_codes + */ + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 1020.0 MHz. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +/*! + \class RFM95 + \brief Only exists as alias for SX1276, since there seems to be no difference between %RFM95 and %SX1276 modules. +*/ +RADIOLIB_TYPE_ALIAS(SX1276, RFM95) + +/*! + \class RFM96 + \brief Only exists as alias for SX1276, since there seems to be no difference between %RFM96 and %SX1276 modules. +*/ +RADIOLIB_TYPE_ALIAS(SX1276, RFM96) + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX1277.cpp b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1277.cpp new file mode 100644 index 000000000..fea394cd3 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1277.cpp @@ -0,0 +1,160 @@ +#include "SX1277.h" +#if !RADIOLIB_EXCLUDE_SX127X + +SX1277::SX1277(Module* mod) : SX1278(mod) { + +} + +int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { + // execute common part + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setGain(gain); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { + // execute common part + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = configFSK(); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + if(enableOOK) { + state = setDataShapingOOK(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } else { + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } + + return(state); +} + +int16_t SX1277::setFrequency(float freq) { + RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY); + + // set frequency and if successful, save the new setting + int16_t state = SX127x::setFrequencyRaw(freq); + if(state == RADIOLIB_ERR_NONE) { + SX127x::frequency = freq; + } + return(state); +} + +int16_t SX1277::setSpreadingFactor(uint8_t sf) { + uint8_t newSpreadingFactor; + + // check allowed spreading factor values + switch(sf) { + case 6: + newSpreadingFactor = RADIOLIB_SX127X_SF_6; + break; + case 7: + newSpreadingFactor = RADIOLIB_SX127X_SF_7; + break; + case 8: + newSpreadingFactor = RADIOLIB_SX127X_SF_8; + break; + case 9: + newSpreadingFactor = RADIOLIB_SX127X_SF_9; + break; + default: + return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + } + + // set spreading factor and if successful, save the new setting + int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor); + if(state == RADIOLIB_ERR_NONE) { + SX127x::spreadingFactor = sf; + } + + return(state); +} + +int16_t SX1277::setDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_SX127X_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + } + + return(state); +} + +int16_t SX1277::checkDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + } + return(RADIOLIB_ERR_NONE); + + } else if(modem == RADIOLIB_SX127X_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); + + } + + return(state); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX1277.h b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1277.h new file mode 100644 index 000000000..1d334cdca --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1277.h @@ -0,0 +1,101 @@ +#if !defined(_RADIOLIB_SX1277_H) +#define _RADIOLIB_SX1277_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX127X + +#include "SX1278.h" + +/*! + \class SX1277 + \brief Derived class for %SX1277 modules. Overrides some methods from SX1278 due to different parameter ranges. +*/ +class SX1277: public SX1278 { + public: + + // constructor + + /*! + \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. + \param mod Instance of Module that will be used to communicate with the %LoRa chip. + */ + SX1277(Module* mod); + + // basic methods + + /*! + \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz. + \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. + \param sf %LoRa link spreading factor. Allowed values range from 6 to 9. + \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. + \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. + Allowed values range from 6 to 65535. + \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. + Set to 0 to enable automatic gain control (recommended). + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + + /*! + \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. + Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. + \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + \param preambleLength Length of FSK preamble in bits. + \param enableOOK Use OOK modulation instead of FSK. + \returns \ref status_codes + */ + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 1020.0 MHz. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets %LoRa link spreading factor. Allowed values range from 6 to 9. Only available in %LoRa mode. + \param sf %LoRa link spreading factor to be set. + \returns \ref status_codes + */ + int16_t setSpreadingFactor(uint8_t sf); + + /*! + \brief Set data. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr) override; + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +/*! + \class RFM97 + \brief Only exists as alias for SX1277, since there seems to be no difference between %RFM97 and %SX1277 modules. +*/ +RADIOLIB_TYPE_ALIAS(SX1277, RFM97) + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX1278.cpp b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1278.cpp new file mode 100644 index 000000000..cefb352cb --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1278.cpp @@ -0,0 +1,682 @@ +#include "SX1278.h" +#include +#if !RADIOLIB_EXCLUDE_SX127X + +SX1278::SX1278(Module* mod) : SX127x(mod) { + +} + +int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { + // execute common part + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setGain(gain); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { + // execute common part + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = configFSK(); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + if(enableOOK) { + state = setDataShapingOOK(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } else { + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } + + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + + return(state); +} + +void SX1278::reset() { + Module* mod = this->getMod(); + mod->hal->pinMode(mod->getRst(), mod->hal->GpioModeOutput); + mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelLow); + mod->hal->delay(1); + mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelHigh); + mod->hal->delay(5); +} + +int16_t SX1278::setFrequency(float freq) { + RADIOLIB_CHECK_RANGE(freq, 137.0, 525.0, RADIOLIB_ERR_INVALID_FREQUENCY); + + // set frequency and if successful, save the new setting + int16_t state = SX127x::setFrequencyRaw(freq); + if(state == RADIOLIB_ERR_NONE) { + SX127x::frequency = freq; + } + return(state); +} + +int16_t SX1278::setBandwidth(float bw) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + uint8_t newBandwidth; + + // check allowed bandwidth values + if(fabs(bw - 7.8) <= 0.001) { + newBandwidth = RADIOLIB_SX1278_BW_7_80_KHZ; + } else if(fabs(bw - 10.4) <= 0.001) { + newBandwidth = RADIOLIB_SX1278_BW_10_40_KHZ; + } else if(fabs(bw - 15.6) <= 0.001) { + newBandwidth = RADIOLIB_SX1278_BW_15_60_KHZ; + } else if(fabs(bw - 20.8) <= 0.001) { + newBandwidth = RADIOLIB_SX1278_BW_20_80_KHZ; + } else if(fabs(bw - 31.25) <= 0.001) { + newBandwidth = RADIOLIB_SX1278_BW_31_25_KHZ; + } else if(fabs(bw - 41.7) <= 0.001) { + newBandwidth = RADIOLIB_SX1278_BW_41_70_KHZ; + } else if(fabs(bw - 62.5) <= 0.001) { + newBandwidth = RADIOLIB_SX1278_BW_62_50_KHZ; + } else if(fabs(bw - 125.0) <= 0.001) { + newBandwidth = RADIOLIB_SX1278_BW_125_00_KHZ; + } else if(fabs(bw - 250.0) <= 0.001) { + newBandwidth = RADIOLIB_SX1278_BW_250_00_KHZ; + } else if(fabs(bw - 500.0) <= 0.001) { + newBandwidth = RADIOLIB_SX1278_BW_500_00_KHZ; + } else { + return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } + + // set bandwidth and if successful, save the new setting + int16_t state = SX1278::setBandwidthRaw(newBandwidth); + if(state == RADIOLIB_ERR_NONE) { + SX127x::bandwidth = bw; + + // calculate symbol length and set low data rate optimization, if auto-configuration is enabled + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; + Module* mod = this->getMod(); + if(symbolLength >= 16.0) { + state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); + } else { + state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); + } + } + } + return(state); +} + +int16_t SX1278::setSpreadingFactor(uint8_t sf) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + uint8_t newSpreadingFactor; + + // check allowed spreading factor values + switch(sf) { + case 6: + newSpreadingFactor = RADIOLIB_SX127X_SF_6; + break; + case 7: + newSpreadingFactor = RADIOLIB_SX127X_SF_7; + break; + case 8: + newSpreadingFactor = RADIOLIB_SX127X_SF_8; + break; + case 9: + newSpreadingFactor = RADIOLIB_SX127X_SF_9; + break; + case 10: + newSpreadingFactor = RADIOLIB_SX127X_SF_10; + break; + case 11: + newSpreadingFactor = RADIOLIB_SX127X_SF_11; + break; + case 12: + newSpreadingFactor = RADIOLIB_SX127X_SF_12; + break; + default: + return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + } + + // set spreading factor and if successful, save the new setting + int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor); + if(state == RADIOLIB_ERR_NONE) { + SX127x::spreadingFactor = sf; + + // calculate symbol length and set low data rate optimization, if auto-configuration is enabled + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; + Module* mod = this->getMod(); + if(symbolLength >= 16.0) { + state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); + } else { + state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); + } + } + } + return(state); +} + +int16_t SX1278::setCodingRate(uint8_t cr) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + uint8_t newCodingRate; + + // check allowed coding rate values + switch(cr) { + case 5: + newCodingRate = RADIOLIB_SX1278_CR_4_5; + break; + case 6: + newCodingRate = RADIOLIB_SX1278_CR_4_6; + break; + case 7: + newCodingRate = RADIOLIB_SX1278_CR_4_7; + break; + case 8: + newCodingRate = RADIOLIB_SX1278_CR_4_8; + break; + default: + return(RADIOLIB_ERR_INVALID_CODING_RATE); + } + + // set coding rate and if successful, save the new setting + int16_t state = SX1278::setCodingRateRaw(newCodingRate); + if(state == RADIOLIB_ERR_NONE) { + SX127x::codingRate = cr; + } + return(state); +} + +int16_t SX1278::setBitRate(float br) { + return(SX127x::setBitRateCommon(br, RADIOLIB_SX1278_REG_BIT_RATE_FRAC)); +} + +int16_t SX1278::setDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_SX127X_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + RADIOLIB_ASSERT(state); + + // set the coding rate + state = this->setCodingRate(dr.lora.codingRate); + } + + return(state); +} + +int16_t SX1278::checkDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + } + return(RADIOLIB_ERR_NONE); + + } else if(modem == RADIOLIB_SX127X_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); + + } + + return(state); +} + +int16_t SX1278::setOutputPower(int8_t power) { + return(this->setOutputPower(power, false)); +} + +int16_t SX1278::setOutputPower(int8_t power, bool useRfo) { + // check allowed power range + if(useRfo) { + // RFO output + RADIOLIB_CHECK_RANGE(power, -3, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } else { + // PA_BOOST output, check high-power operation + if(power != 20) { + RADIOLIB_CHECK_RANGE(power, 2, 17, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + } + + // set mode to standby + int16_t state = SX127x::standby(); + Module* mod = this->getMod(); + + if(useRfo) { + uint8_t paCfg = 0; + if(power < 0) { + // low power mode RFO output + paCfg = RADIOLIB_SX1278_LOW_POWER | (power + 3); + } else { + // high power mode RFO output + paCfg = RADIOLIB_SX1278_MAX_POWER | power; + } + + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, paCfg, 6, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); + + } else { + if(power != 20) { + // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | (power - 2), 6, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); + + } else { + // power is 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | 0x0F, 6, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0); + + } + } + + return(state); +} + +int16_t SX1278::setGain(uint8_t gain) { + // check allowed range + if(gain > 6) { + return(RADIOLIB_ERR_INVALID_GAIN); + } + + // set mode to standby + int16_t state = SX127x::standby(); + Module* mod = this->getMod(); + + // get modem + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA){ + // set gain + if(gain == 0) { + // gain set to 0, enable AGC loop + state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_ON, 2, 2); + } else { + state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_OFF, 2, 2); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); + } + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set gain + if(gain == 0) { + // gain set to 0, enable AGC loop + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); + } else { + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX1278_AGC_AUTO_OFF, 3, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); + } + + } + + return(state); +} + +int16_t SX1278::setDataShaping(uint8_t sh) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check modulation + if(SX127x::ookEnabled) { + // we're in OOK mode, the only thing we can do is disable + if(sh == RADIOLIB_SHAPING_NONE) { + return(setDataShapingOOK(0)); + } + + return(RADIOLIB_ERR_INVALID_MODULATION); + } + + // set mode to standby + int16_t state = SX127x::standby(); + RADIOLIB_ASSERT(state); + + // set data shaping + Module* mod = this->getMod(); + switch(sh) { + case RADIOLIB_SHAPING_NONE: + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5)); + case RADIOLIB_SHAPING_0_3: + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_3, 6, 5)); + case RADIOLIB_SHAPING_0_5: + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_5, 6, 5)); + case RADIOLIB_SHAPING_1_0: + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_1_0, 6, 5)); + default: + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); + } +} + +int16_t SX1278::setDataShapingOOK(uint8_t sh) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check modulation + if(!SX127x::ookEnabled) { + return(RADIOLIB_ERR_INVALID_MODULATION); + } + + // set mode to standby + int16_t state = SX127x::standby(); + + // set data shaping + Module* mod = this->getMod(); + switch(sh) { + case 0: + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5); + break; + case 1: + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_BR, 6, 5); + break; + case 2: + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_2BR, 6, 5); + break; + default: + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); + } + + return(state); +} + +float SX1278::getRSSI(bool packet, bool skipReceive) { + int16_t offset = -157; + if(frequency < 868.0) { + offset = -164; + } + return(SX127x::getRSSI(packet, skipReceive, offset)); +} + +int16_t SX1278::setCRC(bool enable, bool mode) { + Module* mod = this->getMod(); + if(getActiveModem() == RADIOLIB_SX127X_LORA) { + // set LoRa CRC + SX127x::crcEnabled = enable; + if(enable) { + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_ON, 2, 2)); + } else { + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_OFF, 2, 2)); + } + } else { + // set FSK CRC + int16_t state = RADIOLIB_ERR_NONE; + if(enable) { + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4); + } else { + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4); + } + RADIOLIB_ASSERT(state); + + // set FSK CRC mode + if(mode) { + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); + } else { + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); + } + } +} + +int16_t SX1278::forceLDRO(bool enable) { + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + Module* mod = this->getMod(); + this->ldroAuto = false; + if(enable) { + return(mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3)); + } else { + return(mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3)); + } +} + +int16_t SX1278::autoLDRO() { + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + this->ldroAuto = true; + return(RADIOLIB_ERR_NONE); +} + +int16_t SX1278::implicitHeader(size_t len) { + return(setHeaderType(RADIOLIB_SX1278_HEADER_IMPL_MODE, len)); +} + +int16_t SX1278::explicitHeader() { + return(setHeaderType(RADIOLIB_SX1278_HEADER_EXPL_MODE)); +} + +int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) { + // set mode to standby + int16_t state = SX127x::standby(); + + // write register + Module* mod = this->getMod(); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 4); + return(state); +} + +int16_t SX1278::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { + // set mode to standby + int16_t state = SX127x::standby(); + + // write registers + Module* mod = this->getMod(); + if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) { + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); + } else { + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_EXPL_MODE, 0, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); + } + return(state); +} + +int16_t SX1278::setCodingRateRaw(uint8_t newCodingRate) { + // set mode to standby + int16_t state = SX127x::standby(); + + // write register + Module* mod = this->getMod(); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 3, 1); + return(state); +} + +int16_t SX1278::setHeaderType(uint8_t headerType, size_t len) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set requested packet mode + Module* mod = this->getMod(); + int16_t state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 0, 0); + RADIOLIB_ASSERT(state); + + // set length to register + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); + RADIOLIB_ASSERT(state); + + // update cached value + SX127x::packetLength = len; + + return(state); +} + +int16_t SX1278::configFSK() { + // configure common registers + int16_t state = SX127x::configFSK(); + RADIOLIB_ASSERT(state); + + // set fast PLL hop + Module* mod = this->getMod(); + state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7); + return(state); +} + +void SX1278::errataFix(bool rx) { + // only apply in LoRa mode + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return; + } + + // sensitivity optimization for 500kHz bandwidth + // see SX1276/77/78 Errata, section 2.1 for details + Module* mod = this->getMod(); + if(fabs(SX127x::bandwidth - 500.0) <= 0.001) { + if((frequency >= 862.0) && (frequency <= 1020.0)) { + mod->SPIwriteRegister(0x36, 0x02); + mod->SPIwriteRegister(0x3a, 0x64); + } else if((frequency >= 410.0) && (frequency <= 525.0)) { + mod->SPIwriteRegister(0x36, 0x02); + mod->SPIwriteRegister(0x3a, 0x7F); + } + } + + // mitigation of receiver spurious response + // see SX1276/77/78 Errata, section 2.3 for details + + // figure out what we need to set + uint8_t fixedRegs[3] = { 0x00, 0x00, 0x00 }; + float rxFreq = frequency; + if(fabs(SX127x::bandwidth - 7.8) <= 0.001) { + fixedRegs[0] = 0b0000000; + fixedRegs[1] = 0x48; + fixedRegs[2] = 0x00; + rxFreq += 0.00781; + } else if(fabs(SX127x::bandwidth - 10.4) <= 0.001) { + fixedRegs[0] = 0b0000000; + fixedRegs[1] = 0x44; + fixedRegs[2] = 0x00; + rxFreq += 0.01042; + } else if(fabs(SX127x::bandwidth - 15.6) <= 0.001) { + fixedRegs[0] = 0b0000000; + fixedRegs[1] = 0x44; + fixedRegs[2] = 0x00; + rxFreq += 0.01562; + } else if(fabs(SX127x::bandwidth - 20.8) <= 0.001) { + fixedRegs[0] = 0b0000000; + fixedRegs[1] = 0x44; + fixedRegs[2] = 0x00; + rxFreq += 0.02083; + } else if(fabs(SX127x::bandwidth - 31.25) <= 0.001) { + fixedRegs[0] = 0b0000000; + fixedRegs[1] = 0x44; + fixedRegs[2] = 0x00; + rxFreq += 0.03125; + } else if(fabs(SX127x::bandwidth - 41.7) <= 0.001) { + fixedRegs[0] = 0b0000000; + fixedRegs[1] = 0x44; + fixedRegs[2] = 0x00; + rxFreq += 0.04167; + } else if(fabs(SX127x::bandwidth - 62.5) <= 0.001) { + fixedRegs[0] = 0b0000000; + fixedRegs[1] = 0x40; + fixedRegs[2] = 0x00; + } else if(fabs(SX127x::bandwidth - 125.0) <= 0.001) { + fixedRegs[0] = 0b0000000; + fixedRegs[1] = 0x40; + fixedRegs[2] = 0x00; + } else if(fabs(SX127x::bandwidth - 250.0) <= 0.001) { + fixedRegs[0] = 0b0000000; + fixedRegs[1] = 0x40; + fixedRegs[2] = 0x00; + } else if(fabs(SX127x::bandwidth - 500.0) <= 0.001) { + fixedRegs[0] = 0b1000000; + fixedRegs[1] = mod->SPIreadRegister(0x2F); + fixedRegs[2] = mod->SPIreadRegister(0x30); + } else { + return; + } + + // first, go to standby + standby(); + + // shift the freqency up when receiving, or restore the original when transmitting + if(rx) { + SX127x::setFrequencyRaw(rxFreq); + } else { + SX127x::setFrequencyRaw(frequency); + } + + // finally, apply errata fixes + mod->SPIsetRegValue(0x31, fixedRegs[0], 7, 7); + mod->SPIsetRegValue(0x2F, fixedRegs[1]); + mod->SPIsetRegValue(0x30, fixedRegs[2]); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX1278.h b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1278.h new file mode 100644 index 000000000..979edb75a --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1278.h @@ -0,0 +1,319 @@ +#if !defined(_RADIOLIB_SX1278_H) +#define _RADIOLIB_SX1278_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX127X + +#include "../../Module.h" +#include "SX127x.h" + +// SX1278 specific register map +#define RADIOLIB_SX1278_REG_MODEM_CONFIG_3 0x26 +#define RADIOLIB_SX1278_REG_PLL_HOP 0x44 +#define RADIOLIB_SX1278_REG_TCXO 0x4B +#define RADIOLIB_SX1278_REG_PA_DAC 0x4D +#define RADIOLIB_SX1278_REG_FORMER_TEMP 0x5B +#define RADIOLIB_SX1278_REG_BIT_RATE_FRAC 0x5D +#define RADIOLIB_SX1278_REG_AGC_REF 0x61 +#define RADIOLIB_SX1278_REG_AGC_THRESH_1 0x62 +#define RADIOLIB_SX1278_REG_AGC_THRESH_2 0x63 +#define RADIOLIB_SX1278_REG_AGC_THRESH_3 0x64 +#define RADIOLIB_SX1278_REG_PLL 0x70 + +// SX1278 LoRa modem settings +// RADIOLIB_SX1278_REG_OP_MODE MSB LSB DESCRIPTION +#define RADIOLIB_SX1278_HIGH_FREQ 0b00000000 // 3 3 access HF test registers +#define RADIOLIB_SX1278_LOW_FREQ 0b00001000 // 3 3 access LF test registers + +// RADIOLIB_SX1278_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB +#define RADIOLIB_SX1278_FRF_MSB 0x6C // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 +#define RADIOLIB_SX1278_FRF_MID 0x80 // 7 0 where F(XOSC) = 32 MHz +#define RADIOLIB_SX1278_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers + +// RADIOLIB_SX1278_REG_PA_CONFIG +#define RADIOLIB_SX1278_MAX_POWER 0b01110000 // 6 4 max power: P_max = 10.8 + 0.6*MAX_POWER [dBm]; P_max(MAX_POWER = 0b111) = 15 dBm +#define RADIOLIB_SX1278_LOW_POWER 0b00100000 // 6 4 + +// RADIOLIB_SX1278_REG_LNA +#define RADIOLIB_SX1278_LNA_BOOST_LF_OFF 0b00000000 // 4 3 default LNA current + +// SX127X_REG_MODEM_CONFIG_1 +#define RADIOLIB_SX1278_BW_7_80_KHZ 0b00000000 // 7 4 bandwidth: 7.80 kHz +#define RADIOLIB_SX1278_BW_10_40_KHZ 0b00010000 // 7 4 10.40 kHz +#define RADIOLIB_SX1278_BW_15_60_KHZ 0b00100000 // 7 4 15.60 kHz +#define RADIOLIB_SX1278_BW_20_80_KHZ 0b00110000 // 7 4 20.80 kHz +#define RADIOLIB_SX1278_BW_31_25_KHZ 0b01000000 // 7 4 31.25 kHz +#define RADIOLIB_SX1278_BW_41_70_KHZ 0b01010000 // 7 4 41.70 kHz +#define RADIOLIB_SX1278_BW_62_50_KHZ 0b01100000 // 7 4 62.50 kHz +#define RADIOLIB_SX1278_BW_125_00_KHZ 0b01110000 // 7 4 125.00 kHz +#define RADIOLIB_SX1278_BW_250_00_KHZ 0b10000000 // 7 4 250.00 kHz +#define RADIOLIB_SX1278_BW_500_00_KHZ 0b10010000 // 7 4 500.00 kHz +#define RADIOLIB_SX1278_CR_4_5 0b00000010 // 3 1 error coding rate: 4/5 +#define RADIOLIB_SX1278_CR_4_6 0b00000100 // 3 1 4/6 +#define RADIOLIB_SX1278_CR_4_7 0b00000110 // 3 1 4/7 +#define RADIOLIB_SX1278_CR_4_8 0b00001000 // 3 1 4/8 +#define RADIOLIB_SX1278_HEADER_EXPL_MODE 0b00000000 // 0 0 explicit header mode +#define RADIOLIB_SX1278_HEADER_IMPL_MODE 0b00000001 // 0 0 implicit header mode + +// SX127X_REG_MODEM_CONFIG_2 +#define RADIOLIB_SX1278_RX_CRC_MODE_OFF 0b00000000 // 2 2 CRC disabled +#define RADIOLIB_SX1278_RX_CRC_MODE_ON 0b00000100 // 2 2 CRC enabled + +// RADIOLIB_SX1278_REG_MODEM_CONFIG_3 +#define RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF 0b00000000 // 3 3 low data rate optimization disabled +#define RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON 0b00001000 // 3 3 low data rate optimization enabled +#define RADIOLIB_SX1278_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA +#define RADIOLIB_SX1278_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop + +// SX127X_REG_VERSION +#define RADIOLIB_SX1278_CHIP_VERSION 0x12 // this is the "official" version listed in datasheet +#define RADIOLIB_SX1278_CHIP_VERSION_ALT 0x13 // appears sometimes +#define RADIOLIB_SX1278_CHIP_VERSION_RFM9X 0x11 // this value is used for the RFM9x + +// SX1278 FSK modem settings +// SX127X_REG_PA_RAMP +#define RADIOLIB_SX1278_NO_SHAPING 0b00000000 // 6 5 data shaping: no shaping (default) +#define RADIOLIB_SX1278_FSK_GAUSSIAN_1_0 0b00100000 // 6 5 FSK modulation Gaussian filter, BT = 1.0 +#define RADIOLIB_SX1278_FSK_GAUSSIAN_0_5 0b01000000 // 6 5 FSK modulation Gaussian filter, BT = 0.5 +#define RADIOLIB_SX1278_FSK_GAUSSIAN_0_3 0b01100000 // 6 5 FSK modulation Gaussian filter, BT = 0.3 +#define RADIOLIB_SX1278_OOK_FILTER_BR 0b00100000 // 6 5 OOK modulation filter, f_cutoff = BR +#define RADIOLIB_SX1278_OOK_FILTER_2BR 0b01000000 // 6 5 OOK modulation filter, f_cutoff = 2*BR + +// RADIOLIB_SX1278_REG_AGC_REF +#define RADIOLIB_SX1278_AGC_REFERENCE_LEVEL_LF 0x19 // 5 0 floor reference for AGC thresholds: AgcRef = -174 + 10*log(2*RxBw) + 8 + AGC_REFERENCE_LEVEL [dBm]: below 525 MHz +#define RADIOLIB_SX1278_AGC_REFERENCE_LEVEL_HF 0x1C // 5 0 above 779 MHz + +// RADIOLIB_SX1278_REG_AGC_THRESH_1 +#define RADIOLIB_SX1278_AGC_STEP_1_LF 0x0C // 4 0 1st AGC threshold: below 525 MHz +#define RADIOLIB_SX1278_AGC_STEP_1_HF 0x0E // 4 0 above 779 MHz + +// RADIOLIB_SX1278_REG_AGC_THRESH_2 +#define RADIOLIB_SX1278_AGC_STEP_2_LF 0x40 // 7 4 2nd AGC threshold: below 525 MHz +#define RADIOLIB_SX1278_AGC_STEP_2_HF 0x50 // 7 4 above 779 MHz +#define RADIOLIB_SX1278_AGC_STEP_3 0x0B // 3 0 3rd AGC threshold + +// RADIOLIB_SX1278_REG_AGC_THRESH_3 +#define RADIOLIB_SX1278_AGC_STEP_4 0xC0 // 7 4 4th AGC threshold +#define RADIOLIB_SX1278_AGC_STEP_5 0x0C // 4 0 5th AGC threshold + +/*! + \class SX1278 + \brief Derived class for %SX1278 modules. Also used as base class for SX1276, SX1277, SX1279, RFM95 and RFM96. + All of these modules use the same basic hardware and only differ in parameter ranges (and names). +*/ +class SX1278: public SX127x { + public: + + // constructor + + /*! + \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. + \param mod Instance of Module that will be used to communicate with the %LoRa chip. + */ + SX1278(Module* mod); + + // basic methods + + /*! + \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. + \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. + \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. + \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. + \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. + Allowed values range from 6 to 65535. + \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. + Set to 0 to enable automatic gain control (recommended). + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + + /*! + \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. + Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. + \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + \param preambleLength Length of FSK preamble in bits. + \param enableOOK Use OOK modulation instead of FSK. + \returns \ref status_codes + */ + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + + /*! + \brief Reset method. Will reset the chip to the default state using RST pin. + */ + void reset() override; + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 525.0 MHz. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets %LoRa link bandwidth. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. Only available in %LoRa mode. + \param bw %LoRa link bandwidth to be set in kHz. + \returns \ref status_codes + */ + int16_t setBandwidth(float bw); + + /*! + \brief Sets %LoRa link spreading factor. Allowed values range from 6 to 12. Only available in %LoRa mode. + \param sf %LoRa link spreading factor to be set. + \returns \ref status_codes + */ + int16_t setSpreadingFactor(uint8_t sf); + + /*! + \brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode. + \param cr %LoRa link coding rate denominator to be set. + \returns \ref status_codes + */ + int16_t setCodingRate(uint8_t cr); + + /*! + \brief Sets FSK bit rate. Allowed values range from 0.5 to 300 kbps. Only available in FSK mode. + \param br Bit rate to be set (in kbps). + \returns \ref status_codes + */ + int16_t setBitRate(float br) override; + + /*! + \brief Set data. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr) override; + + /*! + \brief Sets transmission output power. Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). + High power +20 dBm operation is also supported, on the PA_BOOST pin. Defaults to PA_BOOST. + \param power Transmission output power in dBm. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power) override; + + /*! + \brief Sets transmission output power. Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). + High power +20 dBm operation is also supported, on the PA_BOOST pin. + \param power Transmission output power in dBm. + \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power, bool useRfo); + + /*! + \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. + Set to 0 to enable automatic gain control (recommended). + \param gain Gain of receiver LNA (low-noise amplifier) to be set. + \returns \ref status_codes + */ + int16_t setGain(uint8_t gain); + + /*! + \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. Only available in FSK mode with FSK modulation. + Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. + \param sh Gaussian shaping bandwidth-time product that will be used for data shaping + \returns \ref status_codes + */ + int16_t setDataShaping(uint8_t sh) override; + + /*! + \brief Sets filter cutoff frequency that will be used for data shaping. + Allowed values are 1 for frequency equal to bit rate and 2 for frequency equal to 2x bit rate. Set to 0 to disable data shaping. + Only available in FSK mode with OOK modulation. + \param sh Cutoff frequency that will be used for data shaping + \returns \ref status_codes + */ + int16_t setDataShapingOOK(uint8_t sh); + + /*! + \brief Gets recorded signal strength indicator. + \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. + \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. + \returns RSSI value in dBm. + */ + float getRSSI(bool packet = true, bool skipReceive = false); + + /*! + \brief Enables/disables CRC check of received packets. + \param enable Enable (true) or disable (false) CRC. + \param mode Set CRC mode to SX127X_CRC_WHITENING_TYPE_CCITT for CCITT, polynomial X16 + X12 + X5 + 1 (false) + or SX127X_CRC_WHITENING_TYPE_IBM for IBM, polynomial X16 + X15 + X2 + 1 (true). Only valid in FSK mode. + \returns \ref status_codes + */ + int16_t setCRC(bool enable, bool mode = false); + + /*! + \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, + LDRO will always be set to the provided value, regardless of symbol length. + To re-enable automatic LDRO configuration, call SX1278::autoLDRO() + \param enable Force LDRO to be always enabled (true) or disabled (false). + \returns \ref status_codes + */ + int16_t forceLDRO(bool enable); + + /*! + \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. After calling this method, + LDRO will be enabled automatically when symbol length exceeds 16 ms. + \returns \ref status_codes + */ + int16_t autoLDRO(); + + /*! + \brief Set implicit header mode for future reception/transmission. Required for spreading factor 6. + \param len Payload length in bytes. + \returns \ref status_codes + */ + int16_t implicitHeader(size_t len); + + /*! + \brief Set explicit header mode for future reception/transmission. + \returns \ref status_codes + */ + int16_t explicitHeader(); + +#if !RADIOLIB_GODMODE + protected: +#endif + int16_t setBandwidthRaw(uint8_t newBandwidth); + int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor); + int16_t setCodingRateRaw(uint8_t newCodingRate); + int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); + + int16_t configFSK(); + void errataFix(bool rx); + +#if !RADIOLIB_GODMODE + private: +#endif + bool ldroAuto = true; + bool ldroEnabled = false; + +}; + +/*! + \class RFM98 + \brief Only exists as alias for SX1278, since there seems to be no difference between %RFM98 and %SX1278 modules. +*/ +RADIOLIB_TYPE_ALIAS(SX1278, RFM98) + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX1279.cpp b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1279.cpp new file mode 100644 index 000000000..9f9ac0379 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1279.cpp @@ -0,0 +1,82 @@ +#include "SX1279.h" +#if !RADIOLIB_EXCLUDE_SX127X + +SX1279::SX1279(Module* mod) : SX1278(mod) { + +} + +int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { + // execute common part + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setGain(gain); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { + // execute common part + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = configFSK(); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + if(enableOOK) { + state = setDataShapingOOK(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } else { + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } + + return(state); +} + +int16_t SX1279::setFrequency(float freq) { + RADIOLIB_CHECK_RANGE(freq, 137.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); + + // set frequency and if successful, save the new setting + int16_t state = SX127x::setFrequencyRaw(freq); + if(state == RADIOLIB_ERR_NONE) { + SX127x::frequency = freq; + } + return(state); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX1279.h b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1279.h new file mode 100644 index 000000000..e802e9c43 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX1279.h @@ -0,0 +1,74 @@ +#if !defined(_RADIOLIB_SX1279_H) +#define _RADIOLIB_SX1279_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX127X + +#include "SX1278.h" + +/*! + \class SX1279 + \brief Derived class for %SX1279 modules. Overrides some methods from SX1278 due to different parameter ranges. +*/ +class SX1279: public SX1278 { + public: + + // constructor + + /*! + \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. + \param mod Instance of Module that will be used to communicate with the %LoRa chip. + */ + SX1279(Module* mod); + + // basic methods + + /*! + \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 960.0 MHz. + \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. + \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. + \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. + \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. + Allowed values range from 6 to 65535. + \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. + Set to 0 to enable automatic gain control (recommended). + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + + /*! + \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. + Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. + \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + \param preambleLength Length of FSK preamble in bits. + \param enableOOK Use OOK modulation instead of FSK. + \returns \ref status_codes + */ + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 960.0 MHz. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX127x.cpp b/lib/lib_rf/RadioLib/src/modules/SX127x/SX127x.cpp new file mode 100644 index 000000000..7606f001b --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX127x.cpp @@ -0,0 +1,1739 @@ +#include "SX127x.h" +#include +#if !RADIOLIB_EXCLUDE_SX127X + +SX127x::SX127x(Module* mod) : PhysicalLayer(RADIOLIB_SX127X_FREQUENCY_STEP_SIZE, RADIOLIB_SX127X_MAX_PACKET_LENGTH) { + this->mod = mod; +} + +int16_t SX127x::begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + + // try to find the SX127x chip + if(!SX127x::findChip(chipVersions, numVersions)) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX127x"); + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = config(); + RADIOLIB_ASSERT(state); + + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + // set LoRa mode + state = setActiveModem(RADIOLIB_SX127X_LORA); + RADIOLIB_ASSERT(state); + } + + // set LoRa sync word + state = SX127x::setSyncWord(syncWord); + RADIOLIB_ASSERT(state); + + // set over current protection + state = SX127x::setCurrentLimit(60); + RADIOLIB_ASSERT(state); + + // set preamble length + state = SX127x::setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + // disable IQ inversion + state = SX127x::invertIQ(false); + RADIOLIB_ASSERT(state); + + // initialize internal variables + this->dataRate = 0.0; + + return(state); +} + +int16_t SX127x::beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + + // try to find the SX127x chip + if(!SX127x::findChip(chipVersions, numVersions)) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX127x"); + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // check currently active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + // set FSK mode + state = setActiveModem(RADIOLIB_SX127X_FSK_OOK); + RADIOLIB_ASSERT(state); + } + + // enable/disable OOK + state = setOOK(enableOOK); + RADIOLIB_ASSERT(state); + + // set frequency deviation + state = SX127x::setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + // set AFC bandwidth + state = SX127x::setAFCBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + // set AFC&AGC trigger to RSSI (both in OOK and FSK) + state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT); + RADIOLIB_ASSERT(state); + + // enable AFC + state = SX127x::setAFC(false); + RADIOLIB_ASSERT(state); + + // set receiver bandwidth + state = SX127x::setRxBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + // set over current protection + state = SX127x::setCurrentLimit(60); + RADIOLIB_ASSERT(state); + + // set preamble length + state = SX127x::setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + // set preamble polarity + state = invertPreamble(false); + RADIOLIB_ASSERT(state); + + // set default sync word + uint8_t syncWord[] = {0x12, 0xAD}; + state = setSyncWord(syncWord, 2); + RADIOLIB_ASSERT(state); + + // disable address filtering + state = disableAddressFiltering(); + RADIOLIB_ASSERT(state); + + // set default RSSI measurement config + state = setRSSIConfig(2); + RADIOLIB_ASSERT(state); + + // set default encoding + state = setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + + // set default packet length mode + state = variablePacketLengthMode(); + + return(state); +} + +int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { + // set mode to standby + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + int16_t modem = getActiveModem(); + uint32_t start = 0; + uint32_t timeout = 0; + if(modem == RADIOLIB_SX127X_LORA) { + // calculate timeout (150 % of expected time-on-air) + timeout = getTimeOnAir(len) * 1.5; + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // calculate timeout (5ms + 500 % of expected time-on-air) + timeout = 5000 + getTimeOnAir(len) * 5; + + } else { + return(RADIOLIB_ERR_UNKNOWN); + + } + + // start transmission + state = startTransmit(data, len, addr); + RADIOLIB_ASSERT(state); + + // wait for packet transmission or timeout + start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { + finishTransmit(); + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + + // update data rate + uint32_t elapsed = this->mod->hal->micros() - start; + this->dataRate = (len*8.0)/((float)elapsed/1000000.0); + + return(finishTransmit()); +} + +int16_t SX127x::receive(uint8_t* data, size_t len) { + // set mode to standby + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + // set mode to receive + state = startReceive(len, RADIOLIB_SX127X_RXSINGLE); + RADIOLIB_ASSERT(state); + + // if no DIO1 is provided, use software timeout (100 LoRa symbols, same as hardware timeout) + uint32_t timeout = 0; + if(this->mod->getGpio() == RADIOLIB_NC) { + float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; + timeout = (uint32_t)(symbolLength * 100.0 * 1000.0); + } + + // wait for packet reception or timeout + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + + if(this->mod->getGpio() == RADIOLIB_NC) { + // no GPIO pin provided, use software timeout + if(this->mod->hal->micros() - start > timeout) { + clearIRQFlags(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } else { + // GPIO provided, use that + if(this->mod->hal->digitalRead(this->mod->getGpio())) { + clearIRQFlags(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } + + } + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // calculate timeout (500 % of expected time-on-air) + uint32_t timeout = getTimeOnAir(len) * 5; + + // set mode to receive + state = startReceive(len, RADIOLIB_SX127X_RX); + RADIOLIB_ASSERT(state); + + // wait for packet reception or timeout + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { + clearIRQFlags(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } + } + + // read the received data + state = readData(data, len); + + return(state); +} + +int16_t SX127x::scanChannel() { + // start CAD + int16_t state = startChannelScan(); + RADIOLIB_ASSERT(state); + + // wait for channel activity detected or timeout + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->digitalRead(this->mod->getGpio())) { + return(RADIOLIB_PREAMBLE_DETECTED); + } + } + + return(RADIOLIB_CHANNEL_FREE); +} + +int16_t SX127x::sleep() { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + // set mode to sleep + return(setMode(RADIOLIB_SX127X_SLEEP)); +} + +int16_t SX127x::standby() { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + // set mode to standby + return(setMode(RADIOLIB_SX127X_STANDBY)); +} + +int16_t SX127x::standby(uint8_t mode) { + (void)mode; + return(standby()); +} + +int16_t SX127x::transmitDirect(uint32_t frf) { + // check modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_TX); + + // user requested to start transmitting immediately (required for RTTY) + if(frf != 0) { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_MSB, (frf & 0xFF0000) >> 16); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_MID, (frf & 0x00FF00) >> 8); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_LSB, frf & 0x0000FF); + + return(setMode(RADIOLIB_SX127X_TX)); + } + + // activate direct mode + int16_t state = directMode(); + RADIOLIB_ASSERT(state); + + // apply fixes to errata + RADIOLIB_ERRATA_SX127X(false); + + // start transmitting + return(setMode(RADIOLIB_SX127X_TX)); +} + +int16_t SX127x::receiveDirect() { + // check modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // activate direct mode + int16_t state = directMode(); + RADIOLIB_ASSERT(state); + + // apply fixes to errata + RADIOLIB_ERRATA_SX127X(true); + + // start receiving + return(setMode(RADIOLIB_SX127X_RX)); +} + +int16_t SX127x::directMode() { + // set mode to standby + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_CONT_DCLK | RADIOLIB_SX127X_DIO2_CONT_DATA, 5, 2); + RADIOLIB_ASSERT(state); + + // enable receiver startup without preamble or RSSI + state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_NONE); + RADIOLIB_ASSERT(state); + + // set continuous mode + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_CONTINUOUS, 6, 6)); +} + +int16_t SX127x::packetMode() { + // check modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET, 6, 6)); +} + +int16_t SX127x::startReceive() { + return(this->startReceive(0, RADIOLIB_SX127X_RXCONTINUOUS)); +} + +int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { + // set mode to standby + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + // set DIO pin mapping + if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4); + } else { + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE | RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT, 7, 4); + } + + // set expected packet length for SF6 + if(this->spreadingFactor == 6) { + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); + this->packetLength = len; + } + + // apply fixes to errata + RADIOLIB_ERRATA_SX127X(true); + + // clear interrupt flags + clearIRQFlags(); + + // set FIFO pointers + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); + RADIOLIB_ASSERT(state); + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set DIO pin mapping + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + clearIRQFlags(); + + // FSK modem does not distinguish between Rx single and continuous + if(mode == RADIOLIB_SX127X_RXCONTINUOUS) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + return(setMode(RADIOLIB_SX127X_RX)); + } + } + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // set mode to receive + return(setMode(mode)); +} + +int16_t SX127x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)irqFlags; + (void)irqMask; + uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS; + if(timeout != 0) { + // for non-zero timeout value, change mode to Rx single and set the timeout + mode = RADIOLIB_SX127X_RXSINGLE; + uint8_t msb_sym = (timeout > 0x3FF) ? 0x3 : (uint8_t)(timeout >> 8); + uint8_t lsb_sym = (timeout > 0x3FF) ? 0xFF : (uint8_t)(timeout & 0xFF); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym); + RADIOLIB_ASSERT(state); + } + return(startReceive((uint8_t)len, mode)); +} + +void SX127x::setDio0Action(void (*func)(void), uint32_t dir) { + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, dir); +} + +void SX127x::clearDio0Action() { + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); +} + +void SX127x::setDio1Action(void (*func)(void), uint32_t dir) { + if(this->mod->getGpio() == RADIOLIB_NC) { + return; + } + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()), func, dir); +} + +void SX127x::clearDio1Action() { + if(this->mod->getGpio() == RADIOLIB_NC) { + return; + } + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio())); +} + +void SX127x::setPacketReceivedAction(void (*func)(void)) { + this->setDio0Action(func, this->mod->hal->GpioInterruptRising); +} + +void SX127x::clearPacketReceivedAction() { + this->clearDio0Action(); +} + +void SX127x::setPacketSentAction(void (*func)(void)) { + this->setDio0Action(func, this->mod->hal->GpioInterruptRising); +} + +void SX127x::clearPacketSentAction() { + this->clearDio0Action(); +} + +void SX127x::setChannelScanAction(void (*func)(void)) { + this->setDio0Action(func, this->mod->hal->GpioInterruptRising); +} + +void SX127x::clearChannelScanAction() { + this->clearDio0Action(); +} + +void SX127x::setFifoEmptyAction(void (*func)(void)) { + // set DIO1 to the FIFO empty event (the register setting is done in startTransmit) + setDio1Action(func, this->mod->hal->GpioInterruptRising); +} + +void SX127x::clearFifoEmptyAction() { + clearDio1Action(); +} + +void SX127x::setFifoFullAction(void (*func)(void)) { + // set the interrupt + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_LEVEL, 5, 4); + + // set DIO1 to the FIFO full event + setDio1Action(func, this->mod->hal->GpioInterruptRising); +} + +void SX127x::clearFifoFullAction() { + clearDio1Action(); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, 0x00, 5, 4); +} + +bool SX127x::fifoAdd(uint8_t* data, int totalLen, int* remLen) { + // subtract first (this may be the first time we get to modify the remaining length) + *remLen -= RADIOLIB_SX127X_FIFO_THRESH - 1; + + // check if there is still something left to send + if(*remLen <= 0) { + // we're done + return(true); + } + + // calculate the number of bytes we can copy + int len = *remLen; + if(len > RADIOLIB_SX127X_FIFO_THRESH - 1) { + len = RADIOLIB_SX127X_FIFO_THRESH - 1; + } + + // copy the bytes to the FIFO + this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, &data[totalLen - *remLen], len); + + // we're not done yet + return(false); +} + +bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) { + // get pointer to the correct position in data buffer + uint8_t* dataPtr = (uint8_t*)&data[*rcvLen]; + + // check how much data are we still expecting + uint8_t len = RADIOLIB_SX127X_FIFO_THRESH - 1; + if(totalLen - *rcvLen < len) { + // we're nearly at the end + len = totalLen - *rcvLen; + } + + // get the data + this->mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, len, dataPtr); + *rcvLen = *rcvLen + len; + + // check if we're done + if(*rcvLen >= totalLen) { + return(true); + } + return(false); +} + +int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { + // set mode to standby + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + // check packet length + if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set DIO mapping + if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4); + } else { + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE, 7, 6); + } + + // apply fixes to errata + RADIOLIB_ERRATA_SX127X(false); + + // clear interrupt flags + clearIRQFlags(); + + // set packet length + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); + + // set FIFO pointers + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX); + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // clear interrupt flags + clearIRQFlags(); + + // set DIO mapping + if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY, 5, 4); + } else { + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6); + } + + // set packet length + if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len); + } + + // check address filtering + uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1); + if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, addr); + } + } + + // write packet to FIFO + size_t packetLen = len; + if((modem == RADIOLIB_SX127X_FSK_OOK) && (len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) { + packetLen = RADIOLIB_SX127X_FIFO_THRESH - 1; + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); + } + this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, data, packetLen); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_TX); + + // start transmission + state |= setMode(RADIOLIB_SX127X_TX); + RADIOLIB_ASSERT(state); + + return(RADIOLIB_ERR_NONE); +} + +int16_t SX127x::finishTransmit() { + // wait for at least 1 bit at the lowest possible bit rate before clearing IRQ flags + // not doing this and clearing RADIOLIB_SX127X_FLAG_FIFO_OVERRUN will dump the FIFO, + // which can lead to mangling of the last bit (#808) + mod->hal->delayMicroseconds(1000000/1200); + + // clear interrupt flags + clearIRQFlags(); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + +int16_t SX127x::readData(uint8_t* data, size_t len) { + int16_t modem = getActiveModem(); + + // get packet length + size_t length = getPacketLength(); + size_t dumpLen = 0; + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + dumpLen = length - len; + length = len; + } + + // check payload CRC + int16_t state = RADIOLIB_ERR_NONE; + if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_IRQ_FLAGS, 5, 5) == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { + state = RADIOLIB_ERR_CRC_MISMATCH; + } + + if(modem == RADIOLIB_SX127X_LORA) { + // check packet header integrity + if(this->crcEnabled && (state == RADIOLIB_ERR_NONE) && (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6) == 0)) { + // CRC is disabled according to packet header and enabled according to user + // most likely damaged packet header + state = RADIOLIB_ERR_LORA_HEADER_DAMAGED; + } + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // check address filtering + uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1); + if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { + this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); + } + } + + // read packet data + this->mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, length, data); + + // dump the bytes that weren't requested + if(dumpLen != 0) { + clearFIFO(dumpLen); + } + + // clear internal flag so getPacketLength can return the new packet length + this->packetLengthQueried = false; + + // clear interrupt flags + clearIRQFlags(); + + return(state); +} + +int16_t SX127x::startChannelScan() { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + clearIRQFlags(); + + // set DIO pin mapping + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_CAD_DONE | RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED, 7, 4); + RADIOLIB_ASSERT(state); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // set mode to CAD + state = setMode(RADIOLIB_SX127X_CAD); + return(state); +} + +int16_t SX127x::getChannelScanResult() { + if((this->getIRQFlags() & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED) == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED) { + return(RADIOLIB_PREAMBLE_DETECTED); + } + return(RADIOLIB_CHANNEL_FREE); +} + +int16_t SX127x::setSyncWord(uint8_t syncWord) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + setMode(RADIOLIB_SX127X_STANDBY); + + // write register + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_WORD, syncWord)); +} + +int16_t SX127x::setCurrentLimit(uint8_t currentLimit) { + // check allowed range + if(!(((currentLimit >= 45) && (currentLimit <= 240)) || (currentLimit == 0))) { + return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT); + } + + // set mode to standby + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + + // set OCP limit + uint8_t raw; + if(currentLimit == 0) { + // limit set to 0, disable OCP + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_OFF, 5, 5); + } else if(currentLimit <= 120) { + raw = (currentLimit - 45) / 5; + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_ON | raw, 5, 0); + } else if(currentLimit <= 240) { + raw = (currentLimit + 30) / 10; + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_ON | raw, 5, 0); + } + return(state); +} + +int16_t SX127x::setPreambleLength(size_t preambleLength) { + // set mode to standby + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + // check active modem + uint8_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + // check allowed range + if(preambleLength < 6) { + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); + } + + // set preamble length + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB, (uint8_t)((preambleLength >> 8) & 0xFF)); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB, (uint8_t)(preambleLength & 0xFF)); + return(state); + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set preamble length (in bytes) + uint16_t numBytes = preambleLength / 8; + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK, (uint8_t)((numBytes >> 8) & 0xFF)); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK, (uint8_t)(numBytes & 0xFF)); + return(state); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + +int16_t SX127x::invertPreamble(bool enable) { + // set mode to standby + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + // check active modem + uint8_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set preamble polarity + uint8_t polarity = enable ? RADIOLIB_SX127X_PREAMBLE_POLARITY_AA : RADIOLIB_SX127X_PREAMBLE_POLARITY_55; + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, polarity, 5, 5); + return(state); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + +float SX127x::getFrequencyError(bool autoCorrect) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + // get raw frequency error + uint32_t raw = (uint32_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MSB, 3, 0) << 16; + raw |= (uint16_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MID) << 8; + raw |= this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_LSB); + + uint32_t base = (uint32_t)2 << 23; + float error; + + // check the first bit + if(raw & 0x80000) { + // frequency error is negative + raw |= (uint32_t)0xFFF00000; + raw = ~raw + 1; + error = (((float)raw * (float)base)/32000000.0) * (this->bandwidth/500.0) * -1.0; + } else { + error = (((float)raw * (float)base)/32000000.0) * (this->bandwidth/500.0); + } + + if(autoCorrect) { + // adjust LoRa modem data rate + float ppmOffset = 0.95 * (error/32.0); + this->mod->SPIwriteRegister(0x27, (uint8_t)ppmOffset); + } + + return(error); + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // get raw frequency error + uint16_t raw = (uint16_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MSB_FSK) << 8; + raw |= this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_LSB_FSK); + + uint32_t base = 1; + float error; + + // check the first bit + if(raw & 0x8000) { + // frequency error is negative + raw |= (uint32_t)0xFFF00000; + raw = ~raw + 1; + error = (float)raw * (32000000.0 / (float)(base << 19)) * -1.0; + } else { + error = (float)raw * (32000000.0 / (float)(base << 19)); + } + + return(error); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + +float SX127x::getAFCError() +{ + // check active modem + int16_t modem = getActiveModem(); + if(modem != RADIOLIB_SX127X_FSK_OOK) { + return 0; + } + + // get raw frequency error + int16_t raw = (uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_MSB) << 8; + raw |= this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_LSB); + + uint32_t base = 1; + return raw * (32000000.0 / (float)(base << 19)); +} + +float SX127x::getSNR() { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(0); + } + + // get SNR value + int8_t rawSNR = (int8_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_SNR_VALUE); + return(rawSNR / 4.0); +} + +float SX127x::getDataRate() const { + return(this->dataRate); +} + +int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check allowed bit rate + // datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine + if(ookEnabled) { + RADIOLIB_CHECK_RANGE(br, 0.5, 32.768002, RADIOLIB_ERR_INVALID_BIT_RATE); // Found that 32.768 is 32.768002 + } else { + RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + } + + // set mode to STANDBY + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + // set bit rate + uint16_t bitRate = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / br; + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); + + // set fractional part of bit rate + if(!ookEnabled) { + float bitRateRem = ((RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / (float)br) - (float)bitRate; + uint8_t bitRateFrac = bitRateRem * 16; + state |= this->mod->SPIsetRegValue(fracRegAddr, bitRateFrac, 7, 0); + } + + if(state == RADIOLIB_ERR_NONE) { + this->bitRate = br; + } + return(state); +} + +int16_t SX127x::setFrequencyDeviation(float freqDev) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set frequency deviation to lowest available setting (required for digimodes) + float newFreqDev = freqDev; + if(freqDev < 0.0) { + newFreqDev = 0.6; + } + + // check frequency deviation range + if(!((newFreqDev + this->bitRate/2.0 <= 250.0) && (freqDev <= 200.0))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + } + + // set mode to STANDBY + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + // set allowed frequency deviation + uint32_t base = 1; + uint32_t FDEV = (newFreqDev * (base << 19)) / 32000; + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FDEV_MSB, (FDEV & 0xFF00) >> 8, 5, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FDEV_LSB, FDEV & 0x00FF, 7, 0); + return(state); +} + +uint8_t SX127x::calculateBWManExp(float bandwidth) +{ + for(uint8_t e = 7; e >= 1; e--) { + for(int8_t m = 2; m >= 0; m--) { + float point = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + 2))); + if(fabs(bandwidth - ((point / 1000.0) + 0.05)) <= 0.5) { + return((m << 3) | e); + } + } + } + return 0; +} + +int16_t SX127x::setRxBandwidth(float rxBw) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + RADIOLIB_CHECK_RANGE(rxBw, 2.6, 250.0, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); + + // set mode to STANDBY + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + // set Rx bandwidth + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_BW, calculateBWManExp(rxBw), 4, 0)); +} + +int16_t SX127x::setAFCBandwidth(float rxBw) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK){ + return(RADIOLIB_ERR_WRONG_MODEM); + } + + RADIOLIB_CHECK_RANGE(rxBw, 2.6, 250.0, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); + + // set mode to STANDBY + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + // set AFC bandwidth + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_AFC_BW, calculateBWManExp(rxBw), 4, 0)); +} + +int16_t SX127x::setAFC(bool isEnabled) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + //set AFC auto on/off + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, isEnabled ? RADIOLIB_SX127X_AFC_AUTO_ON : RADIOLIB_SX127X_AFC_AUTO_OFF, 4, 4)); +} + +int16_t SX127x::setAFCAGCTrigger(uint8_t trigger) { + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + //set AFC&AGC trigger + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, trigger, 2, 0)); +} + +int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) { + // check active modem + uint8_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + + // disable sync word in case len is 0 + if(len == 0) { + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_OFF, 4, 4); + return(state); + } + + RADIOLIB_CHECK_RANGE(len, 1, 8, RADIOLIB_ERR_INVALID_SYNC_WORD); + + // sync word must not contain value 0x00 + for(size_t i = 0; i < len; i++) { + if(syncWord[i] == 0x00) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + } + + // enable sync word recognition + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_ON, 4, 4); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, len - 1, 2, 0); + RADIOLIB_ASSERT(state); + + // set sync word + this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_SYNC_VALUE_1, syncWord, len); + return(RADIOLIB_ERR_NONE); + + } else if(modem == RADIOLIB_SX127X_LORA) { + // with length set to 1 and LoRa modem active, assume it is the LoRa sync word + if(len > 1) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + + return(this->setSyncWord(syncWord[0])); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + +int16_t SX127x::setNodeAddress(uint8_t nodeAddr) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // enable address filtering (node only) + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE, 2, 1); + RADIOLIB_ASSERT(state); + + // set node address + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, nodeAddr)); +} + +int16_t SX127x::setBroadcastAddress(uint8_t broadAddr) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // enable address filtering (node + broadcast) + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1); + RADIOLIB_ASSERT(state); + + // set broadcast address + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, broadAddr)); +} + +int16_t SX127x::disableAddressFiltering() { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // disable address filtering + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_OFF, 2, 1); + RADIOLIB_ASSERT(state); + + // set node address to default (0x00) + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, 0x00); + RADIOLIB_ASSERT(state); + + // set broadcast address to default (0x00) + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, 0x00)); +} + +int16_t SX127x::setOokThresholdType(uint8_t type) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, type, 4, 3, 5)); +} + +int16_t SX127x::setOokFixedOrFloorThreshold(uint8_t value) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_FIX, value, 7, 0, 5)); +} + +int16_t SX127x::setOokPeakThresholdDecrement(uint8_t value) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_AVG, value, 7, 5, 5)); +} + +int16_t SX127x::setOokPeakThresholdStep(uint8_t value) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, value, 2, 0, 5)); +} + +int16_t SX127x::enableBitSync() { + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_ON, 5, 5, 5)); +} + +int16_t SX127x::disableBitSync() { + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_OFF, 5, 5, 5)); +} + +int16_t SX127x::setOOK(bool enableOOK) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set OOK and if successful, save the new setting + int16_t state = RADIOLIB_ERR_NONE; + if(enableOOK) { + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_OOK, 6, 5, 5); + state |= SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT); + } else { + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_FSK, 6, 5, 5); + state |= SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_BOTH); + } + if(state == RADIOLIB_ERR_NONE) { + ookEnabled = enableOOK; + } + + return(state); +} + +int16_t SX127x::setFrequencyRaw(float newFreq) { + int16_t state = RADIOLIB_ERR_NONE; + + // set mode to standby if not FHSS + if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) == RADIOLIB_SX127X_HOP_PERIOD_OFF) { + state = setMode(RADIOLIB_SX127X_STANDBY); + } + + // calculate register values + uint32_t FRF = (newFreq * (uint32_t(1) << RADIOLIB_SX127X_DIV_EXPONENT)) / RADIOLIB_SX127X_CRYSTAL_FREQ; + + // write registers + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MID, (FRF & 0x00FF00) >> 8); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_LSB, FRF & 0x0000FF); + return(state); +} + +size_t SX127x::getPacketLength(bool update) { + int16_t modem = getActiveModem(); + + if(modem == RADIOLIB_SX127X_LORA) { + if(this->spreadingFactor != 6) { + // get packet length for SF7 - SF12 + return(this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_RX_NB_BYTES)); + + } else { + // return the cached value for SF6 + return(this->packetLength); + } + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // get packet length + if(!this->packetLengthQueried && update) { + if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) { + this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); + } else { + this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK); + } + this->packetLengthQueried = true; + } + } + + return(this->packetLength); +} + +int16_t SX127x::fixedPacketLengthMode(uint8_t len) { + return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_FIXED, len)); +} + +int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) { + return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_VARIABLE, maxLen)); +} + +float SX127x::getNumSymbols(size_t len) { + // get symbol length in us + float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; + + // get Low Data Rate optimization flag + float de = 0; + if (symbolLength >= 16.0) { + de = 1; + } + + // get explicit/implicit header enabled flag + float ih = (float) this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0); + + // get CRC enabled flag + float crc = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); + + // get number of preamble symbols + float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); + + // get number of payload symbols + float n_pay = 8.0 + RADIOLIB_MAX(ceil((8.0 * (float) len - 4.0 * (float) this->spreadingFactor + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) this->spreadingFactor - 8.0 * de)) * (float) this->codingRate, 0.0); + + // add 4.25 symbols for the sync + return(n_pre + n_pay + 4.25f); +} + +uint32_t SX127x::getTimeOnAir(size_t len) { + // check active modem + uint8_t modem = getActiveModem(); + if (modem == RADIOLIB_SX127X_LORA) { + // get symbol length in us + float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; + + // get number of symbols + float n_sym = getNumSymbols(len); + + // Get time-on-air in us + return ceil((double)symbolLength * (double)n_sym) * 1000; + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // Get number of bits preamble + float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8; + //Get the number of bits of the sync word + float n_syncWord = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8; + //Get CRC bits + float crc = (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON) * 16; + + if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) { + //If Packet size fixed -> len = fixed packet length + len = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK); + } else { + //if packet variable -> Add 1 extra byte for payload length + len += 1; + } + + // Calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec) + return (uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (this->bitRate * 1000.0)) * 1000000.0); + } else { + return(RADIOLIB_ERR_UNKNOWN); + } + +} + +uint32_t SX127x::calculateRxTimeout(uint32_t timeoutUs) { + // the timeout is given as the number of symbols + // the calling function should provide some extra width, as this number of symbols is truncated to integer + // the order of operators is swapped here to decrease the effects of this truncation error + float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; + uint32_t numSymbols = (timeoutUs / symbolLength) / 1000; + return(numSymbols); +} + +int16_t SX127x::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) { + // IRQ flags/masks are inverted to what seems logical for SX127x (0 being activated, 1 being deactivated) + irqFlags = RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DEFAULT; + irqMask = RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DONE & RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_TIMEOUT; + return(RADIOLIB_ERR_NONE); +} + +bool SX127x::isRxTimeout() { + uint16_t irq = getIRQFlags(); + bool rxTimedOut = irq & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT; + return(rxTimedOut); +} + +int16_t SX127x::setCrcFiltering(bool enable) { + this->crcOn = enable; + + if (enable == true) { + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4)); + } else { + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4)); + } +} + +int16_t SX127x::setRSSIThreshold(float dbm) { + RADIOLIB_CHECK_RANGE(dbm, -127.5, 0, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD); + + return this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); +} + +int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // check provided values + if(!(smoothingSamples <= 7)) { + return(RADIOLIB_ERR_INVALID_NUM_SAMPLES); + } + + RADIOLIB_CHECK_RANGE(offset, -16, 15, RADIOLIB_ERR_INVALID_RSSI_OFFSET); + + // set new register values + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, offset << 3, 7, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, smoothingSamples, 2, 0); + return(state); +} + +int16_t SX127x::setEncoding(uint8_t encoding) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set encoding + switch(encoding) { + case RADIOLIB_ENCODING_NRZ: + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_NONE, 6, 5)); + case RADIOLIB_ENCODING_MANCHESTER: + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_MANCHESTER, 6, 5)); + case RADIOLIB_ENCODING_WHITENING: + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_WHITENING, 6, 5)); + default: + return(RADIOLIB_ERR_INVALID_ENCODING); + } +} + +uint16_t SX127x::getIRQFlags() { + // check active modem + if(getActiveModem() == RADIOLIB_SX127X_LORA) { + // LoRa, just 8-bit value + return((uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS)); + + } else { + // FSK, the IRQ flags are 16 bits in total + uint16_t flags = ((uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2)) << 8; + flags |= (uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1); + return(flags); + } + +} + +uint8_t SX127x::getModemStatus() { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(0x00); + } + + // read the register + return(this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_MODEM_STAT)); +} + +void SX127x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { + this->mod->setRfSwitchPins(rxEn, txEn); +} + +void SX127x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + this->mod->setRfSwitchTable(pins, table); +} + +uint8_t SX127x::randomByte() { + // check active modem + uint8_t rssiValueReg = RADIOLIB_SX127X_REG_RSSI_WIDEBAND; + if(getActiveModem() == RADIOLIB_SX127X_FSK_OOK) { + rssiValueReg = RADIOLIB_SX127X_REG_RSSI_VALUE_FSK; + } + + // set mode to Rx + setMode(RADIOLIB_SX127X_RX); + + // wait a bit for the RSSI reading to stabilise + this->mod->hal->delay(10); + + // read RSSI value 8 times, always keep just the least significant bit + uint8_t randByte = 0x00; + for(uint8_t i = 0; i < 8; i++) { + randByte |= ((this->mod->SPIreadRegister(rssiValueReg) & 0x01) << i); + } + + // set mode to standby + setMode(RADIOLIB_SX127X_STANDBY); + + return(randByte); +} + +int16_t SX127x::getChipVersion() { + return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_VERSION)); +} + +int8_t SX127x::getTempRaw() { + int8_t temp = 0; + uint8_t previousOpMode; + uint8_t ival; + + // save current Op Mode + previousOpMode = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE); + + // check if we need to step out of LoRa mode first + if((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) { + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP)); + } + + // put device in FSK sleep + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP)); + + // put device in FSK RxSynth + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_FSRX)); + + // enable temperature reading + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_ON, 0, 0); + + // wait + this->mod->hal->delayMicroseconds(200); + + // disable temperature reading + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_OFF, 0, 0); + + // put device in FSK sleep + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP)); + + // read temperature + ival = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_TEMP); + + // convert very raw value + if((ival & 0x80) == 0x80) { + temp = 255 - ival; + } else { + temp = -1 * ival; + } + + // check if we need to step back into LoRa mode + if((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) { + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP)); + } + + // reload previous Op Mode + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, previousOpMode); + + return(temp); +} + +Module* SX127x::getMod() { + return(this->mod); +} + +int16_t SX127x::config() { + // turn off frequency hopping + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, RADIOLIB_SX127X_HOP_PERIOD_OFF); + return(state); +} + +int16_t SX127x::configFSK() { + // set RSSI threshold + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, RADIOLIB_SX127X_RSSI_THRESHOLD); + RADIOLIB_ASSERT(state); + + // reset FIFO flag + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, RADIOLIB_SX127X_FLAG_FIFO_OVERRUN); + + // set packet configuration + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_PACKET_VARIABLE | RADIOLIB_SX127X_DC_FREE_NONE | RADIOLIB_SX127X_CRC_ON | RADIOLIB_SX127X_CRC_AUTOCLEAR_ON | RADIOLIB_SX127X_ADDRESS_FILTERING_OFF | RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 7, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET | RADIOLIB_SX127X_IO_HOME_OFF, 6, 5); + RADIOLIB_ASSERT(state); + + // set FIFO threshold + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0); + RADIOLIB_ASSERT(state); + + // disable Rx timeouts + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_1, RADIOLIB_SX127X_TIMEOUT_RX_RSSI_OFF); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_2, RADIOLIB_SX127X_TIMEOUT_RX_PREAMBLE_OFF); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_3, RADIOLIB_SX127X_TIMEOUT_SIGNAL_SYNC_OFF); + RADIOLIB_ASSERT(state); + + // enable preamble detector + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_DETECT, RADIOLIB_SX127X_PREAMBLE_DETECTOR_ON | RADIOLIB_SX127X_PREAMBLE_DETECTOR_2_BYTE | RADIOLIB_SX127X_PREAMBLE_DETECTOR_TOL); + + return(state); +} + +int16_t SX127x::setPacketMode(uint8_t mode, uint8_t len) { + // check packet length + if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set to fixed packet length + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, mode, 7, 7); + RADIOLIB_ASSERT(state); + + // set length to register + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK, len); + RADIOLIB_ASSERT(state); + + // update cached value + this->packetLengthConfig = mode; + return(state); +} + +bool SX127x::findChip(uint8_t* vers, uint8_t num) { + uint8_t i = 0; + bool flagFound = false; + while((i < 10) && !flagFound) { + // reset the module + reset(); + + // check version register + int16_t version = getChipVersion(); + for(uint8_t i = 0; i < num; i++) { + if(version == vers[i]) { + flagFound = true; + break; + } + } + + if(!flagFound) { + RADIOLIB_DEBUG_BASIC_PRINTLN("SX127x not found! (%d of 10 tries) RADIOLIB_SX127X_REG_VERSION == 0x%04X", i + 1, version); + this->mod->hal->delay(10); + i++; + } + + } + + return(flagFound); +} + +int16_t SX127x::setMode(uint8_t mode) { + uint8_t checkMask = 0xFF; + if((getActiveModem() == RADIOLIB_SX127X_FSK_OOK) && (mode == RADIOLIB_SX127X_RX)) { + // disable checking of RX bit in FSK RX mode, as it sometimes seem to fail (#276) + checkMask = 0xFE; + } + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, mode, 2, 0, 5, checkMask)); +} + +int16_t SX127x::getActiveModem() { + return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE, 7, 7)); +} + +int16_t SX127x::setActiveModem(uint8_t modem) { + // set mode to SLEEP + int16_t state = setMode(RADIOLIB_SX127X_SLEEP); + + // set modem + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, modem, 7, 7, 5); + + // set mode to STANDBY + state |= setMode(RADIOLIB_SX127X_STANDBY); + return(state); +} + +void SX127x::clearIRQFlags() { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, 0b11111111); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1, 0b11111111); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, 0b11111111); + } +} + +void SX127x::clearFIFO(size_t count) { + while(count) { + this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); + count--; + } +} + +int16_t SX127x::invertIQ(bool enable) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // Tx path inversion is swapped, because it seems that setting it according to the datsheet + // will actually lead to the wrong inversion. See https://github.com/jgromes/RadioLib/issues/778 + int16_t state; + if(enable) { + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_ON, 6, 6); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_OFF, 0, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_ENABLE); + } else { + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_OFF, 6, 6); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_ON, 0, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_DISABLE); + } + + return(state); +} + +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE +void SX127x::setDirectAction(void (*func)(void)) { + setDio1Action(func, this->mod->hal->GpioInterruptRising); +} + +void SX127x::readBit(uint32_t pin) { + updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin)); +} +#endif + +int16_t SX127x::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); +} + +uint8_t SX127x::getFHSSHoppingPeriod(void) { + return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); +} + +uint8_t SX127x::getFHSSChannel(void) { + return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); +} + +void SX127x::clearFHSSInt(void) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + return; //These are not the interrupts you are looking for + } +} + +int16_t SX127x::setDIOMapping(uint32_t pin, uint32_t value) { + if (pin > 5) + return RADIOLIB_ERR_INVALID_DIO_PIN; + + if (pin < 4) + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin)); + else + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin)); +} + +int16_t SX127x::setDIOPreambleDetect(bool usePreambleDetect) { + return this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, (usePreambleDetect) ? RADIOLIB_SX127X_DIO_MAP_PREAMBLE_DETECT : RADIOLIB_SX127X_DIO_MAP_RSSI, 0, 0); +} + +float SX127x::getRSSI(bool packet, bool skipReceive, int16_t offset) { + if(getActiveModem() == RADIOLIB_SX127X_LORA) { + if(packet) { + // LoRa packet mode, get RSSI of the last packet + float lastPacketRSSI = offset + this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); + + // spread-spectrum modulation signal can be received below noise floor + // check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value + float lastPacketSNR = SX127x::getSNR(); + if(lastPacketSNR < 0.0) { + lastPacketRSSI += lastPacketSNR; + } + return(lastPacketRSSI); + + } else { + // LoRa instant, get current RSSI + float currentRSSI = offset + this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE); + return(currentRSSI); + } + + } else { + // for FSK, there is no packet RSSI + + // enable listen mode + if(!skipReceive) { + startReceive(); + } + + // read the value for FSK + float rssi = (float)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0; + + // set mode back to standby + if(!skipReceive) { + standby(); + } + + // return the value + return(rssi); + } +} + +int16_t SX127x::setLowBatteryThreshold(int8_t level, uint32_t pin) { + // check disable + if(level < 0) { + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LOW_BAT, RADIOLIB_SX127X_LOW_BAT_OFF, 3, 3)); + } + + // enable detector and set the threshold + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LOW_BAT, RADIOLIB_SX127X_LOW_BAT_ON | level, 3, 0); + RADIOLIB_ASSERT(state); + + // set DIO mapping + switch(pin) { + case(0): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_TEMP_CHANGE_LOW_BAT, 7, 6)); + case(3): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO3_CONT_TEMP_CHANGE_LOW_BAT, 1, 0)); + case(4): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, RADIOLIB_SX127X_DIO4_PACK_TEMP_CHANGE_LOW_BAT, 7, 6)); + } + return(RADIOLIB_ERR_INVALID_DIO_PIN); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX127x/SX127x.h b/lib/lib_rf/RadioLib/src/modules/SX127x/SX127x.h new file mode 100644 index 000000000..fd3d4a94a --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX127x/SX127x.h @@ -0,0 +1,1282 @@ +#if !defined(_RADIOLIB_SX127X_H) +#define _RADIOLIB_SX127X_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX127X + +#include "../../Module.h" + +#include "../../protocols/PhysicalLayer/PhysicalLayer.h" + +// SX127x physical layer properties +#define RADIOLIB_SX127X_FREQUENCY_STEP_SIZE 61.03515625 +#define RADIOLIB_SX127X_MAX_PACKET_LENGTH 255 +#define RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK 64 +#define RADIOLIB_SX127X_CRYSTAL_FREQ 32.0 +#define RADIOLIB_SX127X_DIV_EXPONENT 19 + +// SX127x series common LoRa registers +#define RADIOLIB_SX127X_REG_FIFO 0x00 +#define RADIOLIB_SX127X_REG_OP_MODE 0x01 +#define RADIOLIB_SX127X_REG_FRF_MSB 0x06 +#define RADIOLIB_SX127X_REG_FRF_MID 0x07 +#define RADIOLIB_SX127X_REG_FRF_LSB 0x08 +#define RADIOLIB_SX127X_REG_PA_CONFIG 0x09 +#define RADIOLIB_SX127X_REG_PA_RAMP 0x0A +#define RADIOLIB_SX127X_REG_OCP 0x0B +#define RADIOLIB_SX127X_REG_LNA 0x0C +#define RADIOLIB_SX127X_REG_FIFO_ADDR_PTR 0x0D +#define RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR 0x0E +#define RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR 0x0F +#define RADIOLIB_SX127X_REG_FIFO_RX_CURRENT_ADDR 0x10 +#define RADIOLIB_SX127X_REG_IRQ_FLAGS_MASK 0x11 +#define RADIOLIB_SX127X_REG_IRQ_FLAGS 0x12 +#define RADIOLIB_SX127X_REG_RX_NB_BYTES 0x13 +#define RADIOLIB_SX127X_REG_RX_HEADER_CNT_VALUE_MSB 0x14 +#define RADIOLIB_SX127X_REG_RX_HEADER_CNT_VALUE_LSB 0x15 +#define RADIOLIB_SX127X_REG_RX_PACKET_CNT_VALUE_MSB 0x16 +#define RADIOLIB_SX127X_REG_RX_PACKET_CNT_VALUE_LSB 0x17 +#define RADIOLIB_SX127X_REG_MODEM_STAT 0x18 +#define RADIOLIB_SX127X_REG_PKT_SNR_VALUE 0x19 +#define RADIOLIB_SX127X_REG_PKT_RSSI_VALUE 0x1A +#define RADIOLIB_SX127X_REG_RSSI_VALUE 0x1B +#define RADIOLIB_SX127X_REG_HOP_CHANNEL 0x1C +#define RADIOLIB_SX127X_REG_MODEM_CONFIG_1 0x1D +#define RADIOLIB_SX127X_REG_MODEM_CONFIG_2 0x1E +#define RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB 0x1F +#define RADIOLIB_SX127X_REG_PREAMBLE_MSB 0x20 +#define RADIOLIB_SX127X_REG_PREAMBLE_LSB 0x21 +#define RADIOLIB_SX127X_REG_PAYLOAD_LENGTH 0x22 +#define RADIOLIB_SX127X_REG_MAX_PAYLOAD_LENGTH 0x23 +#define RADIOLIB_SX127X_REG_HOP_PERIOD 0x24 +#define RADIOLIB_SX127X_REG_FIFO_RX_BYTE_ADDR 0x25 +#define RADIOLIB_SX127X_REG_FEI_MSB 0x28 +#define RADIOLIB_SX127X_REG_FEI_MID 0x29 +#define RADIOLIB_SX127X_REG_FEI_LSB 0x2A +#define RADIOLIB_SX127X_REG_RSSI_WIDEBAND 0x2C +#define RADIOLIB_SX127X_REG_DETECT_OPTIMIZE 0x31 +#define RADIOLIB_SX127X_REG_INVERT_IQ 0x33 +#define RADIOLIB_SX127X_REG_DETECTION_THRESHOLD 0x37 +#define RADIOLIB_SX127X_REG_SYNC_WORD 0x39 +#define RADIOLIB_SX127X_REG_INVERT_IQ2 0x3B +#define RADIOLIB_SX127X_REG_DIO_MAPPING_1 0x40 +#define RADIOLIB_SX127X_REG_DIO_MAPPING_2 0x41 +#define RADIOLIB_SX127X_REG_VERSION 0x42 + +// SX127x common LoRa modem settings +// RADIOLIB_SX127X_REG_OP_MODE MSB LSB DESCRIPTION +#define RADIOLIB_SX127X_FSK_OOK 0b00000000 // 7 7 FSK/OOK mode +#define RADIOLIB_SX127X_LORA 0b10000000 // 7 7 LoRa mode +#define RADIOLIB_SX127X_ACCESS_SHARED_REG_OFF 0b00000000 // 6 6 access LoRa registers (0x0D:0x3F) in LoRa mode +#define RADIOLIB_SX127X_ACCESS_SHARED_REG_ON 0b01000000 // 6 6 access FSK registers (0x0D:0x3F) in LoRa mode +#define RADIOLIB_SX127X_SLEEP 0b00000000 // 2 0 sleep +#define RADIOLIB_SX127X_STANDBY 0b00000001 // 2 0 standby +#define RADIOLIB_SX127X_FSTX 0b00000010 // 2 0 frequency synthesis TX +#define RADIOLIB_SX127X_TX 0b00000011 // 2 0 transmit +#define RADIOLIB_SX127X_FSRX 0b00000100 // 2 0 frequency synthesis RX +#define RADIOLIB_SX127X_RXCONTINUOUS 0b00000101 // 2 0 receive continuous +#define RADIOLIB_SX127X_RXSINGLE 0b00000110 // 2 0 receive single +#define RADIOLIB_SX127X_CAD 0b00000111 // 2 0 channel activity detection + +// RADIOLIB_SX127X_REG_PA_CONFIG +#define RADIOLIB_SX127X_PA_SELECT_RFO 0b00000000 // 7 7 RFO pin output, power limited to +14 dBm +#define RADIOLIB_SX127X_PA_SELECT_BOOST 0b10000000 // 7 7 PA_BOOST pin output, power limited to +20 dBm +#define RADIOLIB_SX127X_OUTPUT_POWER 0b00001111 // 3 0 output power: P_out = 2 + OUTPUT_POWER [dBm] for PA_SELECT_BOOST + // P_out = -1 + OUTPUT_POWER [dBm] for PA_SELECT_RFO + +// RADIOLIB_SX127X_REG_OCP +#define RADIOLIB_SX127X_OCP_OFF 0b00000000 // 5 5 PA overload current protection disabled +#define RADIOLIB_SX127X_OCP_ON 0b00100000 // 5 5 PA overload current protection enabled +#define RADIOLIB_SX127X_OCP_TRIM 0b00001011 // 4 0 OCP current: I_max(OCP_TRIM = 0b1011) = 100 mA + +// RADIOLIB_SX127X_REG_LNA +#define RADIOLIB_SX127X_LNA_GAIN_1 0b00100000 // 7 5 LNA gain setting: max gain +#define RADIOLIB_SX127X_LNA_GAIN_2 0b01000000 // 7 5 . +#define RADIOLIB_SX127X_LNA_GAIN_3 0b01100000 // 7 5 . +#define RADIOLIB_SX127X_LNA_GAIN_4 0b10000000 // 7 5 . +#define RADIOLIB_SX127X_LNA_GAIN_5 0b10100000 // 7 5 . +#define RADIOLIB_SX127X_LNA_GAIN_6 0b11000000 // 7 5 min gain +#define RADIOLIB_SX127X_LNA_BOOST_OFF 0b00000000 // 1 0 default LNA current +#define RADIOLIB_SX127X_LNA_BOOST_ON 0b00000011 // 1 0 150% LNA current + +// RADIOLIB_SX127X_REG_MODEM_CONFIG_2 +#define RADIOLIB_SX127X_SF_6 0b01100000 // 7 4 spreading factor: 64 chips/bit +#define RADIOLIB_SX127X_SF_7 0b01110000 // 7 4 128 chips/bit +#define RADIOLIB_SX127X_SF_8 0b10000000 // 7 4 256 chips/bit +#define RADIOLIB_SX127X_SF_9 0b10010000 // 7 4 512 chips/bit +#define RADIOLIB_SX127X_SF_10 0b10100000 // 7 4 1024 chips/bit +#define RADIOLIB_SX127X_SF_11 0b10110000 // 7 4 2048 chips/bit +#define RADIOLIB_SX127X_SF_12 0b11000000 // 7 4 4096 chips/bit +#define RADIOLIB_SX127X_TX_MODE_SINGLE 0b00000000 // 3 3 single TX +#define RADIOLIB_SX127X_TX_MODE_CONT 0b00001000 // 3 3 continuous TX +#define RADIOLIB_SX127X_RX_TIMEOUT_MSB 0b00000000 // 1 0 + +// RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB +#define RADIOLIB_SX127X_RX_TIMEOUT_LSB 0b01100100 // 7 0 10-bit RX operation timeout + +// RADIOLIB_SX127X_REG_PREAMBLE_MSB + REG_PREAMBLE_LSB +#define RADIOLIB_SX127X_PREAMBLE_LENGTH_MSB 0b00000000 // 7 0 2-byte preamble length setting: l_P = PREAMBLE_LENGTH + 4.25 +#define RADIOLIB_SX127X_PREAMBLE_LENGTH_LSB 0b00001000 // 7 0 where l_p = preamble length + +// RADIOLIB_SX127X_REG_DETECT_OPTIMIZE +#define RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6 0b00000101 // 2 0 SF6 detection optimization +#define RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12 0b00000011 // 2 0 SF7 to SF12 detection optimization + +// RADIOLIB_SX127X_REG_INVERT_IQ +#define RADIOLIB_SX127X_INVERT_IQ_RXPATH_ON 0b01000000 // 6 6 I and Q signals are inverted +#define RADIOLIB_SX127X_INVERT_IQ_RXPATH_OFF 0b00000000 // 6 6 normal mode +#define RADIOLIB_SX127X_INVERT_IQ_TXPATH_ON 0b00000001 // 0 0 I and Q signals are inverted +#define RADIOLIB_SX127X_INVERT_IQ_TXPATH_OFF 0b00000000 // 0 0 normal mode + +// RADIOLIB_SX127X_REG_DETECTION_THRESHOLD +#define RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6 0b00001100 // 7 0 SF6 detection threshold +#define RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12 0b00001010 // 7 0 SF7 to SF12 detection threshold + +// RADIOLIB_SX127X_REG_PA_DAC +#define RADIOLIB_SX127X_PA_BOOST_OFF 0b00000100 // 2 0 PA_BOOST disabled +#define RADIOLIB_SX127X_PA_BOOST_ON 0b00000111 // 2 0 +20 dBm on PA_BOOST when OUTPUT_POWER = 0b1111 + +// RADIOLIB_SX127X_REG_HOP_PERIOD +#define RADIOLIB_SX127X_HOP_PERIOD_OFF 0b00000000 // 7 0 number of periods between frequency hops; 0 = disabled +#define RADIOLIB_SX127X_HOP_PERIOD_MAX 0b11111111 // 7 0 + +// RADIOLIB_SX127X_REG_IRQ_FLAGS +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT 0b10000000 // 7 7 timeout +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE 0b01000000 // 6 6 packet reception complete +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b00100000 // 5 5 payload CRC error +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER 0b00010000 // 4 4 valid header received +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE 0b00001000 // 3 3 payload transmission complete +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE 0b00000100 // 2 2 CAD complete +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b00000010 // 1 1 FHSS change channel +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED 0b00000001 // 0 0 valid LoRa signal detected during CAD operation + +// RADIOLIB_SX127X_REG_IRQ_FLAGS_MASK +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_TIMEOUT 0b01111111 // 7 7 timeout +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DONE 0b10111111 // 6 6 packet reception complete +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b11011111 // 5 5 payload CRC error +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_VALID_HEADER 0b11101111 // 4 4 valid header received +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_TX_DONE 0b11110111 // 3 3 payload transmission complete +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DONE 0b11111011 // 2 2 CAD complete +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b11111101 // 1 1 FHSS change channel +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DETECTED 0b11111110 // 0 0 valid LoRa signal detected during CAD operation +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DEFAULT 0b00011111 // 7 0 default for Rx (RX_TIMEOUT, RX_DONE, CRC_ERR) + +// RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR +#define RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for TX only + +// RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR +#define RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for RX only + +// RADIOLIB_SX127X_REG_SYNC_WORD +#define RADIOLIB_SX127X_SYNC_WORD 0x12 // 7 0 default LoRa sync word +#define RADIOLIB_SX127X_SYNC_WORD_LORAWAN 0x34 // 7 0 sync word reserved for LoRaWAN networks + +// RADIOLIB_SX127X_REG_INVERT_IQ2 +#define RADIOLIB_SX127X_IQ2_ENABLE 0x19 // 7 0 enable optimize for inverted IQ +#define RADIOLIB_SX127X_IQ2_DISABLE 0x1D // 7 0 reset optimize for inverted IQ + +// SX127x series common FSK registers +// NOTE: FSK register names that are conflicting with LoRa registers are marked with "_FSK" suffix +#define RADIOLIB_SX127X_REG_BITRATE_MSB 0x02 +#define RADIOLIB_SX127X_REG_BITRATE_LSB 0x03 +#define RADIOLIB_SX127X_REG_FDEV_MSB 0x04 +#define RADIOLIB_SX127X_REG_FDEV_LSB 0x05 +#define RADIOLIB_SX127X_REG_RX_CONFIG 0x0D +#define RADIOLIB_SX127X_REG_RSSI_CONFIG 0x0E +#define RADIOLIB_SX127X_REG_RSSI_COLLISION 0x0F +#define RADIOLIB_SX127X_REG_RSSI_THRESH 0x10 +#define RADIOLIB_SX127X_REG_RSSI_VALUE_FSK 0x11 +#define RADIOLIB_SX127X_REG_RX_BW 0x12 +#define RADIOLIB_SX127X_REG_AFC_BW 0x13 +#define RADIOLIB_SX127X_REG_OOK_PEAK 0x14 +#define RADIOLIB_SX127X_REG_OOK_FIX 0x15 +#define RADIOLIB_SX127X_REG_OOK_AVG 0x16 +#define RADIOLIB_SX127X_REG_AFC_FEI 0x1A +#define RADIOLIB_SX127X_REG_AFC_MSB 0x1B +#define RADIOLIB_SX127X_REG_AFC_LSB 0x1C +#define RADIOLIB_SX127X_REG_FEI_MSB_FSK 0x1D +#define RADIOLIB_SX127X_REG_FEI_LSB_FSK 0x1E +#define RADIOLIB_SX127X_REG_PREAMBLE_DETECT 0x1F +#define RADIOLIB_SX127X_REG_RX_TIMEOUT_1 0x20 +#define RADIOLIB_SX127X_REG_RX_TIMEOUT_2 0x21 +#define RADIOLIB_SX127X_REG_RX_TIMEOUT_3 0x22 +#define RADIOLIB_SX127X_REG_RX_DELAY 0x23 +#define RADIOLIB_SX127X_REG_OSC 0x24 +#define RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK 0x25 +#define RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK 0x26 +#define RADIOLIB_SX127X_REG_SYNC_CONFIG 0x27 +#define RADIOLIB_SX127X_REG_SYNC_VALUE_1 0x28 +#define RADIOLIB_SX127X_REG_SYNC_VALUE_2 0x29 +#define RADIOLIB_SX127X_REG_SYNC_VALUE_3 0x2A +#define RADIOLIB_SX127X_REG_SYNC_VALUE_4 0x2B +#define RADIOLIB_SX127X_REG_SYNC_VALUE_5 0x2C +#define RADIOLIB_SX127X_REG_SYNC_VALUE_6 0x2D +#define RADIOLIB_SX127X_REG_SYNC_VALUE_7 0x2E +#define RADIOLIB_SX127X_REG_SYNC_VALUE_8 0x2F +#define RADIOLIB_SX127X_REG_PACKET_CONFIG_1 0x30 +#define RADIOLIB_SX127X_REG_PACKET_CONFIG_2 0x31 +#define RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK 0x32 +#define RADIOLIB_SX127X_REG_NODE_ADRS 0x33 +#define RADIOLIB_SX127X_REG_BROADCAST_ADRS 0x34 +#define RADIOLIB_SX127X_REG_FIFO_THRESH 0x35 +#define RADIOLIB_SX127X_REG_SEQ_CONFIG_1 0x36 +#define RADIOLIB_SX127X_REG_SEQ_CONFIG_2 0x37 +#define RADIOLIB_SX127X_REG_TIMER_RESOL 0x38 +#define RADIOLIB_SX127X_REG_TIMER1_COEF 0x39 +#define RADIOLIB_SX127X_REG_TIMER2_COEF 0x3A +#define RADIOLIB_SX127X_REG_IMAGE_CAL 0x3B +#define RADIOLIB_SX127X_REG_TEMP 0x3C +#define RADIOLIB_SX127X_REG_LOW_BAT 0x3D +#define RADIOLIB_SX127X_REG_IRQ_FLAGS_1 0x3E +#define RADIOLIB_SX127X_REG_IRQ_FLAGS_2 0x3F + +// SX127x common FSK modem settings +// RADIOLIB_SX127X_REG_OP_MODE +#define RADIOLIB_SX127X_MODULATION_FSK 0b00000000 // 6 5 FSK modulation scheme +#define RADIOLIB_SX127X_MODULATION_OOK 0b00100000 // 6 5 OOK modulation scheme +#define RADIOLIB_SX127X_RX 0b00000101 // 2 0 receiver mode + +// RADIOLIB_SX127X_REG_BITRATE_MSB + SX127X_REG_BITRATE_LSB +#define RADIOLIB_SX127X_BITRATE_MSB 0x1A // 7 0 bit rate setting: BitRate = F(XOSC)/(BITRATE + BITRATE_FRAC/16) +#define RADIOLIB_SX127X_BITRATE_LSB 0x0B // 7 0 default value: 4.8 kbps + +// RADIOLIB_SX127X_REG_FDEV_MSB + SX127X_REG_FDEV_LSB +#define RADIOLIB_SX127X_FDEV_MSB 0x00 // 5 0 frequency deviation: Fdev = Fstep * FDEV +#define RADIOLIB_SX127X_FDEV_LSB 0x52 // 7 0 default value: 5 kHz + +// RADIOLIB_SX127X_REG_RX_CONFIG +#define RADIOLIB_SX127X_RESTART_RX_ON_COLLISION_OFF 0b00000000 // 7 7 automatic receiver restart disabled (default) +#define RADIOLIB_SX127X_RESTART_RX_ON_COLLISION_ON 0b10000000 // 7 7 automatically restart receiver if it gets saturated or on packet collision +#define RADIOLIB_SX127X_RESTART_RX_WITHOUT_PLL_LOCK 0b01000000 // 6 6 manually restart receiver without frequency change +#define RADIOLIB_SX127X_RESTART_RX_WITH_PLL_LOCK 0b00100000 // 5 5 manually restart receiver with frequency change +#define RADIOLIB_SX127X_AFC_AUTO_OFF 0b00000000 // 4 4 no AFC performed (default) +#define RADIOLIB_SX127X_AFC_AUTO_ON 0b00010000 // 4 4 AFC performed at each receiver startup +#define RADIOLIB_SX127X_AGC_AUTO_OFF 0b00000000 // 3 3 LNA gain set manually by register +#define RADIOLIB_SX127X_AGC_AUTO_ON 0b00001000 // 3 3 LNA gain controlled by AGC +#define RADIOLIB_SX127X_RX_TRIGGER_NONE 0b00000000 // 2 0 receiver startup at: none +#define RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT 0b00000001 // 2 0 RSSI interrupt +#define RADIOLIB_SX127X_RX_TRIGGER_PREAMBLE_DETECT 0b00000110 // 2 0 preamble detected +#define RADIOLIB_SX127X_RX_TRIGGER_BOTH 0b00000111 // 2 0 RSSI interrupt and preamble detected + +// RADIOLIB_SX127X_REG_RSSI_CONFIG +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_2 0b00000000 // 2 0 number of samples for RSSI average: 2 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_4 0b00000001 // 2 0 4 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_8 0b00000010 // 2 0 8 (default) +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_16 0b00000011 // 2 0 16 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_32 0b00000100 // 2 0 32 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_64 0b00000101 // 2 0 64 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_128 0b00000110 // 2 0 128 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_256 0b00000111 // 2 0 256 + +// RADIOLIB_SX127X_REG_RSSI_COLLISION +#define RADIOLIB_SX127X_RSSI_COLLISION_THRESHOLD 0x0A // 7 0 RSSI threshold in dB that will be considered a collision, default value: 10 dB + +// RADIOLIB_SX127X_REG_RSSI_THRESH +#define RADIOLIB_SX127X_RSSI_THRESHOLD 0xFF // 7 0 RSSI threshold that will trigger RSSI interrupt, RssiThreshold = RSSI_THRESHOLD / 2 [dBm] + +// RADIOLIB_SX127X_REG_RX_BW +#define RADIOLIB_SX127X_RX_BW_MANT_16 0b00000000 // 4 3 channel filter bandwidth: RxBw = F(XOSC) / (RxBwMant * 2^(RxBwExp + 2)) [kHz] +#define RADIOLIB_SX127X_RX_BW_MANT_20 0b00001000 // 4 3 +#define RADIOLIB_SX127X_RX_BW_MANT_24 0b00010000 // 4 3 default RxBwMant parameter +#define RADIOLIB_SX127X_RX_BW_EXP 0b00000101 // 2 0 default RxBwExp parameter + +// RADIOLIB_SX127X_REG_AFC_BW +#define RADIOLIB_SX127X_RX_BW_MANT_AFC 0b00001000 // 4 3 default RxBwMant parameter used during AFC +#define RADIOLIB_SX127X_RX_BW_EXP_AFC 0b00000011 // 2 0 default RxBwExp parameter used during AFC + +// RADIOLIB_SX127X_REG_OOK_PEAK +#define RADIOLIB_SX127X_BIT_SYNC_OFF 0b00000000 // 5 5 bit synchronizer disabled (not allowed in packet mode) +#define RADIOLIB_SX127X_BIT_SYNC_ON 0b00100000 // 5 5 bit synchronizer enabled (default) +#define RADIOLIB_SX127X_OOK_THRESH_FIXED 0b00000000 // 4 3 OOK threshold type: fixed value +#define RADIOLIB_SX127X_OOK_THRESH_PEAK 0b00001000 // 4 3 peak mode (default) +#define RADIOLIB_SX127X_OOK_THRESH_AVERAGE 0b00010000 // 4 3 average mode +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_0_5_DB 0b00000000 // 2 0 OOK demodulator step size: 0.5 dB (default) +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_0_DB 0b00000001 // 2 0 1.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_5_DB 0b00000010 // 2 0 1.5 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_2_0_DB 0b00000011 // 2 0 2.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_3_0_DB 0b00000100 // 2 0 3.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_4_0_DB 0b00000101 // 2 0 4.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_5_0_DB 0b00000110 // 2 0 5.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_6_0_DB 0b00000111 // 2 0 6.0 dB + +// RADIOLIB_SX127X_REG_OOK_FIX +#define RADIOLIB_SX127X_OOK_FIXED_THRESHOLD 0x0C // 7 0 default fixed threshold for OOK data slicer + +// RADIOLIB_SX127X_REG_OOK_AVG +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_1_CHIP 0b00000000 // 7 5 OOK demodulator step period: once per chip (default) +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_2_CHIP 0b00100000 // 7 5 once every 2 chips +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_4_CHIP 0b01000000 // 7 5 once every 4 chips +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_8_CHIP 0b01100000 // 7 5 once every 8 chips +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_2_1_CHIP 0b10000000 // 7 5 2 times per chip +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_4_1_CHIP 0b10100000 // 7 5 4 times per chip +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_8_1_CHIP 0b11000000 // 7 5 8 times per chip +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_16_1_CHIP 0b11100000 // 7 5 16 times per chip +#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_0_DB 0b00000000 // 3 2 OOK average threshold offset: 0.0 dB (default) +#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_2_DB 0b00000100 // 3 2 2.0 dB +#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_4_DB 0b00001000 // 3 2 4.0 dB +#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_6_DB 0b00001100 // 3 2 6.0 dB +#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_32_PI 0b00000000 // 1 0 OOK average filter coefficient: chip rate / 32*pi +#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_8_PI 0b00000001 // 1 0 chip rate / 8*pi +#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_4_PI 0b00000010 // 1 0 chip rate / 4*pi (default) +#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_2_PI 0b00000011 // 1 0 chip rate / 2*pi + +// RADIOLIB_SX127X_REG_AFC_FEI +#define RADIOLIB_SX127X_AGC_START 0b00010000 // 4 4 manually start AGC sequence +#define RADIOLIB_SX127X_AFC_CLEAR 0b00000010 // 1 1 manually clear AFC register +#define RADIOLIB_SX127X_AFC_AUTO_CLEAR_OFF 0b00000000 // 0 0 AFC register will not be cleared at the start of AFC (default) +#define RADIOLIB_SX127X_AFC_AUTO_CLEAR_ON 0b00000001 // 0 0 AFC register will be cleared at the start of AFC + +// RADIOLIB_SX127X_REG_PREAMBLE_DETECT +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_OFF 0b00000000 // 7 7 preamble detection disabled +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_ON 0b10000000 // 7 7 preamble detection enabled (default) +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_1_BYTE 0b00000000 // 6 5 preamble detection size: 1 byte (default) +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_2_BYTE 0b00100000 // 6 5 2 bytes +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_3_BYTE 0b01000000 // 6 5 3 bytes +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_TOL 0x0A // 4 0 default number of tolerated errors per chip (4 chips per bit) + +// RADIOLIB_SX127X_REG_RX_TIMEOUT_1 +#define RADIOLIB_SX127X_TIMEOUT_RX_RSSI_OFF 0x00 // 7 0 disable receiver timeout when RSSI interrupt doesn't occur (default) + +// RADIOLIB_SX127X_REG_RX_TIMEOUT_2 +#define RADIOLIB_SX127X_TIMEOUT_RX_PREAMBLE_OFF 0x00 // 7 0 disable receiver timeout when preamble interrupt doesn't occur (default) + +// RADIOLIB_SX127X_REG_RX_TIMEOUT_3 +#define RADIOLIB_SX127X_TIMEOUT_SIGNAL_SYNC_OFF 0x00 // 7 0 disable receiver timeout when sync address interrupt doesn't occur (default) + +// RADIOLIB_SX127X_REG_OSC +#define RADIOLIB_SX127X_RC_CAL_START 0b00000000 // 3 3 manually start RC oscillator calibration +#define RADIOLIB_SX127X_CLK_OUT_FXOSC 0b00000000 // 2 0 ClkOut frequency: F(XOSC) +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_2 0b00000001 // 2 0 F(XOSC) / 2 +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_4 0b00000010 // 2 0 F(XOSC) / 4 +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_8 0b00000011 // 2 0 F(XOSC) / 8 +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_16 0b00000100 // 2 0 F(XOSC) / 16 +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_32 0b00000101 // 2 0 F(XOSC) / 32 +#define RADIOLIB_SX127X_CLK_OUT_RC 0b00000110 // 2 0 RC +#define RADIOLIB_SX127X_CLK_OUT_OFF 0b00000111 // 2 0 disabled (default) + +// RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK + SX127X_REG_PREAMBLE_LSB_FSK +#define RADIOLIB_SX127X_PREAMBLE_SIZE_MSB 0x00 // 7 0 preamble size in bytes +#define RADIOLIB_SX127X_PREAMBLE_SIZE_LSB 0x03 // 7 0 default value: 3 bytes + +// RADIOLIB_SX127X_REG_SYNC_CONFIG +#define RADIOLIB_SX127X_AUTO_RESTART_RX_MODE_OFF 0b00000000 // 7 6 Rx mode restart after packet reception: disabled +#define RADIOLIB_SX127X_AUTO_RESTART_RX_MODE_NO_PLL 0b01000000 // 7 6 enabled, don't wait for PLL lock +#define RADIOLIB_SX127X_AUTO_RESTART_RX_MODE_PLL 0b10000000 // 7 6 enabled, wait for PLL lock (default) +#define RADIOLIB_SX127X_PREAMBLE_POLARITY_AA 0b00000000 // 5 5 preamble polarity: 0xAA = 0b10101010 (default) +#define RADIOLIB_SX127X_PREAMBLE_POLARITY_55 0b00100000 // 5 5 0x55 = 0b01010101 +#define RADIOLIB_SX127X_SYNC_OFF 0b00000000 // 4 4 sync word disabled +#define RADIOLIB_SX127X_SYNC_ON 0b00010000 // 4 4 sync word enabled (default) +#define RADIOLIB_SX127X_SYNC_SIZE 0x03 // 2 0 sync word size in bytes, SyncSize = SYNC_SIZE + 1 bytes + +// RADIOLIB_SX127X_REG_SYNC_VALUE_1 - SX127X_REG_SYNC_VALUE_8 +#define RADIOLIB_SX127X_SYNC_VALUE_1 0x01 // 7 0 sync word: 1st byte (MSB) +#define RADIOLIB_SX127X_SYNC_VALUE_2 0x01 // 7 0 2nd byte +#define RADIOLIB_SX127X_SYNC_VALUE_3 0x01 // 7 0 3rd byte +#define RADIOLIB_SX127X_SYNC_VALUE_4 0x01 // 7 0 4th byte +#define RADIOLIB_SX127X_SYNC_VALUE_5 0x01 // 7 0 5th byte +#define RADIOLIB_SX127X_SYNC_VALUE_6 0x01 // 7 0 6th byte +#define RADIOLIB_SX127X_SYNC_VALUE_7 0x01 // 7 0 7th byte +#define RADIOLIB_SX127X_SYNC_VALUE_8 0x01 // 7 0 8th byte (LSB) + +// RADIOLIB_SX127X_REG_PACKET_CONFIG_1 +#define RADIOLIB_SX127X_PACKET_FIXED 0b00000000 // 7 7 packet format: fixed length +#define RADIOLIB_SX127X_PACKET_VARIABLE 0b10000000 // 7 7 variable length (default) +#define RADIOLIB_SX127X_DC_FREE_NONE 0b00000000 // 6 5 DC-free encoding: disabled (default) +#define RADIOLIB_SX127X_DC_FREE_MANCHESTER 0b00100000 // 6 5 Manchester +#define RADIOLIB_SX127X_DC_FREE_WHITENING 0b01000000 // 6 5 Whitening +#define RADIOLIB_SX127X_CRC_OFF 0b00000000 // 4 4 CRC disabled +#define RADIOLIB_SX127X_CRC_ON 0b00010000 // 4 4 CRC enabled (default) +#define RADIOLIB_SX127X_CRC_AUTOCLEAR_OFF 0b00001000 // 3 3 keep FIFO on CRC mismatch, issue payload ready interrupt +#define RADIOLIB_SX127X_CRC_AUTOCLEAR_ON 0b00000000 // 3 3 clear FIFO on CRC mismatch, do not issue payload ready interrupt +#define RADIOLIB_SX127X_ADDRESS_FILTERING_OFF 0b00000000 // 2 1 address filtering: none (default) +#define RADIOLIB_SX127X_ADDRESS_FILTERING_NODE 0b00000010 // 2 1 node +#define RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST 0b00000100 // 2 1 node or broadcast +#define RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT 0b00000000 // 0 0 CRC and whitening algorithms: CCITT CRC with standard whitening (default) +#define RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM 0b00000001 // 0 0 IBM CRC with alternate whitening + +// RADIOLIB_SX127X_REG_PACKET_CONFIG_2 +#define RADIOLIB_SX127X_DATA_MODE_PACKET 0b01000000 // 6 6 data mode: packet (default) +#define RADIOLIB_SX127X_DATA_MODE_CONTINUOUS 0b00000000 // 6 6 continuous +#define RADIOLIB_SX127X_IO_HOME_OFF 0b00000000 // 5 5 io-homecontrol compatibility disabled (default) +#define RADIOLIB_SX127X_IO_HOME_ON 0b00100000 // 5 5 io-homecontrol compatibility enabled + +// RADIOLIB_SX127X_REG_FIFO_THRESH +#define RADIOLIB_SX127X_TX_START_FIFO_LEVEL 0b00000000 // 7 7 start packet transmission when: number of bytes in FIFO exceeds FIFO_THRESHOLD +#define RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY 0b10000000 // 7 7 at least one byte in FIFO (default) +#define RADIOLIB_SX127X_FIFO_THRESH 0x1F // 5 0 FIFO level threshold + +// RADIOLIB_SX127X_REG_SEQ_CONFIG_1 +#define RADIOLIB_SX127X_SEQUENCER_START 0b10000000 // 7 7 manually start sequencer +#define RADIOLIB_SX127X_SEQUENCER_STOP 0b01000000 // 6 6 manually stop sequencer +#define RADIOLIB_SX127X_IDLE_MODE_STANDBY 0b00000000 // 5 5 chip mode during sequencer idle mode: standby (default) +#define RADIOLIB_SX127X_IDLE_MODE_SLEEP 0b00100000 // 5 5 sleep +#define RADIOLIB_SX127X_FROM_START_LP_SELECTION 0b00000000 // 4 3 mode that will be set after starting sequencer: low power selection (default) +#define RADIOLIB_SX127X_FROM_START_RECEIVE 0b00001000 // 4 3 receive +#define RADIOLIB_SX127X_FROM_START_TRANSMIT 0b00010000 // 4 3 transmit +#define RADIOLIB_SX127X_FROM_START_TRANSMIT_FIFO_LEVEL 0b00011000 // 4 3 transmit on a FIFO level interrupt +#define RADIOLIB_SX127X_LP_SELECTION_SEQ_OFF 0b00000000 // 2 2 mode that will be set after exiting low power selection: sequencer off (default) +#define RADIOLIB_SX127X_LP_SELECTION_IDLE 0b00000100 // 2 2 idle state +#define RADIOLIB_SX127X_FROM_IDLE_TRANSMIT 0b00000000 // 1 1 mode that will be set after exiting idle mode: transmit (default) +#define RADIOLIB_SX127X_FROM_IDLE_RECEIVE 0b00000010 // 1 1 receive +#define RADIOLIB_SX127X_FROM_TRANSMIT_LP_SELECTION 0b00000000 // 0 0 mode that will be set after exiting transmit mode: low power selection (default) +#define RADIOLIB_SX127X_FROM_TRANSMIT_RECEIVE 0b00000001 // 0 0 receive + +// RADIOLIB_SX127X_REG_SEQ_CONFIG_2 +#define RADIOLIB_SX127X_FROM_RECEIVE_PACKET_RECEIVED_PAYLOAD 0b00100000 // 7 5 mode that will be set after exiting receive mode: packet received on payload ready interrupt (default) +#define RADIOLIB_SX127X_FROM_RECEIVE_LP_SELECTION 0b01000000 // 7 5 low power selection +#define RADIOLIB_SX127X_FROM_RECEIVE_PACKET_RECEIVED_CRC_OK 0b01100000 // 7 5 packet received on CRC OK interrupt +#define RADIOLIB_SX127X_FROM_RECEIVE_SEQ_OFF_RSSI 0b10000000 // 7 5 sequencer off on RSSI interrupt +#define RADIOLIB_SX127X_FROM_RECEIVE_SEQ_OFF_SYNC_ADDR 0b10100000 // 7 5 sequencer off on sync address interrupt +#define RADIOLIB_SX127X_FROM_RECEIVE_SEQ_OFF_PREAMBLE_DETECT 0b11000000 // 7 5 sequencer off on preamble detect interrupt +#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_RECEIVE 0b00000000 // 4 3 mode that will be set after Rx timeout: receive (default) +#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_TRANSMIT 0b00001000 // 4 3 transmit +#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_LP_SELECTION 0b00010000 // 4 3 low power selection +#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_SEQ_OFF 0b00011000 // 4 3 sequencer off +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_SEQ_OFF 0b00000000 // 2 0 mode that will be set after packet received: sequencer off (default) +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_TRANSMIT 0b00000001 // 2 0 transmit +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_LP_SELECTION 0b00000010 // 2 0 low power selection +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_RECEIVE_FS 0b00000011 // 2 0 receive via FS +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_RECEIVE 0b00000100 // 2 0 receive + +// RADIOLIB_SX127X_REG_TIMER_RESOL +#define RADIOLIB_SX127X_TIMER1_OFF 0b00000000 // 3 2 timer 1 resolution: disabled (default) +#define RADIOLIB_SX127X_TIMER1_RESOLUTION_64_US 0b00000100 // 3 2 64 us +#define RADIOLIB_SX127X_TIMER1_RESOLUTION_4_1_MS 0b00001000 // 3 2 4.1 ms +#define RADIOLIB_SX127X_TIMER1_RESOLUTION_262_MS 0b00001100 // 3 2 262 ms +#define RADIOLIB_SX127X_TIMER2_OFF 0b00000000 // 3 2 timer 2 resolution: disabled (default) +#define RADIOLIB_SX127X_TIMER2_RESOLUTION_64_US 0b00000001 // 3 2 64 us +#define RADIOLIB_SX127X_TIMER2_RESOLUTION_4_1_MS 0b00000010 // 3 2 4.1 ms +#define RADIOLIB_SX127X_TIMER2_RESOLUTION_262_MS 0b00000011 // 3 2 262 ms + +// RADIOLIB_SX127X_REG_TIMER1_COEF +#define RADIOLIB_SX127X_TIMER1_COEFFICIENT 0xF5 // 7 0 multiplication coefficient for timer 1 + +// RADIOLIB_SX127X_REG_TIMER2_COEF +#define RADIOLIB_SX127X_TIMER2_COEFFICIENT 0x20 // 7 0 multiplication coefficient for timer 2 + +// RADIOLIB_SX127X_REG_IMAGE_CAL +#define RADIOLIB_SX127X_AUTO_IMAGE_CAL_OFF 0b00000000 // 7 7 temperature calibration disabled (default) +#define RADIOLIB_SX127X_AUTO_IMAGE_CAL_ON 0b10000000 // 7 7 temperature calibration enabled +#define RADIOLIB_SX127X_IMAGE_CAL_START 0b01000000 // 6 6 start temperature calibration +#define RADIOLIB_SX127X_IMAGE_CAL_RUNNING 0b00100000 // 5 5 temperature calibration is on-going +#define RADIOLIB_SX127X_IMAGE_CAL_COMPLETE 0b00000000 // 5 5 temperature calibration finished +#define RADIOLIB_SX127X_TEMP_CHANGED 0b00001000 // 3 3 temperature changed more than TEMP_THRESHOLD since last calibration +#define RADIOLIB_SX127X_TEMP_THRESHOLD_5_DEG_C 0b00000000 // 2 1 temperature change threshold: 5 deg. C +#define RADIOLIB_SX127X_TEMP_THRESHOLD_10_DEG_C 0b00000010 // 2 1 10 deg. C (default) +#define RADIOLIB_SX127X_TEMP_THRESHOLD_15_DEG_C 0b00000100 // 2 1 15 deg. C +#define RADIOLIB_SX127X_TEMP_THRESHOLD_20_DEG_C 0b00000110 // 2 1 20 deg. C +#define RADIOLIB_SX127X_TEMP_MONITOR_ON 0b00000000 // 0 0 temperature monitoring enabled (default) +#define RADIOLIB_SX127X_TEMP_MONITOR_OFF 0b00000001 // 0 0 temperature monitoring disabled + +// RADIOLIB_SX127X_REG_LOW_BAT +#define RADIOLIB_SX127X_LOW_BAT_OFF 0b00000000 // 3 3 low battery detector disabled +#define RADIOLIB_SX127X_LOW_BAT_ON 0b00001000 // 3 3 low battery detector enabled +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_1_695_V 0b00000000 // 2 0 battery voltage threshold: 1.695 V +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_1_764_V 0b00000001 // 2 0 1.764 V +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_1_835_V 0b00000010 // 2 0 1.835 V (default) +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_1_905_V 0b00000011 // 2 0 1.905 V +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_1_976_V 0b00000100 // 2 0 1.976 V +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_2_045_V 0b00000101 // 2 0 2.045 V +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_2_116_V 0b00000110 // 2 0 2.116 V +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_2_185_V 0b00000111 // 2 0 2.185 V + +// RADIOLIB_SX127X_REG_IRQ_FLAGS_1 +#define RADIOLIB_SX127X_FLAG_MODE_READY 0b10000000 // 7 7 requested mode is ready +#define RADIOLIB_SX127X_FLAG_RX_READY 0b01000000 // 6 6 reception ready (after RSSI, AGC, AFC) +#define RADIOLIB_SX127X_FLAG_TX_READY 0b00100000 // 5 5 transmission ready (after PA ramp-up) +#define RADIOLIB_SX127X_FLAG_PLL_LOCK 0b00010000 // 4 4 PLL locked +#define RADIOLIB_SX127X_FLAG_RSSI 0b00001000 // 3 3 RSSI value exceeds RSSI threshold +#define RADIOLIB_SX127X_FLAG_TIMEOUT 0b00000100 // 2 2 timeout occurred +#define RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT 0b00000010 // 1 1 valid preamble was detected +#define RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH 0b00000001 // 0 0 sync address matched + +// RADIOLIB_SX127X_REG_IRQ_FLAGS_2 +#define RADIOLIB_SX127X_FLAG_FIFO_FULL 0b10000000 // 7 7 FIFO is full +#define RADIOLIB_SX127X_FLAG_FIFO_EMPTY 0b01000000 // 6 6 FIFO is empty +#define RADIOLIB_SX127X_FLAG_FIFO_LEVEL 0b00100000 // 5 5 number of bytes in FIFO exceeds FIFO_THRESHOLD +#define RADIOLIB_SX127X_FLAG_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occurred +#define RADIOLIB_SX127X_FLAG_PACKET_SENT 0b00001000 // 3 3 packet was successfully sent +#define RADIOLIB_SX127X_FLAG_PAYLOAD_READY 0b00000100 // 2 2 packet was successfully received +#define RADIOLIB_SX127X_FLAG_CRC_OK 0b00000010 // 1 1 CRC check passed +#define RADIOLIB_SX127X_FLAG_LOW_BAT 0b00000001 // 0 0 battery voltage dropped below threshold + +// RADIOLIB_SX127X_REG_DIO_MAPPING_1 +#define RADIOLIB_SX127X_DIO0_LORA_RX_DONE 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_LORA_TX_DONE 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_LORA_CAD_DONE 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_RSSI_PREAMBLE_DETECT 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_RX_READY 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_TX_READY 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_PACK_CRC_OK 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_PACK_TEMP_CHANGE_LOW_BAT 0b11000000 // 7 6 +#define RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED 0b00100000 // 5 4 +#define RADIOLIB_SX127X_DIO1_CONT_DCLK 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO1_CONT_RSSI_PREAMBLE_DETECT 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO1_PACK_FIFO_FULL 0b00100000 // 5 4 +#define RADIOLIB_SX127X_DIO2_LORA_FHSS_CHANGE_CHANNEL 0b00000000 // 3 2 +#define RADIOLIB_SX127X_DIO2_CONT_DATA 0b00000000 // 3 2 +#define RADIOLIB_SX127X_DIO2_PACK_FIFO_FULL 0b00000000 // 3 2 +#define RADIOLIB_SX127X_DIO2_PACK_RX_READY 0b00000100 // 3 2 +#define RADIOLIB_SX127X_DIO2_PACK_TIMEOUT 0b00001000 // 3 2 +#define RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS 0b00011000 // 3 2 +#define RADIOLIB_SX127X_DIO3_LORA_CAD_DONE 0b00000000 // 1 0 +#define RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER 0b00000001 // 1 0 +#define RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR 0b00000010 // 1 0 +#define RADIOLIB_SX127X_DIO3_CONT_TIMEOUT 0b00000000 // 1 0 +#define RADIOLIB_SX127X_DIO3_CONT_RSSI_PREAMBLE_DETECT 0b00000001 // 1 0 +#define RADIOLIB_SX127X_DIO3_CONT_TEMP_CHANGE_LOW_BAT 0b00000011 // 1 0 +#define RADIOLIB_SX127X_DIO3_PACK_FIFO_EMPTY 0b00000000 // 1 0 +#define RADIOLIB_SX127X_DIO3_PACK_TX_READY 0b00000001 // 1 0 + +// RADIOLIB_SX127X_REG_DIO_MAPPING_2 +#define RADIOLIB_SX127X_DIO4_LORA_CAD_DETECTED 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_LORA_PLL_LOCK 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_CONT_TEMP_CHANGE_LOW_BAT 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_CONT_PLL_LOCK 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_CONT_TIMEOUT 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_PACK_TEMP_CHANGE_LOW_BAT 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_PACK_PLL_LOCK 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_PACK_TIMEOUT 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_PACK_RSSI_PREAMBLE_DETECT 0b11000000 // 7 6 +#define RADIOLIB_SX127X_DIO5_LORA_MODE_READY 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO5_LORA_CLK_OUT 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO5_CONT_PLL_LOCK 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO5_CONT_RSSI_PREAMBLE_DETECT 0b00100000 // 5 4 +#define RADIOLIB_SX127X_DIO5_CONT_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX127X_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO5_PACK_PLL_LOCK 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO5_PACK_DATA 0b00100000 // 5 4 +#define RADIOLIB_SX127X_DIO5_PACK_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX127X_DIO_MAP_PREAMBLE_DETECT 0b00000001 // 0 0 +#define RADIOLIB_SX127X_DIO_MAP_RSSI 0b00000000 // 0 0 + +// SX1272_REG_PLL_HOP + SX1278_REG_PLL_HOP +#define RADIOLIB_SX127X_FAST_HOP_OFF 0b00000000 // 7 7 carrier frequency validated when FRF registers are written +#define RADIOLIB_SX127X_FAST_HOP_ON 0b10000000 // 7 7 carrier frequency validated when FS modes are requested + +// SX1272_REG_TCXO + SX1278_REG_TCXO +#define RADIOLIB_SX127X_TCXO_INPUT_EXTERNAL 0b00000000 // 4 4 use external crystal oscillator +#define RADIOLIB_SX127X_TCXO_INPUT_EXTERNAL_CLIPPED 0b00010000 // 4 4 use external crystal oscillator clipped sine connected to XTA pin + +// SX1272_REG_PLL + SX1278_REG_PLL +#define RADIOLIB_SX127X_PLL_BANDWIDTH_75_KHZ 0b00000000 // 7 6 PLL bandwidth: 75 kHz +#define RADIOLIB_SX127X_PLL_BANDWIDTH_150_KHZ 0b01000000 // 7 6 150 kHz +#define RADIOLIB_SX127X_PLL_BANDWIDTH_225_KHZ 0b10000000 // 7 6 225 kHz +#define RADIOLIB_SX127X_PLL_BANDWIDTH_300_KHZ 0b11000000 // 7 6 300 kHz (default) + +/*! + \class SX127x + \brief Base class for SX127x series. All derived classes for SX127x (e.g. SX1278 or SX1272) inherit from this base class. + This class should not be instantiated directly from Arduino sketch, only from its derived classes. +*/ +class SX127x: public PhysicalLayer { + public: + // introduce PhysicalLayer overloads + using PhysicalLayer::transmit; + using PhysicalLayer::receive; + using PhysicalLayer::startTransmit; + using PhysicalLayer::readData; + + // constructor + + /*! + \brief Default constructor. Called internally when creating new LoRa instance. + \param mod Instance of Module that will be used to communicate with the %LoRa chip. + */ + SX127x(Module* mod); + + // basic methods + + /*! + \brief Initialization method. Will be called with appropriate parameters when calling initialization method from derived class. + \param chipVersion Array of possible values in SPI version register. Used to verify the connection and hardware version. + \param numVersions Number of possible chip versions. + \param syncWord %LoRa sync word. + \param preambleLength Length of %LoRa transmission preamble in symbols. + \returns \ref status_codes + */ + int16_t begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength); + + /*! + \brief Reset method. Will reset the chip to the default state using RST pin. Declared pure virtual since SX1272 and SX1278 implementations differ. + */ + virtual void reset() = 0; + + /*! + \brief Initialization method for FSK modem. Will be called with appropriate parameters when calling FSK initialization method from derived class. + \param chipVersion Array of possible values in SPI version register. Used to verify the connection and hardware version. + \param numVersions Number of possible chip versions. + \param freqDev Frequency deviation of the FSK transmission in kHz. + \param rxBw Receiver bandwidth in kHz. + \param preambleLength Length of FSK preamble in bits. + \param enableOOK Flag to specify OOK mode. This modulation is similar to FSK. + \returns \ref status_codes + */ + int16_t beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK); + + /*! + \brief Binary transmit method. Will transmit arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. + For overloads to transmit Arduino String or C-string, see PhysicalLayer::transmit. + \param data Binary data that will be transmitted. + \param len Length of binary data to transmit (in bytes). + \param addr Node address to transmit the packet to. Only used in FSK mode. + \returns \ref status_codes + */ + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Binary receive method. Will attempt to receive arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. + For overloads to receive Arduino String, see PhysicalLayer::receive. + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \returns \ref status_codes + */ + int16_t receive(uint8_t* data, size_t len) override; + + /*! + \brief Performs scan for valid %LoRa preamble in the current channel. + \returns \ref status_codes + */ + int16_t scanChannel() override; + + /*! + \brief Sets the %LoRa module to sleep to save power. %Module will not be able to transmit or receive any data while in sleep mode. + %Module will wake up automatically when methods like transmit or receive are called. + \returns \ref status_codes + */ + int16_t sleep(); + + /*! + \brief Sets the %LoRa module to standby. + \returns \ref status_codes + */ + int16_t standby() override; + + /*! + \brief Sets the %LoRa module to standby. + \param mode Standby mode to be used. No effect, implemented only for PhysicalLayer compatibility. + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + + /*! + \brief Enables direct transmission mode on pins DIO1 (clock) and DIO2 (data). + While in direct mode, the module will not be able to transmit or receive packets. Can only be activated in FSK mode. + \param frf 24-bit raw frequency value to start transmitting at. Required for quick frequency shifts in RTTY. + \returns \ref status_codes + */ + int16_t transmitDirect(uint32_t frf = 0) override; + + /*! + \brief Enables direct reception mode on pins DIO1 (clock) and DIO2 (data). + While in direct mode, the module will not be able to transmit or receive packets. Can only be activated in FSK mode. + \returns \ref status_codes + */ + int16_t receiveDirect() override; + + /*! + \brief Disables direct mode and enables packet mode, allowing the module to receive packets. Can only be activated in FSK mode. + \returns \ref status_codes + */ + int16_t packetMode(); + + // interrupt methods + + /*! + \brief Set interrupt service routine function to call when DIO0 activates. + \param func Pointer to interrupt service routine. + \param dir Signal change direction. + */ + void setDio0Action(void (*func)(void), uint32_t dir); + + /*! + \brief Clears interrupt service routine to call when DIO0 activates. + */ + void clearDio0Action(); + + /*! + \brief Set interrupt service routine function to call when DIO1 activates. + \param func Pointer to interrupt service routine. + \param dir Signal change direction. + */ + void setDio1Action(void (*func)(void), uint32_t dir); + + /*! + \brief Clears interrupt service routine to call when DIO1 activates. + */ + void clearDio1Action(); + + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + + /*! + \brief Sets interrupt service routine to call when a channel scan is finished. + \param func ISR to call. + */ + void setChannelScanAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a channel scan is finished. + */ + void clearChannelScanAction(); + + /*! + \brief Set interrupt service routine function to call when FIFO is empty. + \param func Pointer to interrupt service routine. + */ + void setFifoEmptyAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when FIFO is empty. + */ + void clearFifoEmptyAction(); + + /*! + \brief Set interrupt service routine function to call when FIFO is full. + \param func Pointer to interrupt service routine. + */ + void setFifoFullAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when FIFO is full. + */ + void clearFifoFullAction(); + + /*! + \brief Set interrupt service routine function to call when FIFO is empty. + \param data Pointer to the transmission buffer. + \param totalLen Total number of bytes to transmit. + \param remLen Pointer to a counter holding the number of bytes that have been transmitted so far. + \returns True when a complete packet is sent, false if more data is needed. + */ + bool fifoAdd(uint8_t* data, int totalLen, int* remLen); + + /*! + \brief Set interrupt service routine function to call when FIFO is sufficiently full to read. + \param data Pointer to a buffer that stores the receive data. + \param totalLen Total number of bytes to receive. + \param rcvLen Pointer to a counter holding the number of bytes that have been received so far. + \returns True when a complete packet is received, false if more data is needed. + */ + bool fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen); + + /*! + \brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. + \param data Binary data that will be transmitted. + \param len Length of binary data to transmit (in bytes). + \param addr Node address to transmit the packet to. Only used in FSK mode. + \returns \ref status_codes + */ + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Clean up after transmission is done. + \returns \ref status_codes + */ + int16_t finishTransmit() override; + + /*! + \brief Interrupt-driven receive method with default parameters. + Implemented for compatibility with PhysicalLayer. + \returns \ref status_codes + */ + int16_t startReceive(); + + /*! + \brief Interrupt-driven receive method. DIO0 will be activated when full valid packet is received. + \param len Expected length of packet to be received, or 0 when unused. + Defaults to 0, non-zero required for LoRa spreading factor 6. + \param mode Receive mode to be used. Defaults to RxContinuous. + \returns \ref status_codes + */ + int16_t startReceive(uint8_t len, uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS); + + /*! + \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. + \param timeout Receive mode type and/or raw timeout value in symbols. + When set to 0, the timeout will be infinite and the device will remain + in Rx mode until explicitly commanded to stop (Rx continuous mode). + When non-zero (maximum 1023), the device will be set to Rx single mode and timeout will be set. + \param irqFlags Ignored. + \param irqMask Ignored. + \param len Expected length of packet to be received. Required for LoRa spreading factor 6. + \returns \ref status_codes + */ + int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + + /*! + \brief Reads data that was received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. + \returns \ref status_codes + */ + int16_t readData(uint8_t* data, size_t len) override; + + /*! + \brief Interrupt-driven channel activity detection method. DIO0 will be activated when LoRa preamble is detected. + DIO1 will be activated if there's no preamble detected before timeout. + \returns \ref status_codes + */ + int16_t startChannelScan() override; + + /*! + \brief Read the channel scan result. + \returns \ref status_codes + */ + int16_t getChannelScanResult() override; + + // configuration methods + + /*! + \brief Sets %LoRa sync word. Only available in %LoRa mode. + \param syncWord Sync word to be set. + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t syncWord); + + /*! + \brief Sets current limit for over current protection at transmitter amplifier. Allowed values range from 45 to 120 mA in 5 mA steps and 120 to 240 mA in 10 mA steps. + \param currentLimit Current limit to be set (in mA). + \returns \ref status_codes + */ + int16_t setCurrentLimit(uint8_t currentLimit); + + /*! + \brief Sets %LoRa or FSK preamble length. Allowed values range from 6 to 65535 in %LoRa mode or 0 to 65535 in FSK mode. + \param preambleLength Preamble length to be set (in symbols when in LoRa mode or bits in FSK mode). + \returns \ref status_codes + */ + int16_t setPreambleLength(size_t preambleLength) override; + + /*! + \brief Invert FSK preamble polarity. The default (non-inverted) is 0x55, the inverted is 0xAA. + \param enable Preamble polarity in FSK mode - 0xAA when true, 0x55 when false. + \returns \ref status_codes + */ + int16_t invertPreamble(bool enable); + + /*! + \brief Gets frequency error of the latest received packet. + \param autoCorrect When set to true, frequency will be automatically corrected. + \returns Frequency error in Hz. + */ + float getFrequencyError(bool autoCorrect = false); + + /*! + \brief Gets current AFC error. + \returns Frequency offset from RF in Hz if AFC is enabled and triggered, zero otherwise. + */ + float getAFCError(); + + /*! + \brief Gets signal-to-noise ratio of the latest received packet. Only available in LoRa mode. + \returns Last packet signal-to-noise ratio (SNR). + */ + float getSNR(); + + /*! + \brief Get data rate of the latest transmitted packet. + \returns Last packet data rate in bps (bits per second). + */ + float getDataRate() const; + + /*! + \brief Sets FSK frequency deviation from carrier frequency. Allowed values depend on bit rate setting and must be lower than 200 kHz. Only available in FSK mode. + \param freqDev Frequency deviation to be set (in kHz). + \returns \ref status_codes + */ + int16_t setFrequencyDeviation(float freqDev) override; + + /*! + \brief Sets FSK receiver bandwidth. Allowed values range from 2.6 to 250 kHz. Only available in FSK mode. + \param rxBw Receiver bandwidth to be set (in kHz). + \returns \ref status_codes + */ + int16_t setRxBandwidth(float rxBw); + + /*! + \brief Sets FSK automatic frequency correction bandwidth. Allowed values range from 2.6 to 250 kHz. Only available in FSK mode. + \param rxBw Receiver AFC bandwidth to be set (in kHz). + \returns \ref status_codes + */ + int16_t setAFCBandwidth(float afcBw); + + /*! + \brief Enables or disables FSK automatic frequency correction(AFC) + \param isEnabled AFC enabled or disabled + \return \ref status_codes + */ + int16_t setAFC(bool isEnabled); + + /*! + \brief Controls trigger of AFC and AGC + \param trigger one from SX127X_RX_TRIGGER_NONE, SX127X_RX_TRIGGER_RSSI_INTERRUPT, SX127X_RX_TRIGGER_PREAMBLE_DETECT, SX127X_RX_TRIGGER_BOTH + \return \ref status_codes + */ + int16_t setAFCAGCTrigger(uint8_t trigger); + + /*! + \brief Sets FSK sync word. Allowed sync words are up to 8 bytes long and can not contain null bytes. Only available in FSK mode. + \param syncWord Sync word array. + \param len Sync word length (in bytes). + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t* syncWord, size_t len) override; + + /*! + \brief Sets FSK node address. Calling this method will enable address filtering. Only available in FSK mode. + \param nodeAddr Node address to be set. + \returns \ref status_codes + */ + int16_t setNodeAddress(uint8_t nodeAddr); + + /*! + \brief Sets FSK broadcast address. Calling this method will enable address filtering. Only available in FSK mode. + \param broadAddr Broadcast address to be set. + \returns \ref status_codes + */ + int16_t setBroadcastAddress(uint8_t broadAddr); + + /*! + \brief Disables FSK address filtering. + \returns \ref status_codes + */ + int16_t disableAddressFiltering(); + + /*! + \brief Enables/disables OOK modulation instead of FSK. + \param enableOOK Enable (true) or disable (false) OOK. + \returns \ref status_codes + */ + int16_t setOOK(bool enableOOK); + + /*! + \brief Selects the type of threshold in the OOK data slicer. + \param type Threshold type: SX127X_OOK_THRESH_PEAK(default), SX127X_OOK_THRESH_FIXED, SX127X_OOK_THRESH_AVERAGE + \returns \ref status_codes + */ + int16_t setOokThresholdType(uint8_t type); + + /*! + \brief Period of decrement of the RSSI threshold in the OOK demodulator. + \param value Use defines RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_X_X_CHIP + \returns \ref status_codes + */ + int16_t setOokPeakThresholdDecrement(uint8_t value); + + /*! + \brief Fixed threshold for the Data Slicer in OOK mode or floor threshold for the Data Slicer in OOK when Peak mode is used. + \param value Threshold level in steps of 0.5 dB. + \returns \ref status_codes + */ + int16_t setOokFixedOrFloorThreshold(uint8_t value); + + /*! + \brief Size of each decrement of the RSSI threshold in the OOK demodulator. + \param value Step size: RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_0_5_DB (default), RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_5_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_2_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_3_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_4_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_5_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_6_0_DB + \returns \ref status_codes + */ + int16_t setOokPeakThresholdStep(uint8_t value); + + /*! + \brief Enable Bit synchronizer. + \returns \ref status_codes + */ + int16_t enableBitSync(); + + /*! + \brief Disable Bit synchronizer (not allowed in Packet mode). + \returns \ref status_codes + */ + int16_t disableBitSync(); + + /*! + \brief Query modem for the packet length of received payload. + \param update Update received packet length. Will return cached value when set to false. + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update = true) override; + + /*! + \brief Set modem in fixed packet length mode. Available in FSK mode only. + \param len Packet length. + \returns \ref status_codes + */ + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK); + + /*! + \brief Set modem in variable packet length mode. Available in FSK mode only. + \param len Maximum packet length. + \returns \ref status_codes + */ + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK); + + /*! + \brief Convert from bytes to LoRa symbols. + \param len Payload length in bytes. + \returns The total number of LoRa symbols, including preamble, sync and possible header. + */ + float getNumSymbols(size_t len); + + /*! + \brief Get expected time-on-air for a given size of payload. + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + uint32_t getTimeOnAir(size_t len) override; + + /*! + \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) + \param timeoutUs Timeout in microseconds to listen for + \returns Timeout value in a unit that is specific for the used module + */ + uint32_t calculateRxTimeout(uint32_t timeoutUs); + + /*! + \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks + \param irqFlags The flags for which IRQs must be triggered + \param irqMask Mask indicating which IRQ triggers a DIO + \returns \ref status_codes + */ + int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask); + + /*! + \brief Check whether the IRQ bit for RxTimeout is set + \returns \ref RxTimeout IRQ is set + */ + bool isRxTimeout(); + + /*! + \brief Enable CRC filtering and generation. + \param enable Set or unset CRC filtering and generation. + \returns \ref status_codes + */ + int16_t setCrcFiltering(bool enable = true); + + /*! + \brief Sets RSSI measurement configuration in FSK mode. + \param smoothingSamples Number of samples taken to average the RSSI result. + numSamples = 2 ^ (1 + smoothingSamples), allowed values are in range 0 (2 samples) - 7 (256 samples) + \param offset Signed RSSI offset that will be automatically compensated. 1 dB per LSB, defaults to 0, allowed values are in range -16 dB to +15 dB. + \returns \ref status_codes + */ + int16_t setRSSIConfig(uint8_t smoothingSamples, int8_t offset = 0); + + /*! + \brief Sets transmission encoding. Only available in FSK mode. + Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER and RADIOLIB_ENCODING_WHITENING. + \param encoding Encoding to be used. + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding) override; + + /*! + \brief Reads currently active IRQ flags, can be used to check which event caused an interrupt. + In LoRa mode, this is the content of SX127X_REG_IRQ_FLAGS register. + In FSK mode, this is the contents of SX127X_REG_IRQ_FLAGS_2 (MSB) and SX127X_REG_IRQ_FLAGS_1 (LSB) registers. + \returns IRQ flags. + */ + uint16_t getIRQFlags(); + + /*! + \brief Reads modem status. Only available in LoRa mode. + \returns Modem status. + */ + uint8_t getModemStatus(); + + /*! + \brief Reads uncalibrated temperature value. This function will change operating mode + and should not be called during Tx, Rx or CAD. + \returns Uncalibrated temperature sensor reading. + */ + int8_t getTempRaw(); + + /*! \copydoc Module::setRfSwitchPins */ + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); + + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + + /*! + \brief Get one truly random byte from RSSI noise. + \returns TRNG byte. + */ + uint8_t randomByte(); + + /*! + \brief Read version SPI register. Should return SX1278_CHIP_VERSION (0x12) or SX1272_CHIP_VERSION (0x22) if SX127x is connected and working. + \returns Version register contents or \ref status_codes + */ + int16_t getChipVersion(); + + /*! + \brief Enable/disable inversion of the I and Q signals + \param enable QI inversion enabled (true) or disabled (false); + \returns \ref status_codes + */ + int16_t invertIQ(bool enable) override; + + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE + /*! + \brief Set interrupt service routine function to call when data bit is received in direct mode. + \param func Pointer to interrupt service routine. + */ + void setDirectAction(void (*func)(void)); + + /*! + \brief Function to read and process data bit in direct reception mode. + \param pin Pin on which to read. + */ + void readBit(uint32_t pin); + #endif + + /*! + \brief Sets the hopping period and enables FHSS + \param freqHoppingPeriod Integer multiple of symbol periods between hops + \returns \ref status_codes + */ + int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); + + /*! + \brief Gets FHSS hopping period + \returns 8 bit period + */ + uint8_t getFHSSHoppingPeriod(void); + + /*! + \brief Gets the FHSS channel in use + \returns 6 bit channel number + */ + uint8_t getFHSSChannel(void); + + /*! + \brief Clear the FHSS interrupt + */ + void clearFHSSInt(void); + + /*! + \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). + \param pin Pin number onto which a signal is to be placed. + \param value The value that indicates which function to place on that pin. See chip datasheet for details. + \returns \ref status_codes + */ + int16_t setDIOMapping(uint32_t pin, uint32_t value); + + /*! + \brief Configure DIO mapping to use RSSI or Preamble Detect for pins that support it. + \param usePreambleDetect Whether to use PreambleDetect (true) or RSSI (false) on the pins that are mapped to this function. + \returns \ref status_codes + */ + int16_t setDIOPreambleDetect(bool usePreambleDetect); + + /*! + \brief Gets recorded signal strength indicator. + \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. + \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. + \returns RSSI value in dBm. + */ + float getRSSI(bool packet, bool skipReceive, int16_t offset); + + /*! + \brief Sets the RSSI value above which the RSSI interrupt is signaled + \param dbm A dBm value between -127.5 and 0 inclusive + \returns \ref status_codes + */ + int16_t setRSSIThreshold(float dbm); + + /*! + \brief Set low battery indicator threshold. + \param level Battery threshold level (one of RADIOLIB_SX127X_LOW_BAT_THRESHOLD_*), + or -1 to disable the detector. Disabled by default. Note that this will not attach any interrupts! + \param pin DIO pin number which will be used to signal low battery. Only DIO0/4 can be used + (in packet mode) or DIO3/4 (in continuous mode). Ignored when disabling the detector. + \returns \ref status_codes + */ + int16_t setLowBatteryThreshold(int8_t level, uint32_t pin = RADIOLIB_NC); + +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL + protected: +#endif + Module* getMod(); + +#if !RADIOLIB_GODMODE + protected: +#endif + float frequency = 0; + float bandwidth = 0; + uint8_t spreadingFactor = 0; + size_t packetLength = 0; + uint8_t codingRate = 0; + bool crcEnabled = false; + bool ookEnabled = false; + + int16_t configFSK(); + int16_t getActiveModem(); + int16_t setFrequencyRaw(float newFreq); + int16_t setBitRateCommon(float br, uint8_t fracRegAddr); + +#if !RADIOLIB_GODMODE + private: +#endif + Module* mod; + + float bitRate = 0; + bool crcOn = true; // default value used in FSK mode + float dataRate = 0; + bool packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once + uint8_t packetLengthConfig = RADIOLIB_SX127X_PACKET_VARIABLE; + + int16_t config(); + int16_t directMode(); + int16_t setPacketMode(uint8_t mode, uint8_t len); + bool findChip(uint8_t* vers, uint8_t num); + int16_t setMode(uint8_t mode); + int16_t setActiveModem(uint8_t modem); + void clearIRQFlags(); + void clearFIFO(size_t count); // used mostly to clear remaining bytes in FIFO after a packet read + + /*! + \brief Calculate exponent and mantissa values for receiver bandwidth and AFC + \param bandwidth bandwidth to be set (in kHz). + \returns bandwidth in mantissa and exponent format + */ + static uint8_t calculateBWManExp(float bandwidth); + + virtual void errataFix(bool rx) = 0; +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX128x/SX1280.cpp b/lib/lib_rf/RadioLib/src/modules/SX128x/SX1280.cpp new file mode 100644 index 000000000..b5b30dd09 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX128x/SX1280.cpp @@ -0,0 +1,183 @@ +#include "SX1280.h" +#include +#if !RADIOLIB_EXCLUDE_SX128X + +SX1280::SX1280(Module* mod) : SX1281(mod) { + +} + +int16_t SX1280::range(bool master, uint32_t addr, uint16_t calTable[3][6]) { + // start ranging + int16_t state = startRanging(master, addr, calTable); + RADIOLIB_ASSERT(state); + + // wait until ranging is finished + Module* mod = this->getMod(); + uint32_t start = mod->hal->millis(); + while(!mod->hal->digitalRead(mod->getIrq())) { + mod->hal->yield(); + if(mod->hal->millis() - start > 10000) { + clearIrqStatus(); + standby(); + return(RADIOLIB_ERR_RANGING_TIMEOUT); + } + } + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + + return(state); +} + +int16_t SX1280::startRanging(bool master, uint32_t addr, uint16_t calTable[3][6]) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // ensure modem is set to ranging + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { + state = setPacketType(RADIOLIB_SX128X_PACKET_TYPE_RANGING); + RADIOLIB_ASSERT(state); + } + + // set modulation parameters + state = setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa); + RADIOLIB_ASSERT(state); + + // set packet parameters + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa); + RADIOLIB_ASSERT(state); + + // check all address bits + if(!master) { + uint8_t regValue; + state = readRegister(RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1); + RADIOLIB_ASSERT(state); + regValue &= 0b00111111; + regValue |= 0b11000000; + state = writeRegister(RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1); + RADIOLIB_ASSERT(state); + } + + // set remaining parameter values + uint32_t addrReg = RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_3; + uint32_t irqMask = RADIOLIB_SX128X_IRQ_RANGING_SLAVE_RESP_DONE | RADIOLIB_SX128X_IRQ_RANGING_SLAVE_REQ_DISCARD; + uint32_t irqDio1 = RADIOLIB_SX128X_IRQ_RANGING_SLAVE_RESP_DONE; + if(master) { + addrReg = RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_3; + irqMask = RADIOLIB_SX128X_IRQ_RANGING_MASTER_RES_VALID | RADIOLIB_SX128X_IRQ_RANGING_MASTER_TIMEOUT; + irqDio1 = RADIOLIB_SX128X_IRQ_RANGING_MASTER_RES_VALID; + } + + // set ranging address + uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; + state = writeRegister(addrReg, addrBuff, 4); + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = setDioIrqParams(irqMask, irqDio1); + RADIOLIB_ASSERT(state); + + // this is the default calibration from AN1200.29 + uint16_t calTbl[3][6] = { + { 10299, 10271, 10244, 10242, 10230, 10246 }, + { 11486, 11474, 11453, 11426, 11417, 11401 }, + { 13308, 13493, 13528, 13515, 13430, 13376 } + }; + + // check if user provided some custom calibration + if(calTable != NULL) { + memcpy(calTbl, calTable, sizeof(calTbl)); + } + + // set calibration values + uint8_t index = (this->spreadingFactor >> 4) - 5; + uint16_t val = 0; + switch(this->bandwidth) { + case(RADIOLIB_SX128X_LORA_BW_406_25): + val = calTbl[0][index]; + break; + case(RADIOLIB_SX128X_LORA_BW_812_50): + val = calTbl[1][index]; + break; + case(RADIOLIB_SX128X_LORA_BW_1625_00): + val = calTbl[2][index]; + break; + default: + return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } + uint8_t calBuff[] = { (uint8_t)((val >> 8) & 0xFF), (uint8_t)(val & 0xFF) }; + state = writeRegister(RADIOLIB_SX128X_REG_RANGING_CALIBRATION_MSB, calBuff, 2); + RADIOLIB_ASSERT(state); + + // set role and start ranging + if(master) { + state = setRangingRole(RADIOLIB_SX128X_RANGING_ROLE_MASTER); + RADIOLIB_ASSERT(state); + + state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE); + RADIOLIB_ASSERT(state); + + } else { + state = setRangingRole(RADIOLIB_SX128X_RANGING_ROLE_SLAVE); + RADIOLIB_ASSERT(state); + + state = setRx(RADIOLIB_SX128X_RX_TIMEOUT_INF); + RADIOLIB_ASSERT(state); + + } + + return(state); +} + +float SX1280::getRangingResult() { + // set mode to standby XOSC + int16_t state = standby(RADIOLIB_SX128X_STANDBY_XOSC); + RADIOLIB_ASSERT(state); + + // enable clock + uint8_t data[4]; + state = readRegister(RADIOLIB_SX128X_REG_RANGING_LORA_CLOCK_ENABLE, data, 1); + RADIOLIB_ASSERT(state); + + data[0] |= (1 << 1); + state = writeRegister(RADIOLIB_SX128X_REG_RANGING_LORA_CLOCK_ENABLE, data, 1); + RADIOLIB_ASSERT(state); + + // set result type to filtered + state = readRegister(RADIOLIB_SX128X_REG_RANGING_TYPE, data, 1); + RADIOLIB_ASSERT(state); + + data[0] &= 0xCF; + data[0] |= (1 << 4); + state = writeRegister(RADIOLIB_SX128X_REG_RANGING_TYPE, data, 1); + RADIOLIB_ASSERT(state); + + // read the register values + state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_MSB, &data[0], 1); + RADIOLIB_ASSERT(state); + state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_MID, &data[1], 1); + RADIOLIB_ASSERT(state); + state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_LSB, &data[2], 1); + RADIOLIB_ASSERT(state); + + // set mode to standby RC + state = standby(); + RADIOLIB_ASSERT(state); + + // calculate the real result + uint32_t raw = ((uint32_t)data[0] << 16) | ((uint32_t)data[1] << 8) | data[2]; + return((float)raw * 150.0 / (4.096 * this->bandwidthKhz)); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX128x/SX1280.h b/lib/lib_rf/RadioLib/src/modules/SX128x/SX1280.h new file mode 100644 index 000000000..c798f044a --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX128x/SX1280.h @@ -0,0 +1,56 @@ +#if !defined(_RADIOLIB_SX1280_H) +#define _RADIOLIB_SX1280_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX128X + +#include "../../Module.h" +#include "SX128x.h" +#include "SX1281.h" + +/*! + \class SX1280 + \brief Derived class for %SX1280 modules. +*/ +class SX1280: public SX1281 { + public: + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1280(Module* mod); + + /*! + \brief Blocking ranging method. + \param master Whether to execute ranging in master mode (true) or slave mode (false). + \param addr Ranging address to be used. + \param calTable Ranging calibration table - set to NULL to use the default. + \returns \ref status_codes + */ + int16_t range(bool master, uint32_t addr, uint16_t calTable[3][6] = NULL); + + /*! + \brief Interrupt-driven ranging method. + \param master Whether to execute ranging in master mode (true) or slave mode (false). + \param addr Ranging address to be used. + \param calTable Ranging calibration table - set to NULL to use the default. + \returns \ref status_codes + */ + int16_t startRanging(bool master, uint32_t addr, uint16_t calTable[3][6] = NULL); + + /*! + \brief Gets ranging result of the last ranging exchange. + \returns Ranging result in meters. + */ + float getRangingResult(); + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX128x/SX1281.cpp b/lib/lib_rf/RadioLib/src/modules/SX128x/SX1281.cpp new file mode 100644 index 000000000..71e7476e7 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX128x/SX1281.cpp @@ -0,0 +1,8 @@ +#include "SX1281.h" +#if !RADIOLIB_EXCLUDE_SX128X + +SX1281::SX1281(Module* mod) : SX128x(mod) { + +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX128x/SX1281.h b/lib/lib_rf/RadioLib/src/modules/SX128x/SX1281.h new file mode 100644 index 000000000..3a41b60a6 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX128x/SX1281.h @@ -0,0 +1,31 @@ +#if !defined(_RADIOLIB_SX1281_H) +#define _RADIOLIB_SX1281_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX128X + +#include "../../Module.h" +#include "SX128x.h" + +/*! + \class SX1281 + \brief Derived class for %SX1281 modules. +*/ +class SX1281: public SX128x { + public: + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1281(Module* mod); + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX128x/SX1282.cpp b/lib/lib_rf/RadioLib/src/modules/SX128x/SX1282.cpp new file mode 100644 index 000000000..d58ba3d37 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX128x/SX1282.cpp @@ -0,0 +1,9 @@ +#include "SX1282.h" +#if !RADIOLIB_EXCLUDE_SX128X + +/// \todo implement advanced ranging +SX1282::SX1282(Module* mod) : SX1280(mod) { + +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX128x/SX1282.h b/lib/lib_rf/RadioLib/src/modules/SX128x/SX1282.h new file mode 100644 index 000000000..091bf133b --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX128x/SX1282.h @@ -0,0 +1,32 @@ +#if !defined(_RADIOLIB_SX1282_H) +#define _RADIOLIB_SX1282_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX128X + +#include "../../Module.h" +#include "SX128x.h" +#include "SX1280.h" + +/*! + \class SX1282 + \brief Derived class for %SX1282 modules. +*/ +class SX1282: public SX1280 { + public: + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1282(Module* mod); + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX128x/SX128x.cpp b/lib/lib_rf/RadioLib/src/modules/SX128x/SX128x.cpp new file mode 100644 index 000000000..55b18dd96 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX128x/SX128x.cpp @@ -0,0 +1,1514 @@ +#include "SX128x.h" +#include +#if !RADIOLIB_EXCLUDE_SX128X + +SX128x::SX128x(Module* mod) : PhysicalLayer(RADIOLIB_SX128X_FREQUENCY_STEP_SIZE, RADIOLIB_SX128X_MAX_PACKET_LENGTH) { + this->mod = mod; +} + +int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t pwr, uint16_t preambleLength) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; + this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; + this->mod->SPIstreamType = true; + this->mod->SPIparseStatusCb = SPIparseStatus; + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); + + // initialize LoRa modulation variables + this->bandwidthKhz = bw; + this->spreadingFactor = RADIOLIB_SX128X_LORA_SF_9; + this->codingRateLoRa = RADIOLIB_SX128X_LORA_CR_4_7; + + // initialize LoRa packet variables + this->preambleLengthLoRa = preambleLength; + this->headerType = RADIOLIB_SX128X_LORA_HEADER_EXPLICIT; + this->payloadLen = 0xFF; + this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON; + + // reset the module and verify startup + int16_t state = reset(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = config(RADIOLIB_SX128X_PACKET_TYPE_LORA); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setSyncWord(syncWord); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + state = setOutputPower(pwr); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, uint16_t preambleLength) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; + this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; + this->mod->SPIstreamType = true; + this->mod->SPIparseStatusCb = SPIparseStatus; + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); + + // initialize GFSK modulation variables + this->bitRateKbps = br; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; + this->modIndexReal = 1.0; + this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00; + this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5; + + // initialize GFSK packet variables + this->preambleLengthGFSK = preambleLength; + this->syncWordLen = 2; + this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1; + this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE; + this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; + + // reset the module and verify startup + int16_t state = reset(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = config(RADIOLIB_SX128X_PACKET_TYPE_GFSK); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + state = setOutputPower(pwr); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + state = setDataShaping(RADIOLIB_SHAPING_0_5); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + uint8_t sync[] = { 0x12, 0xAD }; + state = setSyncWord(sync, 2); + RADIOLIB_ASSERT(state); + + state = setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uint8_t dataShaping) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; + this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; + this->mod->SPIstreamType = true; + this->mod->SPIparseStatusCb = SPIparseStatus; + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); + + // initialize BLE modulation variables + this->bitRateKbps = br; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; + this->modIndexReal = 1.0; + this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00; + this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5; + + // initialize BLE packet variables + this->crcGFSK = RADIOLIB_SX128X_BLE_CRC_3_BYTE; + this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; + + // reset the module and verify startup + int16_t state = reset(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = config(RADIOLIB_SX128X_PACKET_TYPE_BLE); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + state = setOutputPower(pwr); + RADIOLIB_ASSERT(state); + + state = setDataShaping(dataShaping); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint16_t preambleLength, uint8_t dataShaping) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; + this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; + this->mod->SPIstreamType = true; + this->mod->SPIparseStatusCb = SPIparseStatus; + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); + + // initialize FLRC modulation variables + this->bitRateKbps = br; + this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6; + this->codingRateFLRC = RADIOLIB_SX128X_FLRC_CR_3_4; + this->shaping = RADIOLIB_SX128X_FLRC_BT_0_5; + + // initialize FLRC packet variables + this->preambleLengthGFSK = preambleLength; + this->syncWordLen = 2; + this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1; + this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE; + this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF; + + // reset the module and verify startup + int16_t state = reset(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = config(RADIOLIB_SX128X_PACKET_TYPE_FLRC); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setOutputPower(pwr); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + state = setDataShaping(dataShaping); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + uint8_t sync[] = { 0x2D, 0x01, 0x4B, 0x1D}; + state = setSyncWord(sync, 4); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX128x::reset(bool verify) { + // run the reset sequence - same as SX126x, as SX128x docs don't seem to mention this + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + this->mod->hal->delay(1); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + + // return immediately when verification is disabled + if(!verify) { + return(RADIOLIB_ERR_NONE); + } + + // set mode to standby + uint32_t start = this->mod->hal->millis(); + while(true) { + // try to set mode to standby + int16_t state = standby(); + if(state == RADIOLIB_ERR_NONE) { + // standby command successful + return(RADIOLIB_ERR_NONE); + } + + // standby command failed, check timeout and try again + if(this->mod->hal->millis() - start >= 3000) { + // timed out, possibly incorrect wiring + return(state); + } + + // wait a bit to not spam the module + this->mod->hal->delay(10); + } +} + +int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { + // check packet length + if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // check active modem + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // calculate timeout (500% of expected time-on-air) + uint32_t timeout = getTimeOnAir(len) * 5; + + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); + + // start transmission + state = startTransmit(data, len, addr); + RADIOLIB_ASSERT(state); + + // wait for packet transmission or timeout + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { + finishTransmit(); + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + + return(finishTransmit()); +} + +int16_t SX128x::receive(uint8_t* data, size_t len) { + // check active modem + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // calculate timeout (1000% of expected time-on-air) + uint32_t timeout = getTimeOnAir(len) * 10; + + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); + + // start reception + uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); + state = startReceive(timeoutValue); + RADIOLIB_ASSERT(state); + + // wait for packet reception or timeout + bool softTimeout = false; + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + // safety check, the timeout should be done by the radio + if(this->mod->hal->micros() - start > timeout) { + softTimeout = true; + break; + } + } + + // if it was a timeout, this will return an error code + state = standby(); + if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) { + return(state); + } + + // check whether this was a timeout or not + if((getIrqStatus() & RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT) || softTimeout) { + standby(); + clearIrqStatus(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + + // read the received data + return(readData(data, len)); +} + +int16_t SX128x::transmitDirect(uint32_t frf) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_TX); + + // user requested to start transmitting immediately (required for RTTY) + int16_t state = RADIOLIB_ERR_NONE; + if(frf != 0) { + state = setRfFrequency(frf); + } + RADIOLIB_ASSERT(state); + + // start transmitting + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0)); +} + +int16_t SX128x::receiveDirect() { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // SX128x is unable to output received data directly + return(RADIOLIB_ERR_UNKNOWN); +} + +int16_t SX128x::scanChannel() { + // check active modem + if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set DIO pin mapping + state = setDioIrqParams(RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE, RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // set mode to CAD + state = setCad(); + RADIOLIB_ASSERT(state); + + // wait for channel activity detected or timeout + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + } + + // check CAD result + uint16_t cadResult = getIrqStatus(); + if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DETECTED) { + // detected some LoRa activity + clearIrqStatus(); + return(RADIOLIB_LORA_DETECTED); + } else if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DONE) { + // channel is free + clearIrqStatus(); + return(RADIOLIB_CHANNEL_FREE); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + +int16_t SX128x::sleep(bool retainConfig) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + uint8_t sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_RETAIN | RADIOLIB_SX128X_SLEEP_DATA_RAM_RETAIN; + if(!retainConfig) { + sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH | RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH; + } + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false, false); + + // wait for SX128x to safely enter sleep mode + this->mod->hal->delay(1); + + return(state); +} + +int16_t SX128x::standby() { + return(SX128x::standby(RADIOLIB_SX128X_STANDBY_RC)); +} + +int16_t SX128x::standby(uint8_t mode, bool wakeup) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + if(wakeup) { + // pull NSS low to wake up + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + } + + uint8_t data[] = { mode }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1)); +} + +void SX128x::setDio1Action(void (*func)(void)) { + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising); +} + +void SX128x::clearDio1Action() { + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); +} + +void SX128x::setPacketReceivedAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void SX128x::clearPacketReceivedAction() { + this->clearDio1Action(); +} + +void SX128x::setPacketSentAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void SX128x::clearPacketSentAction() { + this->clearDio1Action(); +} + +int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { + // suppress unused variable warning + (void)addr; + + // check packet length + if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set packet Length + int16_t state = RADIOLIB_ERR_NONE; + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, len, this->crcLoRa, this->invertIQEnabled); + } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) { + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, len); + } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { + state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening); + } else { + return(RADIOLIB_ERR_WRONG_MODEM); + } + RADIOLIB_ASSERT(state); + + // update output power + state = setTxParams(this->power); + RADIOLIB_ASSERT(state); + + // set buffer pointers + state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // write packet to buffer + if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { + // first 2 bytes of BLE payload are PDU header + state = writeBuffer(data, len, 2); + RADIOLIB_ASSERT(state); + } else { + state = writeBuffer(data, len); + RADIOLIB_ASSERT(state); + } + + // set DIO mapping + state = setDioIrqParams(RADIOLIB_SX128X_IRQ_TX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT, RADIOLIB_SX128X_IRQ_TX_DONE); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_TX); + + // start transmission + state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE); + RADIOLIB_ASSERT(state); + + // wait for BUSY to go low (= PA ramp up done) + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + } + + return(state); +} + +int16_t SX128x::finishTransmit() { + // clear interrupt flags + clearIrqStatus(); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + +int16_t SX128x::startReceive() { + return(this->startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_SX128X_IRQ_RX_DEFAULT, RADIOLIB_SX128X_IRQ_RX_DONE, 0)); +} + +int16_t SX128x::startReceive(uint16_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)len; + + // check active modem + if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set DIO mapping + if(timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) { + irqMask |= RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT; + } + + int16_t state = setDioIrqParams(irqFlags, irqMask); + RADIOLIB_ASSERT(state); + + // set buffer pointers + state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // set implicit mode and expected len if applicable + if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) { + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled); + RADIOLIB_ASSERT(state); + } + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // set mode to receive + state = setRx(timeout); + + return(state); +} + +int16_t SX128x::readData(uint8_t* data, size_t len) { + // check active modem + if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // check integrity CRC + uint16_t irq = getIrqStatus(); + int16_t crcState = RADIOLIB_ERR_NONE; + if((irq & RADIOLIB_SX128X_IRQ_CRC_ERROR) || (irq & RADIOLIB_SX128X_IRQ_HEADER_ERROR)) { + crcState = RADIOLIB_ERR_CRC_MISMATCH; + } + + // get packet length + size_t length = getPacketLength(); + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + length = len; + } + + // read packet data + state = readBuffer(data, length); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + + // check if CRC failed - this is done after reading data to give user the option to keep them + RADIOLIB_ASSERT(crcState); + + return(state); +} + +int16_t SX128x::setFrequency(float freq) { + RADIOLIB_CHECK_RANGE(freq, 2400.0, 2500.0, RADIOLIB_ERR_INVALID_FREQUENCY); + + // calculate raw value + uint32_t frf = (freq * (uint32_t(1) << RADIOLIB_SX128X_DIV_EXPONENT)) / RADIOLIB_SX128X_CRYSTAL_FREQ; + return(setRfFrequency(frf)); +} + +int16_t SX128x::setBandwidth(float bw) { + // check active modem + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { + // check range for LoRa + RADIOLIB_CHECK_RANGE(bw, 203.125, 1625.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { + // check range for ranging + RADIOLIB_CHECK_RANGE(bw, 406.25, 1625.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + } else { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + if(fabs(bw - 203.125) <= 0.001) { + this->bandwidth = RADIOLIB_SX128X_LORA_BW_203_125; + } else if(fabs(bw - 406.25) <= 0.001) { + this->bandwidth = RADIOLIB_SX128X_LORA_BW_406_25; + } else if(fabs(bw - 812.5) <= 0.001) { + this->bandwidth = RADIOLIB_SX128X_LORA_BW_812_50; + } else if(fabs(bw - 1625.0) <= 0.001) { + this->bandwidth = RADIOLIB_SX128X_LORA_BW_1625_00; + } else { + return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } + + // update modulation parameters + this->bandwidthKhz = bw; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa)); +} + +int16_t SX128x::setSpreadingFactor(uint8_t sf) { + // check active modem + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { + // check range for LoRa + RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { + // check range for ranging + RADIOLIB_CHECK_RANGE(sf, 5, 10, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + } else { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // update modulation parameters + this->spreadingFactor = sf << 4; + int16_t state = setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa); + RADIOLIB_ASSERT(state); + + // update mystery register in LoRa mode - SX1280 datasheet v3.0 section 13.4.1 + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { + uint8_t data = 0; + if((this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_5) || (this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_6)) { + data = 0x1E; + } else if((this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_7) || (this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_8)) { + data = 0x37; + } else { + data = 0x32; + } + state = SX128x::writeRegister(RADIOLIB_SX128X_REG_LORA_SF_CONFIG, &data, 1); + } + + return(state); +} + +int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) { + // check active modem + uint8_t modem = getPacketType(); + + // LoRa/ranging + if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { + RADIOLIB_CHECK_RANGE(cr, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + + // update modulation parameters + if(longInterleaving && (modem == RADIOLIB_SX128X_PACKET_TYPE_LORA)) { + this->codingRateLoRa = cr; + } else { + this->codingRateLoRa = cr - 4; + } + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa)); + + // FLRC + } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC) { + RADIOLIB_CHECK_RANGE(cr, 2, 4, RADIOLIB_ERR_INVALID_CODING_RATE); + + // update modulation parameters + this->codingRateFLRC = (cr - 2) * 2; + return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping)); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + +int16_t SX128x::setOutputPower(int8_t pwr) { + RADIOLIB_CHECK_RANGE(pwr, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + this->power = pwr + 18; + return(setTxParams(this->power)); +} + +int16_t SX128x::setPreambleLength(uint32_t preambleLength) { + uint8_t modem = getPacketType(); + if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { + // LoRa or ranging + RADIOLIB_CHECK_RANGE(preambleLength, 2, 491520, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); + + // check preamble length is even - no point even trying odd numbers + if(preambleLength % 2 != 0) { + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); + } + + // calculate exponent and mantissa values (use the next longer preamble if there's no exact match) + uint8_t e = 1; + uint8_t m = 1; + uint32_t len = 0; + for(; e <= 15; e++) { + for(; m <= 15; m++) { + len = m * (uint32_t(1) << e); + if(len >= preambleLength) { + break; + } + } + if(len >= preambleLength) { + break; + } + } + + // update packet parameters + this->preambleLengthLoRa = (e << 4) | m; + return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled)); + + } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) { + // GFSK or FLRC + RADIOLIB_CHECK_RANGE(preambleLength, 4, 32, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); + + // check preamble length is multiple of 4 + if(preambleLength % 4 != 0) { + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); + } + + // update packet parameters + this->preambleLengthGFSK = ((preambleLength / 4) - 1) << 4; + return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening)); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + +int16_t SX128x::setBitRate(float br) { + // check active modem + uint8_t modem = getPacketType(); + + // GFSK/BLE + if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE)) { + if((uint16_t)br == 125) { + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3; + } else if((uint16_t)br == 250) { + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_6; + } else if((uint16_t)br == 400) { + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_1_2; + } else if((uint16_t)br == 500) { + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_1_2; + } else if((uint16_t)br == 800) { + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; + } else if((uint16_t)br == 1000) { + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_2_4; + } else if((uint16_t)br == 1600) { + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_1_600_BW_2_4; + } else if((uint16_t)br == 2000) { + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_2_000_BW_2_4; + } else { + return(RADIOLIB_ERR_INVALID_BIT_RATE); + } + + // update modulation parameters + this->bitRateKbps = (uint16_t)br; + return(setModulationParams(this->bitRate, this->modIndex, this->shaping)); + + // FLRC + } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC) { + if((uint16_t)br == 260) { + this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_260_BW_0_3; + } else if((uint16_t)br == 325) { + this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_325_BW_0_3; + } else if((uint16_t)br == 520) { + this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_520_BW_0_6; + } else if((uint16_t)br == 650) { + this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6; + } else if((uint16_t)br == 1000) { + this->bitRate = RADIOLIB_SX128X_FLRC_BR_1_000_BW_1_2; + } else if((uint16_t)br == 1300) { + this->bitRate = RADIOLIB_SX128X_FLRC_BR_1_300_BW_1_2; + } else { + return(RADIOLIB_ERR_INVALID_BIT_RATE); + } + + // update modulation parameters + this->bitRateKbps = (uint16_t)br; + return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping)); + + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + +int16_t SX128x::setFrequencyDeviation(float freqDev) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE))) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set frequency deviation to lowest available setting (required for digimodes) + float newFreqDev = freqDev; + if(freqDev < 0.0) { + newFreqDev = 62.5; + } + + RADIOLIB_CHECK_RANGE(newFreqDev, 62.5, 1000.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + + // override for the lowest possible frequency deviation - required for some PhysicalLayer protocols + if(newFreqDev == 0.0) { + this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_35; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3; + return(setModulationParams(this->bitRate, this->modIndex, this->shaping)); + } + + // update modulation parameters + uint8_t modIndex = (uint8_t)((8.0 * (newFreqDev / (float)this->bitRateKbps)) - 1.0); + if(modIndex > RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00) { + return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); + } + + // update modulation parameters + this->modIndex = modIndex; + return(setModulationParams(this->bitRate, this->modIndex, this->shaping)); +} + +int16_t SX128x::setDataShaping(uint8_t sh) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set data this->shaping + switch(sh) { + case RADIOLIB_SHAPING_NONE: + this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_OFF; + break; + case RADIOLIB_SHAPING_0_5: + this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5; + break; + case RADIOLIB_SHAPING_1_0: + this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_1_0; + break; + default: + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); + } + + // update modulation parameters + if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE)) { + return(setModulationParams(this->bitRate, this->modIndex, this->shaping)); + } else { + return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping)); + } +} + +int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) { + // GFSK can use up to 5 bytes as sync word + if(len > 5) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + + // calculate sync word length parameter value + if(len > 0) { + this->syncWordLen = (len - 1)*2; + } + + } else { + // FLRC requires 32-bit sync word + if(!((len == 0) || (len == 4))) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + + // save sync word length parameter value + this->syncWordLen = len; + } + + // reverse sync word byte order + uint8_t syncWordBuff[] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; + for(uint8_t i = 0; i < len; i++) { + syncWordBuff[4 - i] = syncWord[i]; + } + + // update sync word + int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4, syncWordBuff, 5); + RADIOLIB_ASSERT(state); + + // update packet parameters + if(this->syncWordLen == 0) { + this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_OFF; + } else { + /// \todo add support for multiple sync words + this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1; + } + return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening)); +} + +int16_t SX128x::setSyncWord(uint8_t syncWord, uint8_t controlBits) { + // check active modem + if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // update register + uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))}; + return(writeRegister(RADIOLIB_SX128X_REG_LORA_SYNC_WORD_MSB, data, 2)); +} + +int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) { + // check active modem + uint8_t modem = getPacketType(); + + int16_t state; + if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) { + // update packet parameters + if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) { + if(len > 2) { + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); + } + } else { + if(len > 3) { + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); + } + } + this->crcGFSK = len << 4; + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + // set initial CRC value + uint8_t data[] = { (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) }; + state = writeRegister(RADIOLIB_SX128X_REG_CRC_INITIAL_MSB, data, 2); + RADIOLIB_ASSERT(state); + + // set CRC polynomial + data[0] = (uint8_t)((polynomial >> 8) & 0xFF); + data[1] = (uint8_t)(polynomial & 0xFF); + state = writeRegister(RADIOLIB_SX128X_REG_CRC_POLYNOMIAL_MSB, data, 2); + return(state); + + } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { + // update packet parameters + if(len == 0) { + this->crcBLE = RADIOLIB_SX128X_BLE_CRC_OFF; + } else if(len == 3) { + this->crcBLE = RADIOLIB_SX128X_BLE_CRC_3_BYTE; + } else { + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); + } + state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening); + RADIOLIB_ASSERT(state); + + // set initial CRC value + uint8_t data[] = { (uint8_t)((initial >> 16) & 0xFF), (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) }; + state = writeRegister(RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MSB, data, 3); + return(state); + + } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { + // update packet parameters + if(len == 0) { + this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_OFF; + } else if(len == 2) { + this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON; + } else { + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); + } + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled); + return(state); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + +int16_t SX128x::setWhitening(bool enabled) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE))) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // update packet parameters + if(enabled) { + this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; + } else { + this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF; + } + + if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) { + return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening)); + } + return(setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening)); +} + +int16_t SX128x::setAccessAddress(uint32_t addr) { + // check active modem + if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_BLE) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set the address + uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; + return(SX128x::writeRegister(RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_3, addrBuff, 4)); +} + +int16_t SX128x::setHighSensitivityMode(bool enable) { + // read the current registers + uint8_t RxGain = 0; + int16_t state = readRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1); + RADIOLIB_ASSERT(state); + + if(enable) { + RxGain |= 0xC0; // Set bits 6 and 7 + } else { + RxGain &= ~0xC0; // Unset bits 6 and 7 + } + + // update all values + state = writeRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1); + return(state); +} + +int16_t SX128x::setGainControl(uint8_t gain) { + // read the current registers + uint8_t ManualGainSetting = 0; + int16_t state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1); + RADIOLIB_ASSERT(state); + uint8_t LNAGainValue = 0; + state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1); + RADIOLIB_ASSERT(state); + uint8_t LNAGainControl = 0; + state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1); + RADIOLIB_ASSERT(state); + + // set the gain + if (gain > 0 && gain < 14) { + // Set manual gain + ManualGainSetting &= ~0x01; // Set bit 0 to 0 (Enable Manual Gain Control) + LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0 + LNAGainValue |= gain; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13) + LNAGainControl |= 0x80; // Set bit 7 to 1 (Enable Manual Gain Control) + } else { + // Set automatic gain if 0 or out of range + ManualGainSetting |= 0x01; // Set bit 0 to 1 (Enable Automatic Gain Control) + LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0 + LNAGainValue |= 0x0A; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13) + LNAGainControl &= ~0x80; // Set bit 7 to 0 (Enable Automatic Gain Control) + } + + // update all values + state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1); + RADIOLIB_ASSERT(state); + state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1); + RADIOLIB_ASSERT(state); + state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1); + return(state); +} + +float SX128x::getRSSI() { + // get packet status + uint8_t packetStatus[5]; + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); + + // check active modem + uint8_t modem = getPacketType(); + if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { + // LoRa or ranging + uint8_t rssiSync = packetStatus[0]; + float rssiMeasured = -1.0 * rssiSync/2.0; + float snr = getSNR(); + if(snr <= 0.0) { + return(rssiMeasured - snr); + } else { + return(rssiMeasured); + } + } else { + // GFSK, BLE or FLRC + uint8_t rssiSync = packetStatus[1]; + return(-1.0 * rssiSync/2.0); + } +} + +float SX128x::getSNR() { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { + return(0.0); + } + + // get packet status + uint8_t packetStatus[5]; + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); + + // calculate real SNR + uint8_t snr = packetStatus[1]; + if(snr < 128) { + return(snr/4.0); + } else { + return((snr - 256)/4.0); + } +} + +float SX128x::getFrequencyError() { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { + return(0.0); + } + + // read the raw frequency error register values + uint8_t efeRaw[3] = {0}; + int16_t state = readRegister(RADIOLIB_SX128X_REG_FEI_MSB, &efeRaw[0], 1); + RADIOLIB_ASSERT(state); + state = readRegister(RADIOLIB_SX128X_REG_FEI_MID, &efeRaw[1], 1); + RADIOLIB_ASSERT(state); + state = readRegister(RADIOLIB_SX128X_REG_FEI_LSB, &efeRaw[2], 1); + RADIOLIB_ASSERT(state); + uint32_t efe = ((uint32_t) efeRaw[0] << 16) | ((uint32_t) efeRaw[1] << 8) | efeRaw[2]; + efe &= 0x0FFFFF; + + float error = 0; + + // check the first bit + if (efe & 0x80000) { + // frequency error is negative + efe |= (uint32_t) 0xFFF00000; + efe = ~efe + 1; + error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz) * -1.0; + } else { + error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz); + } + + return(error); +} + +size_t SX128x::getPacketLength(bool update) { + (void)update; + + // in implicit mode, return the cached value + if((getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT)) { + return(this->payloadLen); + } + + uint8_t rxBufStatus[2] = {0, 0}; + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); + return((size_t)rxBufStatus[0]); +} + +uint32_t SX128x::getTimeOnAir(size_t len) { + // check active modem + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { + // calculate number of symbols + float N_symbol = 0; + uint8_t sf = this->spreadingFactor >> 4; + if(this->codingRateLoRa <= RADIOLIB_SX128X_LORA_CR_4_8) { + // legacy coding rate - nice and simple + + // get SF coefficients + float coeff1 = 0; + int16_t coeff2 = 0; + int16_t coeff3 = 0; + if(sf < 7) { + // SF5, SF6 + coeff1 = 6.25; + coeff2 = 4*sf; + coeff3 = 4*sf; + } else if(sf < 11) { + // SF7. SF8, SF9, SF10 + coeff1 = 4.25; + coeff2 = 4*sf + 8; + coeff3 = 4*sf; + } else { + // SF11, SF12 + coeff1 = 4.25; + coeff2 = 4*sf + 8; + coeff3 = 4*(sf - 2); + } + + // get CRC length + int16_t N_bitCRC = 16; + if(this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_OFF) { + N_bitCRC = 0; + } + + // get header length + int16_t N_symbolHeader = 20; + if(this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) { + N_symbolHeader = 0; + } + + // calculate number of LoRa preamble symbols + uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4)); + + // calculate the number of symbols + N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceil(RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRateLoRa + 4); + + } else { + // long interleaving - abandon hope all ye who enter here + /// \todo implement this mess - SX1280 datasheet v3.0 section 7.4.4.2 + + } + + // get time-on-air in us + return(((uint32_t(1) << sf) / this->bandwidthKhz) * N_symbol * 1000.0); + + } else { + return(((uint32_t)len * 8 * 1000) / this->bitRateKbps); + } + +} + +int16_t SX128x::implicitHeader(size_t len) { + return(setHeaderType(RADIOLIB_SX128X_LORA_HEADER_IMPLICIT, len)); +} + +int16_t SX128x::explicitHeader() { + return(setHeaderType(RADIOLIB_SX128X_LORA_HEADER_EXPLICIT)); +} + +int16_t SX128x::setEncoding(uint8_t encoding) { + return(setWhitening(encoding)); +} + +void SX128x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { + this->mod->setRfSwitchPins(rxEn, txEn); +} + +void SX128x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + this->mod->setRfSwitchTable(pins, table); +} + +uint8_t SX128x::randomByte() { + // it's unclear whether SX128x can measure RSSI while not receiving a packet + // this method is implemented only for PhysicalLayer compatibility + return(0); +} + +int16_t SX128x::invertIQ(bool enable) { + if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + if(enable) { + this->invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_INVERTED; + } else { + this->invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_STANDARD; + } + + return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled)); +} + +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE +void SX128x::setDirectAction(void (*func)(void)) { + // SX128x is unable to perform direct mode reception + // this method is implemented only for PhysicalLayer compatibility + (void)func; +} + +void SX128x::readBit(uint32_t pin) { + // SX128x is unable to perform direct mode reception + // this method is implemented only for PhysicalLayer compatibility + (void)pin; +} +#endif + +Module* SX128x::getMod() { + return(this->mod); +} + +uint8_t SX128x::getStatus() { + uint8_t data = 0; + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_STATUS, &data, 0); + return(data); +} + +int16_t SX128x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { + this->mod->SPIwriteRegisterBurst(addr, data, numBytes); + return(RADIOLIB_ERR_NONE); +} + +int16_t SX128x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { + // send the command + this->mod->SPIreadRegisterBurst(addr, numBytes, data); + + // check the status + int16_t state = this->mod->SPIcheckStream(); + return(state); +} + +int16_t SX128x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { + uint8_t cmd[] = { RADIOLIB_SX128X_CMD_WRITE_BUFFER, offset }; + return(this->mod->SPIwriteStream(cmd, 2, data, numBytes)); +} + +int16_t SX128x::readBuffer(uint8_t* data, uint8_t numBytes) { + uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_BUFFER, RADIOLIB_SX128X_CMD_NOP }; + return(this->mod->SPIreadStream(cmd, 2, data, numBytes)); +} + +int16_t SX128x::setTx(uint16_t periodBaseCount, uint8_t periodBase) { + uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX, data, 3)); +} + +int16_t SX128x::setRx(uint16_t periodBaseCount, uint8_t periodBase) { + uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RX, data, 3)); +} + +int16_t SX128x::setCad() { + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD, NULL, 0)); +} + +uint8_t SX128x::getPacketType() { + uint8_t data = 0xFF; + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_TYPE, &data, 1); + return(data); +} + +int16_t SX128x::setRfFrequency(uint32_t frf) { + uint8_t data[] = { (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY, data, 3)); +} + +int16_t SX128x::setTxParams(uint8_t pwr, uint8_t rampTime) { + uint8_t data[] = { pwr, rampTime }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_PARAMS, data, 2)); +} + +int16_t SX128x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { + uint8_t data[] = { txBaseAddress, rxBaseAddress }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); +} + +int16_t SX128x::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3) { + uint8_t data[] = { modParam1, modParam2, modParam3 }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS, data, 3)); +} + +int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t payLen, uint8_t hdrType) { + uint8_t data[] = { preambleLen, syncLen, syncMatch, hdrType, payLen, crcLen, whiten }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); +} + +int16_t SX128x::setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTest, uint8_t whiten) { + uint8_t data[] = { connState, crcLen, bleTest, whiten, 0x00, 0x00, 0x00 }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); +} + +int16_t SX128x::setPacketParamsLoRa(uint8_t preambleLen, uint8_t hdrType, uint8_t payLen, uint8_t crc, uint8_t invIQ) { + uint8_t data[] = { preambleLen, hdrType, payLen, crc, invIQ, 0x00, 0x00 }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); +} + +int16_t SX128x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { + uint8_t data[] = { (uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF), + (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), + (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), + (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF) }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); +} + +uint16_t SX128x::getIrqStatus() { + uint8_t data[] = { 0x00, 0x00 }; + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_IRQ_STATUS, data, 2); + return(((uint16_t)(data[0]) << 8) | data[1]); +} + +int16_t SX128x::clearIrqStatus(uint16_t clearIrqParams) { + uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS, data, 2)); +} + +int16_t SX128x::setRangingRole(uint8_t role) { + uint8_t data[] = { role }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RANGING_ROLE, data, 1)); +} + +int16_t SX128x::setPacketType(uint8_t type) { + uint8_t data[] = { type }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1)); +} + +int16_t SX128x::setHeaderType(uint8_t hdrType, size_t len) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // update packet parameters + this->headerType = hdrType; + this->payloadLen = len; + return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled)); +} + +int16_t SX128x::config(uint8_t modem) { + // reset buffer base address + int16_t state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // set modem + uint8_t data[1]; + data[0] = modem; + state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1); + RADIOLIB_ASSERT(state); + + // set CAD parameters + data[0] = RADIOLIB_SX128X_CAD_ON_8_SYMB; + state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD_PARAMS, data, 1); + RADIOLIB_ASSERT(state); + + // set regulator mode to DC-DC + data[0] = RADIOLIB_SX128X_REGULATOR_DC_DC; + state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE, data, 1); + RADIOLIB_ASSERT(state); + + return(RADIOLIB_ERR_NONE); +} + +int16_t SX128x::SPIparseStatus(uint8_t in) { + if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_TIMEOUT) { + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + } else if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_ERROR) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } else if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_FAILED) { + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } else if((in == 0x00) || (in == 0xFF)) { + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + return(RADIOLIB_ERR_NONE); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/SX128x/SX128x.h b/lib/lib_rf/RadioLib/src/modules/SX128x/SX128x.h new file mode 100644 index 000000000..1348f3aed --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/SX128x/SX128x.h @@ -0,0 +1,844 @@ +#if !defined(_RADIOLIB_SX128X_H) +#define _RADIOLIB_SX128X_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX128X + +#include "../../Module.h" + +#include "../../protocols/PhysicalLayer/PhysicalLayer.h" + +// SX128X physical layer properties +#define RADIOLIB_SX128X_FREQUENCY_STEP_SIZE 198.3642578 +#define RADIOLIB_SX128X_MAX_PACKET_LENGTH 255 +#define RADIOLIB_SX128X_CRYSTAL_FREQ 52.0 +#define RADIOLIB_SX128X_DIV_EXPONENT 18 + +// SX128X SPI commands +#define RADIOLIB_SX128X_CMD_NOP 0x00 +#define RADIOLIB_SX128X_CMD_GET_STATUS 0xC0 +#define RADIOLIB_SX128X_CMD_WRITE_REGISTER 0x18 +#define RADIOLIB_SX128X_CMD_READ_REGISTER 0x19 +#define RADIOLIB_SX128X_CMD_WRITE_BUFFER 0x1A +#define RADIOLIB_SX128X_CMD_READ_BUFFER 0x1B +#define RADIOLIB_SX128X_CMD_SET_SLEEP 0x84 +#define RADIOLIB_SX128X_CMD_SET_STANDBY 0x80 +#define RADIOLIB_SX128X_CMD_SET_FS 0xC1 +#define RADIOLIB_SX128X_CMD_SET_TX 0x83 +#define RADIOLIB_SX128X_CMD_SET_RX 0x82 +#define RADIOLIB_SX128X_CMD_SET_RX_DUTY_CYCLE 0x94 +#define RADIOLIB_SX128X_CMD_SET_CAD 0xC5 +#define RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1 +#define RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_PREAMBLE 0xD2 +#define RADIOLIB_SX128X_CMD_SET_PACKET_TYPE 0x8A +#define RADIOLIB_SX128X_CMD_GET_PACKET_TYPE 0x03 +#define RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY 0x86 +#define RADIOLIB_SX128X_CMD_SET_TX_PARAMS 0x8E +#define RADIOLIB_SX128X_CMD_SET_CAD_PARAMS 0x88 +#define RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F +#define RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS 0x8B +#define RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS 0x8C +#define RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS 0x17 +#define RADIOLIB_SX128X_CMD_GET_PACKET_STATUS 0x1D +#define RADIOLIB_SX128X_CMD_GET_RSSI_INST 0x1F +#define RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS 0x8D +#define RADIOLIB_SX128X_CMD_GET_IRQ_STATUS 0x15 +#define RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS 0x97 +#define RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE 0x96 +#define RADIOLIB_SX128X_CMD_SET_SAVE_CONTEXT 0xD5 +#define RADIOLIB_SX128X_CMD_SET_AUTO_TX 0x98 +#define RADIOLIB_SX128X_CMD_SET_AUTO_FS 0x9E +#define RADIOLIB_SX128X_CMD_SET_PERF_COUNTER_MODE 0x9C +#define RADIOLIB_SX128X_CMD_SET_LONG_PREAMBLE 0x9B +#define RADIOLIB_SX128X_CMD_SET_UART_SPEED 0x9D +#define RADIOLIB_SX128X_CMD_SET_RANGING_ROLE 0xA3 +#define RADIOLIB_SX128X_CMD_SET_ADVANCED_RANGING 0x9A + +// SX128X register map +#define RADIOLIB_SX128X_REG_GAIN_MODE 0x0891 +#define RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2 0x0895 +#define RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING 0x089E +#define RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1 0x089F +#define RADIOLIB_SX128X_REG_SYNCH_PEAK_ATTENUATION 0x08C2 +#define RADIOLIB_SX128X_REG_LORA_FIXED_PAYLOAD_LENGTH 0x0901 +#define RADIOLIB_SX128X_REG_LORA_HEADER_MODE 0x0903 +#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_3 0x0912 +#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_2 0x0913 +#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_1 0x0914 +#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_0 0x0915 +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_3 0x0916 +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_2 0x0917 +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_1 0x0918 +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_0 0x0919 +#define RADIOLIB_SX128X_REG_RANGING_FILTER_WINDOW_SIZE 0x091E +#define RADIOLIB_SX128X_REG_RANGING_FILTER_RESET 0x0923 +#define RADIOLIB_SX128X_REG_RANGING_TYPE 0x0924 +#define RADIOLIB_SX128X_REG_LORA_SF_CONFIG 0x0925 +#define RADIOLIB_SX128X_REG_RANGING_ADDRESS_SWITCH 0x0927 +#define RADIOLIB_SX128X_REG_RANGING_CALIBRATION_BYTE_2 0x092B +#define RADIOLIB_SX128X_REG_RANGING_CALIBRATION_MSB 0x092C +#define RADIOLIB_SX128X_REG_RANGING_CALIBRATION_LSB 0x092D +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH 0x0931 +#define RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION 0x093C +#define RADIOLIB_SX128X_REG_LORA_SYNC_WORD_MSB 0x0944 +#define RADIOLIB_SX128X_REG_LORA_SYNC_WORD_LSB 0x0945 +#define RADIOLIB_SX128X_REG_RANGING_FILTER_RSSI_OFFSET 0x0953 +#define RADIOLIB_SX128X_REG_FEI_MSB 0x0954 +#define RADIOLIB_SX128X_REG_FEI_MID 0x0955 +#define RADIOLIB_SX128X_REG_FEI_LSB 0x0956 +#define RADIOLIB_SX128X_REG_RANGING_ADDRESS_MSB 0x095F +#define RADIOLIB_SX128X_REG_RANGING_ADDRESS_LSB 0x0960 +#define RADIOLIB_SX128X_REG_RANGING_RESULT_MSB 0x0961 +#define RADIOLIB_SX128X_REG_RANGING_RESULT_MID 0x0962 +#define RADIOLIB_SX128X_REG_RANGING_RESULT_LSB 0x0963 +#define RADIOLIB_SX128X_REG_RANGING_RSSI 0x0964 +#define RADIOLIB_SX128X_REG_RANGING_LORA_CLOCK_ENABLE 0x097F +#define RADIOLIB_SX128X_REG_PACKET_PREAMBLE_SETTINGS 0x09C1 +#define RADIOLIB_SX128X_REG_WHITENING_INITIAL_VALUE 0x09C5 +#define RADIOLIB_SX128X_REG_CRC_POLYNOMIAL_MSB 0x09C6 +#define RADIOLIB_SX128X_REG_CRC_POLYNOMIAL_LSB 0x09C7 +#define RADIOLIB_SX128X_REG_CRC_INITIAL_MSB 0x09C8 +#define RADIOLIB_SX128X_REG_CRC_INITIAL_LSB 0x09C9 +#define RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MSB 0x09C7 +#define RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MID (RADIOLIB_SX128X_REG_CRC_INITIAL_MSB) +#define RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_LSB (RADIOLIB_SX128X_REG_CRC_INITIAL_LSB) +#define RADIOLIB_SX128X_REG_SYNCH_ADDRESS_CONTROL 0x09CD +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4 0x09CE +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_3 0x09CF +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_2 0x09D0 +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_1 0x09D1 +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_0 0x09D2 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_4 0x09D3 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_3 0x09D4 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_2 0x09D5 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_1 0x09D6 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_0 0x09D7 +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_4 0x09D8 +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_3 0x09D9 +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_2 0x09DA +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_1 0x09DB +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_0 0x09DC +#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_3 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_3) +#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_2 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_2) +#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_1 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_1) +#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_0 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_0) + +// SX128X SPI command variables +//RADIOLIB_SX128X_CMD_GET_STATUS MSB LSB DESCRIPTION +#define RADIOLIB_SX128X_STATUS_MODE_STDBY_RC 0b01000000 // 7 5 current chip mode: STDBY_RC +#define RADIOLIB_SX128X_STATUS_MODE_STDBY_XOSC 0b01100000 // 7 5 STDBY_XOSC +#define RADIOLIB_SX128X_STATUS_MODE_FS 0b10000000 // 7 5 FS +#define RADIOLIB_SX128X_STATUS_MODE_RX 0b10100000 // 7 5 Rx +#define RADIOLIB_SX128X_STATUS_MODE_TX 0b11000000 // 7 5 Tx +#define RADIOLIB_SX128X_STATUS_CMD_PROCESSED 0b00000100 // 4 2 command status: processing OK +#define RADIOLIB_SX128X_STATUS_DATA_AVAILABLE 0b00001000 // 4 2 data available +#define RADIOLIB_SX128X_STATUS_CMD_TIMEOUT 0b00001100 // 4 2 timeout +#define RADIOLIB_SX128X_STATUS_CMD_ERROR 0b00010000 // 4 2 processing error +#define RADIOLIB_SX128X_STATUS_CMD_FAILED 0b00010100 // 4 2 failed to execute +#define RADIOLIB_SX128X_STATUS_TX_DONE 0b00011000 // 4 2 transmission finished +#define RADIOLIB_SX128X_STATUS_BUSY 0b00000001 // 0 0 chip busy +#define RADIOLIB_SX128X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed + +//RADIOLIB_SX128X_CMD_SET_SLEEP +#define RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH 0b00000000 // 1 1 data buffer behavior in sleep mode: flush +#define RADIOLIB_SX128X_SLEEP_DATA_BUFFER_RETAIN 0b00000010 // 1 1 retain +#define RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH 0b00000000 // 0 0 data RAM (configuration) behavior in sleep mode: flush +#define RADIOLIB_SX128X_SLEEP_DATA_RAM_RETAIN 0b00000001 // 0 0 retain + +//RADIOLIB_SX128X_CMD_SET_STANDBY +#define RADIOLIB_SX128X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator +#define RADIOLIB_SX128X_STANDBY_XOSC 0x01 // 7 0 52 MHz crystal oscillator + +//RADIOLIB_SX128X_CMD_SET_TX + RADIOLIB_SX128X_CMD_SET_RX + RADIOLIB_SX128X_CMD_SET_RX_DUTY_CYCLE +#define RADIOLIB_SX128X_PERIOD_BASE_15_625_US 0x00 // 7 0 time period step: 15.625 us +#define RADIOLIB_SX128X_PERIOD_BASE_62_5_US 0x01 // 7 0 62.5 us +#define RADIOLIB_SX128X_PERIOD_BASE_1_MS 0x02 // 7 0 1 ms +#define RADIOLIB_SX128X_PERIOD_BASE_4_MS 0x03 // 7 0 4 ms + +//RADIOLIB_SX128X_CMD_SET_TX +#define RADIOLIB_SX128X_TX_TIMEOUT_NONE 0x0000 // 15 0 Tx timeout duration: no timeout (Tx single mode) + +//RADIOLIB_SX128X_CMD_SET_RX +#define RADIOLIB_SX128X_RX_TIMEOUT_NONE 0x0000 // 15 0 Rx timeout duration: no timeout (Rx single mode) +#define RADIOLIB_SX128X_RX_TIMEOUT_INF 0xFFFF // 15 0 infinite (Rx continuous mode) + +//RADIOLIB_SX128X_CMD_SET_PACKET_TYPE +#define RADIOLIB_SX128X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: (G)FSK +#define RADIOLIB_SX128X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa +#define RADIOLIB_SX128X_PACKET_TYPE_RANGING 0x02 // 7 0 ranging engine +#define RADIOLIB_SX128X_PACKET_TYPE_FLRC 0x03 // 7 0 FLRC +#define RADIOLIB_SX128X_PACKET_TYPE_BLE 0x04 // 7 0 BLE + +//RADIOLIB_SX128X_CMD_SET_TX_PARAMS +#define RADIOLIB_SX128X_PA_RAMP_02_US 0x00 // 7 0 PA ramp time: 2 us +#define RADIOLIB_SX128X_PA_RAMP_04_US 0x20 // 7 0 4 us +#define RADIOLIB_SX128X_PA_RAMP_06_US 0x40 // 7 0 6 us +#define RADIOLIB_SX128X_PA_RAMP_08_US 0x60 // 7 0 8 us +#define RADIOLIB_SX128X_PA_RAMP_10_US 0x80 // 7 0 10 us +#define RADIOLIB_SX128X_PA_RAMP_12_US 0xA0 // 7 0 12 us +#define RADIOLIB_SX128X_PA_RAMP_16_US 0xC0 // 7 0 16 us +#define RADIOLIB_SX128X_PA_RAMP_20_US 0xE0 // 7 0 20 us + +//RADIOLIB_SX128X_CMD_SET_CAD_PARAMS +#define RADIOLIB_SX128X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 +#define RADIOLIB_SX128X_CAD_ON_2_SYMB 0x20 // 7 0 2 +#define RADIOLIB_SX128X_CAD_ON_4_SYMB 0x40 // 7 0 4 +#define RADIOLIB_SX128X_CAD_ON_8_SYMB 0x60 // 7 0 8 +#define RADIOLIB_SX128X_CAD_ON_16_SYMB 0x80 // 7 0 16 + +//RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS +#define RADIOLIB_SX128X_BLE_GFSK_BR_2_000_BW_2_4 0x04 // 7 0 GFSK/BLE bit rate and bandwidth setting: 2.0 Mbps 2.4 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_1_600_BW_2_4 0x28 // 7 0 1.6 Mbps 2.4 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_2_4 0x4C // 7 0 1.0 Mbps 2.4 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_1_2 0x45 // 7 0 1.0 Mbps 1.2 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4 0x70 // 7 0 0.8 Mbps 2.4 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_1_2 0x69 // 7 0 0.8 Mbps 1.2 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_1_2 0x8D // 7 0 0.5 Mbps 1.2 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_0_6 0x86 // 7 0 0.5 Mbps 0.6 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_1_2 0xB1 // 7 0 0.4 Mbps 1.2 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_0_6 0xAA // 7 0 0.4 Mbps 0.6 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_6 0xCE // 7 0 0.25 Mbps 0.6 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_3 0xC7 // 7 0 0.25 Mbps 0.3 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3 0xEF // 7 0 0.125 Mbps 0.3 MHz +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_35 0x00 // 7 0 GFSK/BLE modulation index: 0.35 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_50 0x01 // 7 0 0.50 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_75 0x02 // 7 0 0.75 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00 0x03 // 7 0 1.00 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_25 0x04 // 7 0 1.25 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_50 0x05 // 7 0 1.50 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_75 0x06 // 7 0 1.75 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_00 0x07 // 7 0 2.00 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_25 0x08 // 7 0 2.25 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_50 0x09 // 7 0 2.50 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_75 0x0A // 7 0 2.75 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_00 0x0B // 7 0 3.00 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_25 0x0C // 7 0 3.25 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_50 0x0D // 7 0 3.50 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_75 0x0E // 7 0 3.75 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00 0x0F // 7 0 4.00 +#define RADIOLIB_SX128X_BLE_GFSK_BT_OFF 0x00 // 7 0 GFSK Gaussian filter BT product: filter disabled +#define RADIOLIB_SX128X_BLE_GFSK_BT_1_0 0x10 // 7 0 1.0 +#define RADIOLIB_SX128X_BLE_GFSK_BT_0_5 0x20 // 7 0 0.5 +#define RADIOLIB_SX128X_FLRC_BR_1_300_BW_1_2 0x45 // 7 0 FLRC bit rate and bandwidth setting: 1.3 Mbps 1.2 MHz +#define RADIOLIB_SX128X_FLRC_BR_1_000_BW_1_2 0x69 // 7 0 1.04 Mbps 1.2 MHz +#define RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6 0x86 // 7 0 0.65 Mbps 0.6 MHz +#define RADIOLIB_SX128X_FLRC_BR_0_520_BW_0_6 0xAA // 7 0 0.52 Mbps 0.6 MHz +#define RADIOLIB_SX128X_FLRC_BR_0_325_BW_0_3 0xC7 // 7 0 0.325 Mbps 0.3 MHz +#define RADIOLIB_SX128X_FLRC_BR_0_260_BW_0_3 0xEB // 7 0 0.260 Mbps 0.3 MHz +#define RADIOLIB_SX128X_FLRC_CR_1_2 0x00 // 7 0 FLRC coding rate: 1/2 +#define RADIOLIB_SX128X_FLRC_CR_3_4 0x02 // 7 0 3/4 +#define RADIOLIB_SX128X_FLRC_CR_1_0 0x04 // 7 0 1/1 +#define RADIOLIB_SX128X_FLRC_BT_OFF 0x00 // 7 0 FLRC Gaussian filter BT product: filter disabled +#define RADIOLIB_SX128X_FLRC_BT_1_0 0x10 // 7 0 1.0 +#define RADIOLIB_SX128X_FLRC_BT_0_5 0x20 // 7 0 0.5 +#define RADIOLIB_SX128X_LORA_SF_5 0x50 // 7 0 LoRa spreading factor: 5 +#define RADIOLIB_SX128X_LORA_SF_6 0x60 // 7 0 6 +#define RADIOLIB_SX128X_LORA_SF_7 0x70 // 7 0 7 +#define RADIOLIB_SX128X_LORA_SF_8 0x80 // 7 0 8 +#define RADIOLIB_SX128X_LORA_SF_9 0x90 // 7 0 9 +#define RADIOLIB_SX128X_LORA_SF_10 0xA0 // 7 0 10 +#define RADIOLIB_SX128X_LORA_SF_11 0xB0 // 7 0 11 +#define RADIOLIB_SX128X_LORA_SF_12 0xC0 // 7 0 12 +#define RADIOLIB_SX128X_LORA_BW_1625_00 0x0A // 7 0 LoRa bandwidth: 1625.0 kHz +#define RADIOLIB_SX128X_LORA_BW_812_50 0x18 // 7 0 812.5 kHz +#define RADIOLIB_SX128X_LORA_BW_406_25 0x26 // 7 0 406.25 kHz +#define RADIOLIB_SX128X_LORA_BW_203_125 0x34 // 7 0 203.125 kHz +#define RADIOLIB_SX128X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 +#define RADIOLIB_SX128X_LORA_CR_4_6 0x02 // 7 0 4/6 +#define RADIOLIB_SX128X_LORA_CR_4_7 0x03 // 7 0 4/7 +#define RADIOLIB_SX128X_LORA_CR_4_8 0x04 // 7 0 4/8 +#define RADIOLIB_SX128X_LORA_CR_4_5_LI 0x05 // 7 0 4/5, long interleaving +#define RADIOLIB_SX128X_LORA_CR_4_6_LI 0x06 // 7 0 4/6, long interleaving +#define RADIOLIB_SX128X_LORA_CR_4_7_LI 0x07 // 7 0 4/7, long interleaving + +//RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_OFF 0x00 // 7 0 GFSK/FLRC sync word used: none +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1 0x10 // 7 0 sync word 1 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_2 0x20 // 7 0 sync word 2 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1_2 0x30 // 7 0 sync words 1 and 2 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_3 0x40 // 7 0 sync word 3 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1_3 0x50 // 7 0 sync words 1 and 3 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_2_3 0x60 // 7 0 sync words 2 and 3 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1_2_3 0x70 // 7 0 sync words 1, 2 and 3 +#define RADIOLIB_SX128X_GFSK_FLRC_PACKET_FIXED 0x00 // 7 0 GFSK/FLRC packet length mode: fixed +#define RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE 0x20 // 7 0 variable +#define RADIOLIB_SX128X_GFSK_FLRC_CRC_OFF 0x00 // 7 0 GFSK/FLRC packet CRC: none +#define RADIOLIB_SX128X_GFSK_FLRC_CRC_1_BYTE 0x10 // 7 0 1 byte +#define RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE 0x20 // 7 0 2 bytes +#define RADIOLIB_SX128X_GFSK_FLRC_CRC_3_BYTE 0x30 // 7 0 3 bytes (FLRC only) +#define RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON 0x00 // 7 0 GFSK/BLE whitening: enabled +#define RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF 0x08 // 7 0 disabled +#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_MAX_31 0x00 // 7 0 BLE maximum payload length: 31 bytes +#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_MAX_37 0x20 // 7 0 37 bytes +#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_TEST 0x40 // 7 0 63 bytes (test mode) +#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_MAX_255 0x80 // 7 0 255 bytes (Bluetooth 4.2 and above) +#define RADIOLIB_SX128X_BLE_CRC_OFF 0x00 // 7 0 BLE packet CRC: none +#define RADIOLIB_SX128X_BLE_CRC_3_BYTE 0x10 // 7 0 3 byte +#define RADIOLIB_SX128X_BLE_PRBS_9 0x00 // 7 0 BLE test payload contents: PRNG sequence using x^9 + x^5 + x +#define RADIOLIB_SX128X_BLE_EYELONG 0x04 // 7 0 repeated 0xF0 +#define RADIOLIB_SX128X_BLE_EYESHORT 0x08 // 7 0 repeated 0xAA +#define RADIOLIB_SX128X_BLE_PRBS_15 0x0C // 7 0 PRNG sequence using x^15 + x^14 + x^13 + x^12 + x^2 + x + 1 +#define RADIOLIB_SX128X_BLE_ALL_1 0x10 // 7 0 repeated 0xFF +#define RADIOLIB_SX128X_BLE_ALL_0 0x14 // 7 0 repeated 0x00 +#define RADIOLIB_SX128X_BLE_EYELONG_INV 0x18 // 7 0 repeated 0x0F +#define RADIOLIB_SX128X_BLE_EYESHORT_INV 0x1C // 7 0 repeated 0x55 +#define RADIOLIB_SX128X_FLRC_SYNC_WORD_OFF 0x00 // 7 0 FLRC sync word: disabled +#define RADIOLIB_SX128X_FLRC_SYNC_WORD_ON 0x04 // 7 0 enabled +#define RADIOLIB_SX128X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit +#define RADIOLIB_SX128X_LORA_HEADER_IMPLICIT 0x80 // 7 0 implicit +#define RADIOLIB_SX128X_LORA_CRC_OFF 0x00 // 7 0 LoRa packet CRC: disabled +#define RADIOLIB_SX128X_LORA_CRC_ON 0x20 // 7 0 enabled +#define RADIOLIB_SX128X_LORA_IQ_STANDARD 0x40 // 7 0 LoRa IQ: standard +#define RADIOLIB_SX128X_LORA_IQ_INVERTED 0x00 // 7 0 inverted + +//RADIOLIB_SX128X_CMD_GET_PACKET_STATUS +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_ERROR 0b01000000 // 6 6 packet status errors byte: sync word error +#define RADIOLIB_SX128X_PACKET_STATUS_LENGTH_ERROR 0b00100000 // 5 5 packet length error +#define RADIOLIB_SX128X_PACKET_STATUS_CRC_ERROR 0b00010000 // 4 4 CRC error +#define RADIOLIB_SX128X_PACKET_STATUS_ABORT_ERROR 0b00001000 // 3 3 packet reception aborted +#define RADIOLIB_SX128X_PACKET_STATUS_HEADER_RECEIVED 0b00000100 // 2 2 header received +#define RADIOLIB_SX128X_PACKET_STATUS_PACKET_RECEIVED 0b00000010 // 1 1 packet received +#define RADIOLIB_SX128X_PACKET_STATUS_PACKET_CTRL_BUSY 0b00000001 // 0 0 packet controller is busy +#define RADIOLIB_SX128X_PACKET_STATUS_RX_PID 0b11000000 // 7 6 packet status status byte: PID field of the received packet +#define RADIOLIB_SX128X_PACKET_STATUS_NO_ACK 0b00100000 // 5 5 NO_ACK field of the received packet +#define RADIOLIB_SX128X_PACKET_STATUS_RX_PID_ERROR 0b00010000 // 4 4 PID field error +#define RADIOLIB_SX128X_PACKET_STATUS_PACKET_SENT 0b00000001 // 0 0 packet sent +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_ERROR 0b00000000 // 2 0 packet status sync byte: sync word detection error +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_1 0b00000001 // 2 0 detected sync word 1 +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_2 0b00000010 // 2 0 detected sync word 2 +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_3 0b00000100 // 2 0 detected sync word 3 + +//RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS +#define RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED 0x8000 // 15 15 interrupt source: preamble detected +#define RADIOLIB_SX128X_IRQ_ADVANCED_RANGING_DONE 0x8000 // 15 15 advanced ranging done +#define RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT 0x4000 // 14 14 Rx or Tx timeout +#define RADIOLIB_SX128X_IRQ_CAD_DETECTED 0x2000 // 13 13 channel activity detected +#define RADIOLIB_SX128X_IRQ_CAD_DONE 0x1000 // 12 12 CAD finished +#define RADIOLIB_SX128X_IRQ_RANGING_SLAVE_REQ_VALID 0x0800 // 11 11 ranging request valid (slave) +#define RADIOLIB_SX128X_IRQ_RANGING_MASTER_TIMEOUT 0x0400 // 10 10 ranging timeout (master) +#define RADIOLIB_SX128X_IRQ_RANGING_MASTER_RES_VALID 0x0200 // 9 9 ranging result valid (master) +#define RADIOLIB_SX128X_IRQ_RANGING_SLAVE_REQ_DISCARD 0x0100 // 8 8 ranging result valid (master) +#define RADIOLIB_SX128X_IRQ_RANGING_SLAVE_RESP_DONE 0x0080 // 7 7 ranging response complete (slave) +#define RADIOLIB_SX128X_IRQ_CRC_ERROR 0x0040 // 6 6 CRC error +#define RADIOLIB_SX128X_IRQ_HEADER_ERROR 0x0020 // 5 5 header error +#define RADIOLIB_SX128X_IRQ_HEADER_VALID 0x0010 // 4 4 header valid +#define RADIOLIB_SX128X_IRQ_SYNC_WORD_ERROR 0x0008 // 3 3 sync word error +#define RADIOLIB_SX128X_IRQ_SYNC_WORD_VALID 0x0004 // 2 2 sync word valid +#define RADIOLIB_SX128X_IRQ_RX_DONE 0x0002 // 1 1 Rx done +#define RADIOLIB_SX128X_IRQ_TX_DONE 0x0001 // 0 0 Tx done +#define RADIOLIB_SX128X_IRQ_RX_DEFAULT 0x4062 // 15 0 default for Rx (RX_DONE, RX_TX_TIMEOUT, CRC_ERROR and HEADER_ERROR) +#define RADIOLIB_SX128X_IRQ_NONE 0x0000 // 15 0 none +#define RADIOLIB_SX128X_IRQ_ALL 0xFFFF // 15 0 all + +//RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE +#define RADIOLIB_SX128X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) +#define RADIOLIB_SX128X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC + +//RADIOLIB_SX128X_CMD_SET_RANGING_ROLE +#define RADIOLIB_SX128X_RANGING_ROLE_MASTER 0x01 // 7 0 ranging role: master +#define RADIOLIB_SX128X_RANGING_ROLE_SLAVE 0x00 // 7 0 slave + +//RADIOLIB_SX128X_REG_LORA_SYNC_WORD_1 - RADIOLIB_SX128X_REG_LORA_SYNC_WORD_2 +#define RADIOLIB_SX128X_SYNC_WORD_PRIVATE 0x12 + +/*! + \class SX128x + \brief Base class for %SX128x series. All derived classes for %SX128x (e.g. SX1280 or SX1281) inherit from this base class. + This class should not be instantiated directly from Arduino sketch, only from its derived classes. +*/ +class SX128x: public PhysicalLayer { + public: + // introduce PhysicalLayer overloads + using PhysicalLayer::transmit; + using PhysicalLayer::receive; + using PhysicalLayer::startTransmit; + using PhysicalLayer::readData; + + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX128x(Module* mod); + + // basic methods + + /*! + \brief Initialization method for LoRa modem. + \param freq Carrier frequency in MHz. Defaults to 2400.0 MHz. + \param bw LoRa bandwidth in kHz. Defaults to 812.5 kHz. + \param sf LoRa spreading factor. Defaults to 9. + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + \param syncWord 2-byte LoRa sync word. Defaults to RADIOLIB_SX128X_SYNC_WORD_PRIVATE (0x12). + \param pwr Output power in dBm. Defaults to 10 dBm. + \param preambleLength LoRa preamble length in symbols. Defaults to 12 symbols. + \returns \ref status_codes + */ + int16_t begin(float freq = 2400.0, float bw = 812.5, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX128X_SYNC_WORD_PRIVATE, int8_t pwr = 10, uint16_t preambleLength = 12); + + /*! + \brief Initialization method for GFSK modem. + \param freq Carrier frequency in MHz. Defaults to 2400.0 MHz. + \param br FSK bit rate in kbps. Defaults to 800 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 400.0 kHz. + \param pwr Output power in dBm. Defaults to 10 dBm. + \param preambleLength FSK preamble length in bits. Defaults to 16 bits. + \returns \ref status_codes + */ + int16_t beginGFSK(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t pwr = 10, uint16_t preambleLength = 16); + + /*! + \brief Initialization method for BLE modem. + \param freq Carrier frequency in MHz. Defaults to 2400.0 MHz. + \param br BLE bit rate in kbps. Defaults to 800 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 400.0 kHz. + \param pwr Output power in dBm. Defaults to 10 dBm. + \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. + \returns \ref status_codes + */ + int16_t beginBLE(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t pwr = 10, uint8_t dataShaping = RADIOLIB_SHAPING_0_5); + + /*! + \brief Initialization method for FLRC modem. + \param freq Carrier frequency in MHz. Defaults to 2400.0 MHz. + \param br FLRC bit rate in kbps. Defaults to 650 kbps. + \param cr FLRC coding rate. Defaults to 3 (coding rate 3/4). + \param pwr Output power in dBm. Defaults to 10 dBm. + \param preambleLength FLRC preamble length in bits. Defaults to 16 bits. + \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. + \returns \ref status_codes + */ + int16_t beginFLRC(float freq = 2400.0, uint16_t br = 650, uint8_t cr = 3, int8_t pwr = 10, uint16_t preambleLength = 16, uint8_t dataShaping = RADIOLIB_SHAPING_0_5); + + /*! + \brief Reset method. Will reset the chip to the default state using RST pin. + \param verify Whether correct module startup should be verified. When set to true, RadioLib will attempt to verify the module has started correctly + by repeatedly issuing setStandby command. Enabled by default. + \returns \ref status_codes + */ + int16_t reset(bool verify = true); + + /*! + \brief Blocking binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \param addr Address to send the data to. Unsupported, compatibility only. + \returns \ref status_codes + */ + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Blocking binary receive method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \returns \ref status_codes + */ + int16_t receive(uint8_t* data, size_t len) override; + + /*! + \brief Starts direct mode transmission. + \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. + \returns \ref status_codes + */ + int16_t transmitDirect(uint32_t frf = 0) override; + + /*! + \brief Starts direct mode reception. Only implemented for PhysicalLayer compatibility, + as %SX128x series does not support direct mode reception. Will always return RADIOLIB_ERR_UNKNOWN. + \returns \ref status_codes + */ + int16_t receiveDirect() override; + + /*! + \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. + \returns \ref status_codes + */ + int16_t scanChannel(); + + /*! + \brief Sets the module to sleep mode. To wake the device up, call standby(). + \param retainConfig Set to true to retain configuration and data buffer or to false + to discard current configuration and data buffer. Defaults to true. + \returns \ref status_codes + */ + int16_t sleep(bool retainConfig = true); + + /*! + \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). + \returns \ref status_codes + */ + int16_t standby() override; + + /*! + \brief Sets the module to standby mode. + \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX128X_STANDBY_RC + (13 MHz RC oscillator) or RADIOLIB_SX128X_STANDBY_XOSC (52 MHz external crystal oscillator). + \param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module. + \returns \ref status_codes + */ + int16_t standby(uint8_t mode, bool wakeup = false); + + // interrupt methods + + /*! + \brief Sets interrupt service routine to call when DIO1 activates. + \param func ISR to call. + */ + void setDio1Action(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when DIO1 activates. + */ + void clearDio1Action(); + + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + + /*! + \brief Interrupt-driven binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \param addr Address to send the data to. Unsupported, compatibility only. + \returns \ref status_codes + */ + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Clean up after transmission is done. + \returns \ref status_codes + */ + int16_t finishTransmit() override; + + /*! + \brief Interrupt-driven receive method with default parameters. + Implemented for compatibility with PhysicalLayer. + + \returns \ref status_codes + */ + int16_t startReceive(); + + /*! + \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. + \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to + RADIOLIB_SX128X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), + set to RADIOLIB_SX128X_RX_TIMEOUT_NONE for no timeout (Rx single mode). + If timeout other than infinite is set, signal will be generated on DIO1. + + \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX128X_IRQ_RX_DEFAULT. + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX128X_IRQ_RX_DONE. + \param len Only for PhysicalLayer compatibility, not used. + \returns \ref status_codes + */ + int16_t startReceive(uint16_t timeout, uint16_t irqFlags = RADIOLIB_SX128X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX128X_IRQ_RX_DONE, size_t len = 0); + + /*! + \brief Reads the current IRQ status. + \returns IRQ status bits + */ + uint16_t getIrqStatus(); + + /*! + \brief Reads data received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. + \returns \ref status_codes + */ + int16_t readData(uint8_t* data, size_t len) override; + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values are in range from 2400.0 to 2500.0 MHz. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets LoRa bandwidth. Allowed values are 203.125, 406.25, 812.5 and 1625.0 kHz. + \param bw LoRa bandwidth to be set in kHz. + \returns \ref status_codes + */ + int16_t setBandwidth(float bw); + + /*! + \brief Sets LoRa spreading factor. Allowed values range from 5 to 12. + \param sf LoRa spreading factor to be set. + \returns \ref status_codes + */ + int16_t setSpreadingFactor(uint8_t sf); + + /*! + \brief Sets LoRa coding rate denominator. Allowed values range from 5 to 8. + \param cr LoRa coding rate denominator to be set. + \param longInterleaving Whether to enable long interleaving mode. Not available for coding rate 4/7, + defaults to false. + \returns \ref status_codes + */ + int16_t setCodingRate(uint8_t cr, bool longInterleaving = false); + + /*! + \brief Sets output power. Allowed values are in range from -18 to 13 dBm. + \param pwr Output power to be set in dBm. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t pwr); + + /*! + \brief Sets preamble length for currently active modem. Allowed values range from 1 to 65535. + \param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK/BLE/FLRC). + \returns \ref status_codes + */ + int16_t setPreambleLength(uint32_t preambleLength); + + /*! + \brief Sets FSK or FLRC bit rate. Allowed values are 125, 250, 400, 500, 800, 1000, + 1600 and 2000 kbps (for FSK modem) or 260, 325, 520, 650, 1000 and 1300 (for FLRC modem). + \param br FSK/FLRC bit rate to be set in kbps. + \returns \ref status_codes + */ + int16_t setBitRate(float br); + + /*! + \brief Sets FSK frequency deviation. Allowed values range from 0.0 to 3200.0 kHz. + \param freqDev FSK frequency deviation to be set in kHz. + \returns \ref status_codes + */ + int16_t setFrequencyDeviation(float freqDev) override; + + /*! + \brief Sets time-bandwidth product of Gaussian filter applied for shaping. + Allowed values are RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. + \param sh Time-bandwidth product of Gaussian filter to be set. + \returns \ref status_codes + */ + int16_t setDataShaping(uint8_t sh) override; + + /*! + \brief Sets FSK/FLRC sync word in the form of array of up to 5 bytes (FSK). For FLRC modem, + the sync word must be exactly 4 bytes long + \param syncWord Sync word to be set. + \param len Sync word length in bytes. + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t* syncWord, uint8_t len); + + /*! + \brief Sets LoRa sync word. + \param syncWord LoRa sync word to be set. + \param controlBits Undocumented control bits, required for compatibility purposes. + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t syncWord, uint8_t controlBits = 0x44); + + /*! + \brief Sets CRC configuration. + \param len CRC length in bytes, Allowed values are 1, 2 or 3, set to 0 to disable CRC. + \param initial Initial CRC value. Defaults to 0x1D0F (CCIT CRC), not available for LoRa modem. + \param polynomial Polynomial for CRC calculation. Defaults to 0x1021 (CCIT CRC), not available for LoRa or BLE modem. + \returns \ref status_codes + */ + int16_t setCRC(uint8_t len, uint32_t initial = 0x1D0F, uint16_t polynomial = 0x1021); + + /*! + \brief Sets whitening parameters, not available for LoRa or FLRC modem. + \param enabled Set to true to enable whitening. + \returns \ref status_codes + */ + int16_t setWhitening(bool enabled); + + /*! + \brief Sets BLE access address. + \param addr BLE access address. + \returns \ref status_codes + */ + int16_t setAccessAddress(uint32_t addr); + + /*! + \brief Enables or disables receiver high sensitivity mode. + \param enable True to enable and false to disable. + \returns \ref status_codes + */ + int16_t setHighSensitivityMode(bool enable); + + /*! + \brief Enables or disables receiver manual gain control. + \param gain Use 0 for automatic gain, 1 for minimum gain and up to 13 for maximum gain. + \returns \ref status_codes + */ + int16_t setGainControl(uint8_t gain = 0); + + /*! + \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. + \returns RSSI of the last received packet in dBm. + */ + float getRSSI(); + + /*! + \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa or ranging modem. + \returns SNR of the last received packet in dB. + */ + float getSNR(); + + /*! + \brief Gets frequency error of the latest received packet. + \returns Frequency error in Hz. + */ + float getFrequencyError(); + + /*! + \brief Query modem for the packet length of received payload. + \param update Update received packet length. Will return cached value when set to false. + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update = true) override; + + /*! + \brief Get expected time-on-air for a given size of payload. + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + uint32_t getTimeOnAir(size_t len); + + /*! + \brief Set implicit header mode for future reception/transmission. + \returns \ref status_codes + */ + int16_t implicitHeader(size_t len); + + /*! + \brief Set explicit header mode for future reception/transmission. + \param len Payload length in bytes. + \returns \ref status_codes + */ + int16_t explicitHeader(); + + /*! + \brief Sets transmission encoding. Serves only as alias for PhysicalLayer compatibility. + \param encoding Encoding to be used. Set to 0 for NRZ, and 2 for whitening. + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding) override; + + /*! \copydoc Module::setRfSwitchPins */ + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); + + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + + /*! + \brief Dummy random method, to ensure PhysicalLayer compatibility. + \returns Always returns 0. + */ + uint8_t randomByte(); + + /*! + \brief Enable/disable inversion of the I and Q signals + \param enable QI inversion enabled (true) or disabled (false); + \returns \ref status_codes + */ + int16_t invertIQ(bool enable); + + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE + /*! + \brief Dummy method, to ensure PhysicalLayer compatibility. + \param func Ignored. + */ + void setDirectAction(void (*func)(void)); + + /*! + \brief Dummy method, to ensure PhysicalLayer compatibility. + \param pin Ignored. + */ + void readBit(uint32_t pin); + #endif + +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL + protected: +#endif + Module* getMod(); + + // cached LoRa parameters + float bandwidthKhz = 0; + uint8_t bandwidth = 0, spreadingFactor = 0, codingRateLoRa = 0; + uint8_t preambleLengthLoRa = 0, headerType = 0, payloadLen = 0, crcLoRa = 0; + + // SX128x SPI command implementations + uint8_t getStatus(); + int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); + int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); + int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); + int16_t readBuffer(uint8_t* data, uint8_t numBytes); + int16_t setTx(uint16_t periodBaseCount = RADIOLIB_SX128X_TX_TIMEOUT_NONE, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US); + int16_t setRx(uint16_t periodBaseCount, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US); + int16_t setCad(); + uint8_t getPacketType(); + int16_t setRfFrequency(uint32_t frf); + int16_t setTxParams(uint8_t pwr, uint8_t rampTime = RADIOLIB_SX128X_PA_RAMP_10_US); + int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00); + int16_t setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3); + int16_t setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t payLen = 0xFF, uint8_t hdrType = RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE); + int16_t setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTest, uint8_t whiten); + int16_t setPacketParamsLoRa(uint8_t preambleLen, uint8_t hdrType, uint8_t payLen, uint8_t crc, uint8_t invIQ = RADIOLIB_SX128X_LORA_IQ_STANDARD); + int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX128X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX128X_IRQ_NONE); + int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX128X_IRQ_ALL); + int16_t setRangingRole(uint8_t role); + int16_t setPacketType(uint8_t type); + +#if !RADIOLIB_GODMODE + private: +#endif + Module* mod; + + // common low-level SPI interface + static int16_t SPIparseStatus(uint8_t in); + + // common parameters + uint8_t power = 0; + + // cached LoRa parameters + uint8_t invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_STANDARD; + + // cached GFSK parameters + float modIndexReal = 0; + uint16_t bitRateKbps = 0; + uint8_t bitRate = 0, modIndex = 0, shaping = 0; + uint8_t preambleLengthGFSK = 0, syncWordLen = 0, syncWordMatch = 0, crcGFSK = 0, whitening = 0; + + // cached FLRC parameters + uint8_t codingRateFLRC = 0; + + // cached BLE parameters + uint8_t connectionState = 0, crcBLE = 0, bleTestPayload = 0; + + int16_t config(uint8_t modem); + int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/Si443x/Si4430.cpp b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4430.cpp new file mode 100644 index 000000000..7f9ed5fbe --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4430.cpp @@ -0,0 +1,39 @@ +#include "Si4430.h" +#if !RADIOLIB_EXCLUDE_SI443X + +Si4430::Si4430(Module* mod) : Si4432(mod) { + +} + +int16_t Si4430::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { + // execute common part + int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSi4430"); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t Si4430::setFrequency(float freq) { + RADIOLIB_CHECK_RANGE(freq, 900.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); + + // set frequency + return(Si443x::setFrequencyRaw(freq)); +} + +int16_t Si4430::setOutputPower(int8_t power) { + RADIOLIB_CHECK_RANGE(power, -8, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + // set output power + Module* mod = this->getMod(); + return(mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/Si443x/Si4430.h b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4430.h new file mode 100644 index 000000000..6acac97d1 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4430.h @@ -0,0 +1,67 @@ +#if !defined(_RADIOLIB_SI4430_H) +#define _RADIOLIB_SI4430_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SI443X + +#include "../../Module.h" +#include "Si4432.h" + +/*! + \class Si4430 + \brief Derived class for %Si4430 modules. +*/ +class Si4430: public Si4432 { + public: + + // constructor + + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio chip. + */ + Si4430(Module* mod); + + // basic methods + + /*! + \brief Initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 900.0 MHz to 960.0 MHz. + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 0.123 to 256.0 kbps. + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.625 to 320.0 kbps. + \param rxBw Receiver bandwidth in kHz. Allowed values range from 2.6 to 620.7 kHz. + \param power Transmission output power in dBm. Allowed values range from -8 to 13 dBm in 3 dBm steps. + \param preambleLen Preamble Length in bits. Defaults to 16 bits. + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values range from 900.0 MHz to 960.0 MHz. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets output power. Allowed values range from -8 to 13 dBm in 3 dBm steps. + \param power Output power to be set in dBm. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power); + +#if !RADIOLIB_GODMODE + protected: +#endif + +#if !RADIOLIB_GODMODE + private: +#endif +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/Si443x/Si4431.cpp b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4431.cpp new file mode 100644 index 000000000..c603e6f15 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4431.cpp @@ -0,0 +1,32 @@ +#include "Si4431.h" +#if !RADIOLIB_EXCLUDE_SI443X + +Si4431::Si4431(Module* mod) : Si4432(mod) { + +} + +int16_t Si4431::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { + // execute common part + int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSi4431"); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t Si4431::setOutputPower(int8_t power) { + RADIOLIB_CHECK_RANGE(power, -8, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + // set output power + Module* mod = this->getMod(); + return(mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/Si443x/Si4431.h b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4431.h new file mode 100644 index 000000000..8d3d9dd92 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4431.h @@ -0,0 +1,60 @@ +#if !defined(_RADIOLIB_SI4431_H) +#define _RADIOLIB_SI4431_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SI443X + +#include "../../Module.h" +#include "Si4432.h" + +/*! + \class Si4431 + \brief Derived class for %Si4431 modules. +*/ +class Si4431: public Si4432 { + public: + + // constructor + + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio chip. + */ + Si4431(Module* mod); + + // basic methods + + /*! + \brief Initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 240.0 MHz to 930.0 MHz. + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 0.123 to 256.0 kbps. + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.625 to 320.0 kbps. + \param rxBw Receiver bandwidth in kHz. Allowed values range from 2.6 to 620.7 kHz. + \param power Transmission output power in dBm. Allowed values range from -8 to 13 dBm in 3 dBm steps. + \param preambleLen Preamble Length in bits. Defaults to 16 bits. + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); + + // configuration methods + + /*! + \brief Sets output power. Allowed values range from -8 to 13 dBm in 3 dBm steps. + \param power Output power to be set in dBm. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power); + +#if !RADIOLIB_GODMODE + protected: +#endif + +#if !RADIOLIB_GODMODE + private: +#endif +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/Si443x/Si4432.cpp b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4432.cpp new file mode 100644 index 000000000..56690862f --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4432.cpp @@ -0,0 +1,39 @@ +#include "Si4432.h" +#if !RADIOLIB_EXCLUDE_SI443X + +Si4432::Si4432(Module* mod) : Si443x(mod) { + +} + +int16_t Si4432::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { + // execute common part + int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSi4432"); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t Si4432::setFrequency(float freq) { + RADIOLIB_CHECK_RANGE(freq, 240.0, 930.0, RADIOLIB_ERR_INVALID_FREQUENCY); + + // set frequency + return(Si443x::setFrequencyRaw(freq)); +} + +int16_t Si4432::setOutputPower(int8_t power) { + RADIOLIB_CHECK_RANGE(power, -1, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + // set output power + Module* mod = this->getMod(); + return(mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 1) / 3), 2, 0)); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/Si443x/Si4432.h b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4432.h new file mode 100644 index 000000000..b0a8cb877 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/Si443x/Si4432.h @@ -0,0 +1,67 @@ +#if !defined(_RADIOLIB_SI4432_H) +#define _RADIOLIB_SI4432_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SI443X + +#include "../../Module.h" +#include "Si443x.h" + +/*! + \class Si4432 + \brief Derived class for %Si4432 modules. +*/ +class Si4432: public Si443x { + public: + + // constructor + + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio chip. + */ + Si4432(Module* mod); + + // basic methods + + /*! + \brief Initialization method. Must be called at least once from Arduino sketch to initialize the module. + \param freq Carrier frequency in MHz. Allowed values range from 240.0 MHz to 930.0 MHz. + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 0.123 to 256.0 kbps. + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.625 to 320.0 kbps. + \param rxBw Receiver bandwidth in kHz. Allowed values range from 2.6 to 620.7 kHz. + \param power Transmission output power in dBm. Allowed values range from -1 to 20 dBm in 3 dBm steps. + \param preambleLen Preamble Length in bits. Defaults to 16 bits. + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values range from 240.0 MHz to 930.0 MHz. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets output power. Allowed values range from -1 to 20 dBm in 3 dBm steps. + \param power Output power to be set in dBm. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power); + +#if !RADIOLIB_GODMODE + protected: +#endif + +#if !RADIOLIB_GODMODE + private: +#endif +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/Si443x/Si443x.cpp b/lib/lib_rf/RadioLib/src/modules/Si443x/Si443x.cpp new file mode 100644 index 000000000..541f3eb74 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/Si443x/Si443x.cpp @@ -0,0 +1,813 @@ +#include "Si443x.h" +#include +#if !RADIOLIB_EXCLUDE_SI443X + +Si443x::Si443x(Module* mod) : PhysicalLayer(RADIOLIB_SI443X_FREQUENCY_STEP_SIZE, RADIOLIB_SI443X_MAX_PACKET_LENGTH) { + this->mod = mod; +} + +int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + + // try to find the Si443x chip + if(!Si443x::findChip()) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No Si443x found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } else { + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSi443x"); + } + + // reset the device + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_SOFTWARE_RESET); + + // clear POR interrupt + clearIRQFlags(); + + // configure settings not accessible by API + int16_t state = config(); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + state = setRxBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLen); + RADIOLIB_ASSERT(state); + + uint8_t syncWord[] = {0x12, 0xAD}; + state = setSyncWord(syncWord, sizeof(syncWord)); + RADIOLIB_ASSERT(state); + + state = packetMode(); + RADIOLIB_ASSERT(state); + + state = setDataShaping(0); + RADIOLIB_ASSERT(state); + + state = setEncoding(0); + RADIOLIB_ASSERT(state); + + state = variablePacketLengthMode(); + + return(state); +} + +void Si443x::reset() { + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + this->mod->hal->delay(1); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + this->mod->hal->delay(100); +} + +int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { + // calculate timeout (5ms + 500 % of expected time-on-air) + uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (this->bitRate * 1000.0)) * 5000000.0); + + // start transmission + int16_t state = startTransmit(data, len, addr); + RADIOLIB_ASSERT(state); + + // wait for transmission end or timeout + uint32_t start = this->mod->hal->micros(); + while(this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { + finishTransmit(); + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + + return(finishTransmit()); +} + +int16_t Si443x::receive(uint8_t* data, size_t len) { + // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) + uint32_t timeout = 500000 + (1.0/(this->bitRate*1000.0))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0); + + // start reception + int16_t state = startReceive(); + RADIOLIB_ASSERT(state); + + // wait for packet reception or timeout + uint32_t start = this->mod->hal->micros(); + while(this->mod->hal->digitalRead(this->mod->getIrq())) { + if(this->mod->hal->micros() - start > timeout) { + standby(); + clearIRQFlags(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } + + // read packet data + return(readData(data, len)); +} + +int16_t Si443x::sleep() { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + // disable wakeup timer interrupt + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, 0x00); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + RADIOLIB_ASSERT(state); + + // enable wakeup timer to set mode to sleep + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_ENABLE_WAKEUP_TIMER); + + return(state); +} + +int16_t Si443x::standby() { + return(standby(RADIOLIB_SI443X_XTAL_ON)); +} + +int16_t Si443x::standby(uint8_t mode) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, mode, 7, 0, 10)); +} + +int16_t Si443x::transmitDirect(uint32_t frf) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_TX); + + // user requested to start transmitting immediately (required for RTTY) + if(frf != 0) { + // convert the 24-bit frequency to the format accepted by the module + /// \todo integers only + float newFreq = frf / 6400.0; + + // check high/low band + uint8_t bandSelect = RADIOLIB_SI443X_BAND_SELECT_LOW; + uint8_t freqBand = (newFreq / 10) - 24; + if(newFreq >= 480.0) { + bandSelect = RADIOLIB_SI443X_BAND_SELECT_HIGH; + freqBand = (newFreq / 20) - 24; + } + + // calculate register values + uint16_t freqCarrier = ((newFreq / (10 * ((bandSelect >> 5) + 1))) - freqBand - 24) * (uint32_t)64000; + + // update registers + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT, RADIOLIB_SI443X_SIDE_BAND_SELECT_LOW | bandSelect | freqBand); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); + + // start direct transmission + directMode(); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); + + return(RADIOLIB_ERR_NONE); + } + + // activate direct mode + int16_t state = directMode(); + RADIOLIB_ASSERT(state); + + // start transmitting + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); + return(state); +} + +int16_t Si443x::receiveDirect() { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // activate direct mode + int16_t state = directMode(); + RADIOLIB_ASSERT(state); + + // start receiving + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); + return(state); +} + +int16_t Si443x::packetMode() { + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_FSK, 1, 0); + RADIOLIB_ASSERT(state); + + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_TX_DATA_SOURCE_FIFO, 5, 4)); +} + +void Si443x::setIrqAction(void (*func)(void)) { + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptFalling); +} + +void Si443x::clearIrqAction() { + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); +} + +void Si443x::setPacketReceivedAction(void (*func)(void)) { + this->setIrqAction(func); +} + +void Si443x::clearPacketReceivedAction() { + this->clearIrqAction(); +} + +void Si443x::setPacketSentAction(void (*func)(void)) { + this->setIrqAction(func); +} + +void Si443x::clearPacketSentAction() { + this->clearIrqAction(); +} + +int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { + // check packet length + if(len > RADIOLIB_SI443X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // clear Tx FIFO + this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_TX_FIFO_RESET, 0, 0); + this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_TX_FIFO_CLEAR, 0, 0); + + // clear interrupt flags + clearIRQFlags(); + + // set packet length + if (this->packetLengthConfig == RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF) { + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); + } + + /// \todo use header as address field? + (void)addr; + + // write packet to FIFO + this->mod->SPIwriteRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, data, len); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_TX); + + // set interrupt mapping + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_PACKET_SENT_ENABLED); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + + // set mode to transmit + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); + + return(state); +} + +int16_t Si443x::finishTransmit() { + // clear interrupt flags + clearIRQFlags(); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + +int16_t Si443x::startReceive() { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // clear Rx FIFO + this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_RX_FIFO_RESET, 1, 1); + this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_RX_FIFO_CLEAR, 1, 1); + + // clear interrupt flags + clearIRQFlags(); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // set interrupt mapping + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED | RADIOLIB_SI443X_CRC_ERROR_ENABLED); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + + // set mode to receive + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); + + return(state); +} + +int16_t Si443x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)timeout; + (void)irqFlags; + (void)irqMask; + (void)len; + return(startReceive()); +} + +int16_t Si443x::readData(uint8_t* data, size_t len) { + // clear interrupt flags + clearIRQFlags(); + + // get packet length + size_t length = getPacketLength(); + size_t dumpLen = 0; + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + dumpLen = length - len; + length = len; + } + + // read packet data + this->mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, length, data); + + // dump the bytes that weren't requested + if(dumpLen != 0) { + clearFIFO(dumpLen); + } + + // clear internal flag so getPacketLength can return the new packet length + this->packetLengthQueried = false; + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + clearIRQFlags(); + + return(RADIOLIB_ERR_NONE); +} + +int16_t Si443x::setBitRate(float br) { + RADIOLIB_CHECK_RANGE(br, 0.123, 256.0, RADIOLIB_ERR_INVALID_BIT_RATE); + + // check high data rate + uint8_t dataRateMode = RADIOLIB_SI443X_LOW_DATA_RATE_MODE; + uint8_t exp = 21; + if(br >= 30.0) { + // bit rate above 30 kbps + dataRateMode = RADIOLIB_SI443X_HIGH_DATA_RATE_MODE; + exp = 16; + } + + // calculate raw data rate value + uint16_t txDr = (br * ((uint32_t)1 << exp)) / 1000.0; + + // update registers + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, dataRateMode, 5, 5); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TX_DATA_RATE_1, (uint8_t)((txDr & 0xFF00) >> 8)); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TX_DATA_RATE_0, (uint8_t)(txDr & 0xFF)); + + if(state == RADIOLIB_ERR_NONE) { + this->bitRate = br; + } + RADIOLIB_ASSERT(state); + + // update clock recovery + state = updateClockRecovery(); + + return(state); +} + +int16_t Si443x::setFrequencyDeviation(float freqDev) { + // set frequency deviation to lowest available setting (required for digimodes) + float newFreqDev = freqDev; + if(freqDev < 0.0) { + newFreqDev = 0.625; + } + + RADIOLIB_CHECK_RANGE(newFreqDev, 0.625, 320.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + + // calculate raw frequency deviation value + uint16_t fdev = (uint16_t)(newFreqDev / 0.625); + + // update registers + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, (uint8_t)((fdev & 0x0100) >> 6), 2, 2); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_FREQUENCY_DEVIATION, (uint8_t)(fdev & 0xFF)); + + if(state == RADIOLIB_ERR_NONE) { + this->frequencyDev = newFreqDev; + } + + return(state); +} + +int16_t Si443x::setRxBandwidth(float rxBw) { + RADIOLIB_CHECK_RANGE(rxBw, 2.6, 620.7, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); + + // decide which approximation to use for decimation rate and filter tap calculation + uint8_t bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_OFF; + uint8_t decRate = RADIOLIB_SI443X_IF_FILTER_DEC_RATE; + uint8_t filterSet = RADIOLIB_SI443X_IF_FILTER_COEFF_SET; + + // this is the "well-behaved" section - can be linearly approximated + if((rxBw >= 2.6) && (rxBw <= 4.5)) { + decRate = 5; + filterSet = ((rxBw - 2.1429)/0.3250 + 0.5); + } else if((rxBw > 4.5) && (rxBw <= 8.8)) { + decRate = 4; + filterSet = ((rxBw - 3.9857)/0.6643 + 0.5); + } else if((rxBw > 8.8) && (rxBw <= 17.5)) { + decRate = 3; + filterSet = ((rxBw - 7.6714)/1.3536 + 0.5); + } else if((rxBw > 17.5) && (rxBw <= 34.7)) { + decRate = 2; + filterSet = ((rxBw - 15.2000)/2.6893 + 0.5); + } else if((rxBw > 34.7) && (rxBw <= 69.2)) { + decRate = 1; + filterSet = ((rxBw - 30.2430)/5.3679 + 0.5); + } else if((rxBw > 69.2) && (rxBw <= 137.9)) { + decRate = 0; + filterSet = ((rxBw - 60.286)/10.7000 + 0.5); + + // this is the "Lord help thee who tread 'ere" section - no way to approximate this mess + /// \todo float tolerance equality as macro? + } else if(fabs(rxBw - 142.8) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 1; + filterSet = 4; + } else if(fabs(rxBw - 167.8) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 1; + filterSet = 5; + } else if(fabs(rxBw - 181.1) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 1; + filterSet = 6; + } else if(fabs(rxBw - 191.5) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 15; + } else if(fabs(rxBw - 225.1) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 1; + } else if(fabs(rxBw - 248.8) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 2; + } else if(fabs(rxBw - 269.3) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 3; + } else if(fabs(rxBw - 284.8) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 4; + } else if(fabs(rxBw -335.5) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 8; + } else if(fabs(rxBw - 391.8) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 9; + } else if(fabs(rxBw - 420.2) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 10; + } else if(fabs(rxBw - 468.4) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 11; + } else if(fabs(rxBw - 518.8) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 12; + } else if(fabs(rxBw - 577.0) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 13; + } else if(fabs(rxBw - 620.7) <= 0.001) { + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 14; + } else { + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); + } + + // shift decimation rate bits + decRate <<= 4; + + // update register + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, bypass | decRate | filterSet); + RADIOLIB_ASSERT(state); + + // update clock recovery + state = updateClockRecovery(); + + return(state); +} + +int16_t Si443x::setSyncWord(uint8_t* syncWord, size_t len) { + RADIOLIB_CHECK_RANGE(len, 1, 4, RADIOLIB_ERR_INVALID_SYNC_WORD); + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set sync word length + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, (uint8_t)(len - 1) << 1, 2, 1); + RADIOLIB_ASSERT(state); + + // set sync word bytes + this->mod->SPIwriteRegisterBurst(RADIOLIB_SI443X_REG_SYNC_WORD_3, syncWord, len); + + return(state); +} + +int16_t Si443x::setPreambleLength(uint8_t preambleLen) { + // Si443x configures preamble length in 4-bit nibbles + if(preambleLen % 4 != 0) { + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); + } + + // set default preamble length + uint8_t preLenNibbles = preambleLen / 4; + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_PREAMBLE_LENGTH, preLenNibbles); + RADIOLIB_ASSERT(state); + + // set default preamble detection threshold to 5/8 of preamble length (in units of 4 bits) + uint8_t preThreshold = 5*preLenNibbles / 8; + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_PREAMBLE_DET_CONTROL, preThreshold << 3, 7, 3)); +} + +size_t Si443x::getPacketLength(bool update) { + if(!this->packetLengthQueried && update) { + if (this->packetLengthConfig == RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON) { + this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH); + } else { + this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SI443X_REG_RECEIVED_PACKET_LENGTH); + } + this->packetLengthQueried = true; + } + + return(this->packetLength); +} + +int16_t Si443x::setEncoding(uint8_t encoding) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set encoding + /// \todo - add inverted Manchester? + switch(encoding) { + case RADIOLIB_ENCODING_NRZ: + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); + case RADIOLIB_ENCODING_MANCHESTER: + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_ON | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); + case RADIOLIB_ENCODING_WHITENING: + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); + default: + return(RADIOLIB_ERR_INVALID_ENCODING); + } +} + +int16_t Si443x::setDataShaping(uint8_t sh) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set data shaping + switch(sh) { + case RADIOLIB_SHAPING_NONE: + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); + case RADIOLIB_SHAPING_0_3: + return(RADIOLIB_ERR_INVALID_ENCODING); + case RADIOLIB_SHAPING_0_5: + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_GFSK, 1, 0)); + case RADIOLIB_SHAPING_1_0: + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); + default: + return(RADIOLIB_ERR_INVALID_ENCODING); + } +} + +void Si443x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { + this->mod->setRfSwitchPins(rxEn, txEn); +} + +void Si443x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + this->mod->setRfSwitchTable(pins, table); +} + +uint8_t Si443x::randomByte() { + // set mode to Rx + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); + + // wait a bit for the RSSI reading to stabilise + this->mod->hal->delay(10); + + // read RSSI value 8 times, always keep just the least significant bit + uint8_t randByte = 0x00; + for(uint8_t i = 0; i < 8; i++) { + randByte |= ((this->mod->SPIreadRegister(RADIOLIB_SI443X_REG_RSSI) & 0x01) << i); + } + + // set mode to standby + standby(); + + return(randByte); +} + +int16_t Si443x::getChipVersion() { + return(this->mod->SPIgetRegValue(RADIOLIB_SI443X_REG_DEVICE_VERSION)); +} + +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE +void Si443x::setDirectAction(void (*func)(void)) { + setIrqAction(func); +} + +void Si443x::readBit(uint32_t pin) { + updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin)); +} +#endif + +int16_t Si443x::fixedPacketLengthMode(uint8_t len) { + return(Si443x::setPacketMode(RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON, len)); +} + +int16_t Si443x::variablePacketLengthMode(uint8_t maxLen) { + return(Si443x::setPacketMode(RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF, maxLen)); +} + +Module* Si443x::getMod() { + return(this->mod); +} + +int16_t Si443x::setFrequencyRaw(float newFreq) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // check high/low band + uint8_t bandSelect = RADIOLIB_SI443X_BAND_SELECT_LOW; + uint8_t freqBand = (newFreq / 10) - 24; + uint8_t afcLimiter = 80; + this->frequency = newFreq; + if(newFreq >= 480.0) { + bandSelect = RADIOLIB_SI443X_BAND_SELECT_HIGH; + freqBand = (newFreq / 20) - 24; + afcLimiter = 40; + } + + // calculate register values + uint16_t freqCarrier = ((newFreq / (10 * ((bandSelect >> 5) + 1))) - freqBand - 24) * (uint32_t)64000; + + // update registers + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT, bandSelect | freqBand, 5, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); + state |= this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); + state |= this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_AFC_LIMITER, afcLimiter); + + return(state); +} + +int16_t Si443x::setPacketMode(uint8_t mode, uint8_t len) { + // check packet length + if (len > RADIOLIB_SI443X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set to fixed packet length + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, mode, 3, 3); + RADIOLIB_ASSERT(state); + + // set length to register + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); + RADIOLIB_ASSERT(state); + + // update cached value + this->packetLengthConfig = mode; + return(state); +} + +bool Si443x::findChip() { + uint8_t i = 0; + bool flagFound = false; + while((i < 10) && !flagFound) { + // reset the module + reset(); + + // check version register + uint8_t version = this->mod->SPIreadRegister(RADIOLIB_SI443X_REG_DEVICE_VERSION); + if(version == RADIOLIB_SI443X_DEVICE_VERSION) { + flagFound = true; + } else { + RADIOLIB_DEBUG_BASIC_PRINTLN("Si443x not found! (%d of 10 tries) RADIOLIB_SI443X_REG_DEVICE_VERSION == 0x%02X, expected 0x0%X", i + 1, version, RADIOLIB_SI443X_DEVICE_VERSION); + this->mod->hal->delay(10); + i++; + } + } + + return(flagFound); +} + +void Si443x::clearIRQFlags() { + uint8_t buff[2]; + this->mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1, 2, buff); +} + +void Si443x::clearFIFO(size_t count) { + while(count) { + this->mod->SPIreadRegister(RADIOLIB_SI443X_REG_FIFO_ACCESS); + count--; + } +} + +int16_t Si443x::config() { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // disable POR and chip ready interrupts + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + + // enable AGC + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_AGC_OVERRIDE_1, RADIOLIB_SI443X_AGC_GAIN_INCREASE_ON | RADIOLIB_SI443X_AGC_ON, 6, 5); + RADIOLIB_ASSERT(state); + + // disable packet header + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, RADIOLIB_SI443X_SYNC_WORD_TIMEOUT_OFF | RADIOLIB_SI443X_HEADER_LENGTH_HEADER_NONE, 7, 4); + RADIOLIB_ASSERT(state); + + // set antenna switching + this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO0_CONFIG, RADIOLIB_SI443X_GPIOX_TX_STATE_OUT, 4, 0); + this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO1_CONFIG, RADIOLIB_SI443X_GPIOX_RX_STATE_OUT, 4, 0); + + // disable packet header checking + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_1, RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_NONE | RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_NONE); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t Si443x::updateClockRecovery() { + // get the parameters + uint8_t bypass = this->mod->SPIgetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, 7, 7) >> 7; + uint8_t decRate = this->mod->SPIgetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, 6, 4) >> 4; + uint8_t manch = this->mod->SPIgetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, 1, 1) >> 1; + + // calculate oversampling ratio, NCO offset and clock recovery gain + int8_t ndecExp = (int8_t)decRate - 3; + float ndec = 0; + if(ndecExp > 0) { + ndec = (uint16_t)1 << ndecExp; + } else { + ndecExp *= -1; + ndec = 1.0/(float)((uint16_t)1 << ndecExp); + } + float rxOsr = ((float)(500 * (1 + 2*bypass))) / (ndec * this->bitRate * ((float)(1 + manch))); + uint32_t ncoOff = (this->bitRate * (1 + manch) * ((uint32_t)(1) << (20 + decRate))) / (500 * (1 + 2*bypass)); + uint16_t crGain = 2 + (((float)(65536.0 * (1 + manch)) * this->bitRate) / (rxOsr * (this->frequencyDev / 0.625))); + uint16_t rxOsr_fixed = (uint16_t)rxOsr; + + // print that whole mess + RADIOLIB_DEBUG_BASIC_PRINTLN("%X\n%X\n%X", bypass, decRate, manch); + RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(rxOsr, 2); + RADIOLIB_DEBUG_BASIC_PRINTLN("\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr_fixed, rxOsr_fixed, ncoOff, ncoOff, crGain, crGain); + + // update oversampling ratio + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OVERSAMP_RATIO, (uint8_t)(rxOsr_fixed & 0x00FF)); + RADIOLIB_ASSERT(state); + + // update NCO offset + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((ncoOff & 0x0F0000) >> 16), 3, 0); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_1, (uint8_t)((ncoOff & 0x00FF00) >> 8)); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_0, (uint8_t)(ncoOff & 0x0000FF)); + RADIOLIB_ASSERT(state); + + // update clock recovery loop gain + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1, (uint8_t)((crGain & 0x0700) >> 8), 2, 0); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0, (uint8_t)(crGain & 0x00FF)); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t Si443x::directMode() { + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_TX_DATA_SOURCE_GPIO, 5, 4); + RADIOLIB_ASSERT(state); + + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO1_CONFIG, RADIOLIB_SI443X_GPIOX_TX_RX_DATA_CLK_OUT, 4, 0); + RADIOLIB_ASSERT(state); + + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO2_CONFIG, RADIOLIB_SI443X_GPIOX_TX_DATA_IN, 4, 0); + RADIOLIB_ASSERT(state); + + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_FSK, 1, 0); + return(state); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/Si443x/Si443x.h b/lib/lib_rf/RadioLib/src/modules/Si443x/Si443x.h new file mode 100644 index 000000000..9d6398064 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/Si443x/Si443x.h @@ -0,0 +1,860 @@ +#if !defined(_RADIOLIB_SI443X_H) +#define _RADIOLIB_SI443X_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SI443X + +#include "../../Module.h" + +#include "../../protocols/PhysicalLayer/PhysicalLayer.h" + +// Si443x physical layer properties +#define RADIOLIB_SI443X_FREQUENCY_STEP_SIZE 156.25 +#define RADIOLIB_SI443X_MAX_PACKET_LENGTH 64 + +// Si443x series common registers +#define RADIOLIB_SI443X_REG_DEVICE_TYPE 0x00 +#define RADIOLIB_SI443X_REG_DEVICE_VERSION 0x01 +#define RADIOLIB_SI443X_REG_DEVICE_STATUS 0x02 +#define RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1 0x03 +#define RADIOLIB_SI443X_REG_INTERRUPT_STATUS_2 0x04 +#define RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1 0x05 +#define RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2 0x06 +#define RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1 0x07 +#define RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2 0x08 +#define RADIOLIB_SI443X_REG_XOSC_LOAD_CAPACITANCE 0x09 +#define RADIOLIB_SI443X_REG_MCU_OUTPUT_CLOCK 0x0A +#define RADIOLIB_SI443X_REG_GPIO0_CONFIG 0x0B +#define RADIOLIB_SI443X_REG_GPIO1_CONFIG 0x0C +#define RADIOLIB_SI443X_REG_GPIO2_CONFIG 0x0D +#define RADIOLIB_SI443X_REG_IO_PORT_CONFIG 0x0E +#define RADIOLIB_SI443X_REG_ADC_CONFIG 0x0F +#define RADIOLIB_SI443X_REG_ADC_SENSOR_AMP_OFFSET 0x10 +#define RADIOLIB_SI443X_REG_ADC_VALUE 0x11 +#define RADIOLIB_SI443X_REG_TEMP_SENSOR_CONTROL 0x12 +#define RADIOLIB_SI443X_REG_TEMP_VALUE_OFFSET 0x13 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_1 0x14 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_2 0x15 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_3 0x16 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_VALUE_1 0x17 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_VALUE_2 0x18 +#define RADIOLIB_SI443X_REG_LOW_DC_MODE_DURATION 0x19 +#define RADIOLIB_SI443X_REG_LOW_BATT_DET_THRESHOLD 0x1A +#define RADIOLIB_SI443X_REG_BATT_VOLTAGE_LEVEL 0x1B +#define RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH 0x1C +#define RADIOLIB_SI443X_REG_AFC_LOOP_GEARSHIFT_OVERRIDE 0x1D +#define RADIOLIB_SI443X_REG_AFC_TIMING_CONTROL 0x1E +#define RADIOLIB_SI443X_REG_CLOCK_REC_GEARSHIFT_OVERRIDE 0x1F +#define RADIOLIB_SI443X_REG_CLOCK_REC_OVERSAMP_RATIO 0x20 +#define RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2 0x21 +#define RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_1 0x22 +#define RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_0 0x23 +#define RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1 0x24 +#define RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0 0x25 +#define RADIOLIB_SI443X_REG_RSSI 0x26 +#define RADIOLIB_SI443X_REG_RSSI_CLEAR_CHANNEL_THRESHOLD 0x27 +#define RADIOLIB_SI443X_REG_ANTENNA_DIVERSITY_1 0x28 +#define RADIOLIB_SI443X_REG_ANTENNA_DIVERSITY_2 0x29 +#define RADIOLIB_SI443X_REG_AFC_LIMITER 0x2A +#define RADIOLIB_SI443X_REG_AFC_CORRECTION 0x2B +#define RADIOLIB_SI443X_REG_OOK_COUNTER_1 0x2C +#define RADIOLIB_SI443X_REG_OOK_COUNTER_2 0x2D +#define RADIOLIB_SI443X_REG_SLICER_PEAK_HOLD 0x2E +#define RADIOLIB_SI443X_REG_DATA_ACCESS_CONTROL 0x30 +#define RADIOLIB_SI443X_REG_EZMAC_STATUS 0x31 +#define RADIOLIB_SI443X_REG_HEADER_CONTROL_1 0x32 +#define RADIOLIB_SI443X_REG_HEADER_CONTROL_2 0x33 +#define RADIOLIB_SI443X_REG_PREAMBLE_LENGTH 0x34 +#define RADIOLIB_SI443X_REG_PREAMBLE_DET_CONTROL 0x35 +#define RADIOLIB_SI443X_REG_SYNC_WORD_3 0x36 +#define RADIOLIB_SI443X_REG_SYNC_WORD_2 0x37 +#define RADIOLIB_SI443X_REG_SYNC_WORD_1 0x38 +#define RADIOLIB_SI443X_REG_SYNC_WORD_0 0x39 +#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_3 0x3A +#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_2 0x3B +#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_1 0x3C +#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_0 0x3D +#define RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH 0x3E +#define RADIOLIB_SI443X_REG_CHECK_HEADER_3 0x3F +#define RADIOLIB_SI443X_REG_CHECK_HEADER_2 0x40 +#define RADIOLIB_SI443X_REG_CHECK_HEADER_1 0x41 +#define RADIOLIB_SI443X_REG_CHECK_HEADER_0 0x42 +#define RADIOLIB_SI443X_REG_HEADER_ENABLE_3 0x43 +#define RADIOLIB_SI443X_REG_HEADER_ENABLE_2 0x44 +#define RADIOLIB_SI443X_REG_HEADER_ENABLE_1 0x45 +#define RADIOLIB_SI443X_REG_HEADER_ENABLE_0 0x46 +#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_3 0x47 +#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_2 0x48 +#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_1 0x49 +#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_0 0x4A +#define RADIOLIB_SI443X_REG_RECEIVED_PACKET_LENGTH 0x4B +#define RADIOLIB_SI443X_REG_ADC8_CONTROL 0x4F +#define RADIOLIB_SI443X_REG_CHANNEL_FILTER_COEFF 0x60 +#define RADIOLIB_SI443X_REG_XOSC_CONTROL_TEST 0x62 +#define RADIOLIB_SI443X_REG_AGC_OVERRIDE_1 0x69 +#define RADIOLIB_SI443X_REG_TX_POWER 0x6D +#define RADIOLIB_SI443X_REG_TX_DATA_RATE_1 0x6E +#define RADIOLIB_SI443X_REG_TX_DATA_RATE_0 0x6F +#define RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1 0x70 +#define RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2 0x71 +#define RADIOLIB_SI443X_REG_FREQUENCY_DEVIATION 0x72 +#define RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_1 0x73 +#define RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_2 0x74 +#define RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT 0x75 +#define RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1 0x76 +#define RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0 0x77 +#define RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_CHANNEL_SEL 0x79 +#define RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_STEP_SIZE 0x7A +#define RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_1 0x7C +#define RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_2 0x7D +#define RADIOLIB_SI443X_REG_RX_FIFO_CONTROL 0x7E +#define RADIOLIB_SI443X_REG_FIFO_ACCESS 0x7F + +// RADIOLIB_SI443X_REG_DEVICE_TYPE MSB LSB DESCRIPTION +#define RADIOLIB_SI443X_DEVICE_TYPE 0x08 // 4 0 device identification register + +// RADIOLIB_SI443X_REG_DEVICE_VERSION +#define RADIOLIB_SI443X_DEVICE_VERSION 0x06 // 4 0 chip version register + +// RADIOLIB_SI443X_REG_DEVICE_STATUS +#define RADIOLIB_SI443X_RX_TX_FIFO_OVERFLOW 0b10000000 // 7 7 Rx/Tx FIFO overflow flag +#define RADIOLIB_SI443X_RX_TX_FIFO_UNDERFLOW 0b01000000 // 6 6 Rx/Tx FIFO underflow flag +#define RADIOLIB_SI443X_RX_FIFO_EMPTY 0b00100000 // 5 5 Rx FIFO empty flag +#define RADIOLIB_SI443X_HEADER_ERROR 0b00010000 // 4 4 header error flag +#define RADIOLIB_SI443X_FREQUENCY_ERROR 0b00001000 // 3 3 frequency error flag (frequency outside allowed range) +#define RADIOLIB_SI443X_TX 0b00000010 // 1 0 power state: Tx +#define RADIOLIB_SI443X_RX 0b00000001 // 1 0 Rx +#define RADIOLIB_SI443X_IDLE 0b00000000 // 1 0 idle + +// RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1 +#define RADIOLIB_SI443X_FIFO_LEVEL_ERROR_INTERRUPT 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_INTERRUPT 0b01000000 // 6 6 Tx FIFO almost full +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_INTERRUPT 0b00100000 // 5 5 Tx FIFO almost empty +#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_INTERRUPT 0b00010000 // 4 4 Rx FIFO almost full +#define RADIOLIB_SI443X_EXTERNAL_INTERRUPT 0b00001000 // 3 3 external interrupt occurred on GPIOx +#define RADIOLIB_SI443X_PACKET_SENT_INTERRUPT 0b00000100 // 2 2 packet transmission done +#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED_INTERRUPT 0b00000010 // 1 1 valid packet has been received +#define RADIOLIB_SI443X_CRC_ERROR_INTERRUPT 0b00000001 // 0 0 CRC failed + +// RADIOLIB_SI443X_REG_INTERRUPT_STATUS_2 +#define RADIOLIB_SI443X_SYNC_WORD_DETECTED_INTERRUPT 0b10000000 // 7 7 sync word has been detected +#define RADIOLIB_SI443X_VALID_RADIOLIB_PREAMBLE_DETECTED_INTERRUPT 0b01000000 // 6 6 valid preamble has been detected +#define RADIOLIB_SI443X_INVALID_RADIOLIB_PREAMBLE_DETECTED_INTERRUPT 0b00100000 // 5 5 invalid preamble has been detected +#define RADIOLIB_SI443X_RSSI_INTERRUPT 0b00010000 // 4 4 RSSI exceeded programmed threshold +#define RADIOLIB_SI443X_WAKEUP_TIMER_INTERRUPT 0b00001000 // 3 3 wake-up timer expired +#define RADIOLIB_SI443X_LOW_BATTERY_INTERRUPT 0b00000100 // 2 2 low battery detected +#define RADIOLIB_SI443X_CHIP_READY_INTERRUPT 0b00000010 // 1 1 chip ready event detected +#define RADIOLIB_SI443X_POWER_ON_RESET_INTERRUPT 0b00000001 // 0 0 power-on-reset detected + +// RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1 +#define RADIOLIB_SI443X_FIFO_LEVEL_ERROR_ENABLED 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow interrupt enabled +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_ENABLED 0b01000000 // 6 6 Tx FIFO almost full interrupt enabled +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_ENABLED 0b00100000 // 5 5 Tx FIFO almost empty interrupt enabled +#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_ENABLED 0b00010000 // 4 4 Rx FIFO almost full interrupt enabled +#define RADIOLIB_SI443X_EXTERNAL_ENABLED 0b00001000 // 3 3 external interrupt interrupt enabled +#define RADIOLIB_SI443X_PACKET_SENT_ENABLED 0b00000100 // 2 2 packet transmission done interrupt enabled +#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED 0b00000010 // 1 1 valid packet received interrupt enabled +#define RADIOLIB_SI443X_CRC_ERROR_ENABLED 0b00000001 // 0 0 CRC failed interrupt enabled + +// RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2 +#define RADIOLIB_SI443X_SYNC_WORD_DETECTED_ENABLED 0b10000000 // 7 7 sync word interrupt enabled +#define RADIOLIB_SI443X_VALID_RADIOLIB_PREAMBLE_DETECTED_ENABLED 0b01000000 // 6 6 valid preamble interrupt enabled +#define RADIOLIB_SI443X_INVALID_RADIOLIB_PREAMBLE_DETECTED_ENABLED 0b00100000 // 5 5 invalid preamble interrupt enabled +#define RADIOLIB_SI443X_RSSI_ENABLED 0b00010000 // 4 4 RSSI exceeded programmed threshold interrupt enabled +#define RADIOLIB_SI443X_WAKEUP_TIMER_ENABLED 0b00001000 // 3 3 wake-up timer interrupt enabled +#define RADIOLIB_SI443X_LOW_BATTERY_ENABLED 0b00000100 // 2 2 low battery interrupt enabled +#define RADIOLIB_SI443X_CHIP_READY_ENABLED 0b00000010 // 1 1 chip ready event interrupt enabled +#define RADIOLIB_SI443X_POWER_ON_RESET_ENABLED 0b00000001 // 0 0 power-on-reset interrupt enabled + +// RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1 +#define RADIOLIB_SI443X_SOFTWARE_RESET 0b10000000 // 7 7 reset all registers to default values +#define RADIOLIB_SI443X_ENABLE_LOW_BATTERY_DETECT 0b01000000 // 6 6 enable low battery detection +#define RADIOLIB_SI443X_ENABLE_WAKEUP_TIMER 0b00100000 // 5 5 enable wakeup timer +#define RADIOLIB_SI443X_32_KHZ_RC 0b00000000 // 4 4 32.768 kHz source: RC oscillator (default) +#define RADIOLIB_SI443X_32_KHZ_XOSC 0b00010000 // 4 4 crystal oscillator +#define RADIOLIB_SI443X_TX_ON 0b00001000 // 3 3 Tx on in manual transmit mode +#define RADIOLIB_SI443X_RX_ON 0b00000100 // 2 2 Rx on in manual receive mode +#define RADIOLIB_SI443X_PLL_ON 0b00000010 // 1 1 PLL on (tune mode) +#define RADIOLIB_SI443X_XTAL_OFF 0b00000000 // 0 0 crystal oscillator: off (standby mode) +#define RADIOLIB_SI443X_XTAL_ON 0b00000001 // 0 0 on (ready mode) + +// RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2 +#define RADIOLIB_SI443X_ANT_DIV_TR_HL_IDLE_L 0b00000000 // 7 5 GPIO1/2 states: Tx/Rx GPIO1 H, GPIO2 L; idle low (default) +#define RADIOLIB_SI443X_ANT_DIV_TR_LH_IDLE_L 0b00100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle low +#define RADIOLIB_SI443X_ANT_DIV_TR_HL_IDLE_H 0b01000000 // 7 5 Tx/Rx GPIO1 H, GPIO2 L; idle high +#define RADIOLIB_SI443X_ANT_DIV_TR_LH_IDLE_H 0b01100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle high +#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_IDLE_L 0b10000000 // 7 5 Tx/Rx diversity algorithm; idle low +#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_IDLE_H 0b10100000 // 7 5 Tx/Rx diversity algorithm; idle high +#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_L 0b11000000 // 7 5 Tx/Rx diversity algorithm (beacon); idle low +#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_H 0b11100000 // 7 5 Tx/Rx diversity algorithm (beacon); idle high +#define RADIOLIB_SI443X_RX_MULTIPACKET_OFF 0b00000000 // 4 4 Rx multipacket: disabled (default) +#define RADIOLIB_SI443X_RX_MULTIPACKET_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_AUTO_TX_OFF 0b00000000 // 3 3 Tx autotransmit on FIFO almost full: disabled (default) +#define RADIOLIB_SI443X_AUTO_TX_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_LOW_DUTY_CYCLE_OFF 0b00000000 // 2 2 low duty cycle mode: disabled (default) +#define RADIOLIB_SI443X_LOW_DUTY_CYCLE_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_SI443X_RX_FIFO_RESET 0b00000010 // 1 1 Rx FIFO reset/clear: reset (call first) +#define RADIOLIB_SI443X_RX_FIFO_CLEAR 0b00000000 // 1 1 clear (call second) +#define RADIOLIB_SI443X_TX_FIFO_RESET 0b00000001 // 0 0 Tx FIFO reset/clear: reset (call first) +#define RADIOLIB_SI443X_TX_FIFO_CLEAR 0b00000000 // 0 0 clear (call second) + +// RADIOLIB_SI443X_REG_XOSC_LOAD_CAPACITANCE +#define RADIOLIB_SI443X_XTAL_SHIFT 0b00000000 // 7 7 crystal capacitance configuration: +#define RADIOLIB_SI443X_XTAL_LOAD_CAPACITANCE 0b01111111 // 6 0 C_int = 1.8 pF + 0.085 pF * RADIOLIB_SI443X_XTAL_LOAD_CAPACITANCE + 3.7 pF * RADIOLIB_SI443X_XTAL_SHIFT + +// RADIOLIB_SI443X_REG_MCU_OUTPUT_CLOCK +#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_OFF 0b00000000 // 5 4 additional clock cycles: none (default) +#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_128 0b00010000 // 5 4 128 +#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_256 0b00100000 // 5 4 256 +#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_512 0b00110000 // 5 4 512 +#define RADIOLIB_SI443X_LOW_FREQ_CLOCK_OFF 0b00000000 // 3 3 32.768 kHz clock output: disabled (default) +#define RADIOLIB_SI443X_LOW_FREQ_CLOCK_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_MCU_CLOCK_30_MHZ 0b00000000 // 2 0 GPIO clock output: 30 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_15_MHZ 0b00000001 // 2 0 15 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_10_MHZ 0b00000010 // 2 0 10 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_4_MHZ 0b00000011 // 2 0 4 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_3_MHZ 0b00000100 // 2 0 3 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_2_MHZ 0b00000101 // 2 0 2 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_1_MHZ 0b00000110 // 2 0 1 MHz (default) +#define RADIOLIB_SI443X_MCU_CLOCK_32_KHZ 0b00000111 // 2 0 32.768 kHz + +// RADIOLIB_SI443X_REG_GPIO0_CONFIG + RADIOLIB_SI443X_REG_GPIO1_CONFIG + RADIOLIB_SI443X_REG_GPIO2_CONFIG +#define RADIOLIB_SI443X_GPIOX_DRIVE_STRENGTH 0b00000000 // 7 6 GPIOx drive strength (higher number = stronger drive) +#define RADIOLIB_SI443X_GPIOX_PULLUP_OFF 0b00000000 // 5 5 GPIOx internal 200k pullup: disabled (default) +#define RADIOLIB_SI443X_GPIOX_PULLUP_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SI443X_GPIO0_POWER_ON_RESET_OUT 0b00000000 // 4 0 GPIOx function: power-on-reset output (GPIO0 only, default) +#define RADIOLIB_SI443X_GPIO1_POWER_ON_RESET_INV_OUT 0b00000000 // 4 0 inverted power-on-reset output (GPIO1 only, default) +#define RADIOLIB_SI443X_GPIO2_MCU_CLOCK_OUT 0b00000000 // 4 0 MCU clock output (GPIO2 only, default) +#define RADIOLIB_SI443X_GPIOX_WAKEUP_OUT 0b00000001 // 4 0 wakeup timer expired output +#define RADIOLIB_SI443X_GPIOX_LOW_BATTERY_OUT 0b00000010 // 4 0 low battery detect output +#define RADIOLIB_SI443X_GPIOX_DIGITAL_OUT 0b00000011 // 4 0 direct digital output +#define RADIOLIB_SI443X_GPIOX_EXT_INT_FALLING_IN 0b00000100 // 4 0 external interrupt, falling edge +#define RADIOLIB_SI443X_GPIOX_EXT_INT_RISING_IN 0b00000101 // 4 0 external interrupt, rising edge +#define RADIOLIB_SI443X_GPIOX_EXT_INT_CHANGE_IN 0b00000110 // 4 0 external interrupt, state change +#define RADIOLIB_SI443X_GPIOX_ADC_IN 0b00000111 // 4 0 ADC analog input +#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_N_IN 0b00001000 // 4 0 analog test N input +#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_P_IN 0b00001001 // 4 0 analog test P input +#define RADIOLIB_SI443X_GPIOX_DIGITAL_IN 0b00001010 // 4 0 direct digital input +#define RADIOLIB_SI443X_GPIOX_DIGITAL_TEST_OUT 0b00001011 // 4 0 digital test output +#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_N_OUT 0b00001100 // 4 0 analog test N output +#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_P_OUT 0b00001101 // 4 0 analog test P output +#define RADIOLIB_SI443X_GPIOX_REFERENCE_VOLTAGE_OUT 0b00001110 // 4 0 reference voltage output +#define RADIOLIB_SI443X_GPIOX_TX_RX_DATA_CLK_OUT 0b00001111 // 4 0 Tx/Rx clock output in direct mode +#define RADIOLIB_SI443X_GPIOX_TX_DATA_IN 0b00010000 // 4 0 Tx data input direct mode +#define RADIOLIB_SI443X_GPIOX_EXT_RETRANSMIT_REQUEST_IN 0b00010001 // 4 0 external retransmission request input +#define RADIOLIB_SI443X_GPIOX_TX_STATE_OUT 0b00010010 // 4 0 Tx state output +#define RADIOLIB_SI443X_GPIOX_TX_FIFO_ALMOST_FULL_OUT 0b00010011 // 4 0 Tx FIFO almost full output +#define RADIOLIB_SI443X_GPIOX_RX_DATA_OUT 0b00010100 // 4 0 Rx data output +#define RADIOLIB_SI443X_GPIOX_RX_STATE_OUT 0b00010101 // 4 0 Rx state output +#define RADIOLIB_SI443X_GPIOX_RX_FIFO_ALMOST_FULL_OUT 0b00010110 // 4 0 Rx FIFO almost full output +#define RADIOLIB_SI443X_GPIOX_ANT_DIV_1_OUT 0b00010111 // 4 0 antenna diversity output 1 +#define RADIOLIB_SI443X_GPIOX_ANT_DIV_2_OUT 0b00011000 // 4 0 antenna diversity output 2 +#define RADIOLIB_SI443X_GPIOX_VALID_PREAMBLE_OUT 0b00011001 // 4 0 valid preamble detected output +#define RADIOLIB_SI443X_GPIOX_INVALID_PREAMBLE_OUT 0b00011010 // 4 0 invalid preamble detected output +#define RADIOLIB_SI443X_GPIOX_SYNC_WORD_DETECTED_OUT 0b00011011 // 4 0 sync word detected output +#define RADIOLIB_SI443X_GPIOX_CLEAR_CHANNEL_OUT 0b00011100 // 4 0 clear channel assessment output +#define RADIOLIB_SI443X_GPIOX_VDD 0b00011101 // 4 0 VDD +#define RADIOLIB_SI443X_GPIOX_GND 0b00011110 // 4 0 GND + +// RADIOLIB_SI443X_REG_IO_PORT_CONFIG +#define RADIOLIB_SI443X_GPIO2_EXT_INT_STATE_MASK 0b01000000 // 6 6 external interrupt state mask for: GPIO2 +#define RADIOLIB_SI443X_GPIO1_EXT_INT_STATE_MASK 0b00100000 // 5 5 GPIO1 +#define RADIOLIB_SI443X_GPIO0_EXT_INT_STATE_MASK 0b00010000 // 4 4 GPIO0 +#define RADIOLIB_SI443X_IRQ_BY_SDO_OFF 0b00000000 // 3 3 output IRQ state on SDO pin: disabled (default) +#define RADIOLIB_SI443X_IRQ_BY_SDO_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_GPIO2_DIGITAL_STATE_MASK 0b00000100 // 2 2 digital state mask for: GPIO2 +#define RADIOLIB_SI443X_GPIO1_DIGITAL_STATE_MASK 0b00000010 // 1 1 GPIO1 +#define RADIOLIB_SI443X_GPIO0_DIGITAL_STATE_MASK 0b00000001 // 0 0 GPIO0 + +// RADIOLIB_SI443X_REG_ADC_CONFIG +#define RADIOLIB_SI443X_ADC_START 0b10000000 // 7 7 ADC control: start measurement +#define RADIOLIB_SI443X_ADC_RUNNING 0b00000000 // 7 7 measurement in progress +#define RADIOLIB_SI443X_ADC_DONE 0b10000000 // 7 7 done +#define RADIOLIB_SI443X_ADC_SOURCE_TEMPERATURE 0b00000000 // 6 4 ADC source: internal temperature sensor (default) +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO0_SINGLE 0b00010000 // 6 4 single-ended on GPIO0 +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO1_SINGLE 0b00100000 // 6 4 single-ended on GPIO1 +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO2_SINGLE 0b00110000 // 6 4 single-ended on GPIO2 +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO01_DIFF 0b01000000 // 6 4 differential on GPIO0 (+) and GPIO1 (-) +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO12_DIFF 0b01010000 // 6 4 differential on GPIO1 (+) and GPIO2 (-) +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO02_DIFF 0b01100000 // 6 4 differential on GPIO0 (+) and GPIO2 (-) +#define RADIOLIB_SI443X_ADC_SOURCE_GND 0b01110000 // 6 4 GND +#define RADIOLIB_SI443X_ADC_REFERNCE_BAND_GAP 0b00000000 // 3 2 ADC reference: internal bandgap 1.2 V (default) +#define RADIOLIB_SI443X_ADC_REFERNCE_VDD_3 0b00001000 // 3 2 VDD/3 +#define RADIOLIB_SI443X_ADC_REFERNCE_VDD_2 0b00001100 // 3 2 VDD/2 +#define RADIOLIB_SI443X_ADC_GAIN 0b00000000 // 1 0 ADC amplifier gain + +// RADIOLIB_SI443X_REG_ADC_SENSOR_AMP_OFFSET +#define RADIOLIB_SI443X_ADC_OFFSET 0b00000000 // 3 0 ADC offset + +// RADIOLIB_SI443X_REG_TEMP_SENSOR_CONTROL +#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_64_TO_64_C 0b00000000 // 7 6 temperature sensor range: -64 to 64 deg. C, 0.5 deg. C resolution (default) +#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_64_TO_192_C 0b01000000 // 7 6 -64 to 192 deg. C, 1.0 deg. C resolution +#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_0_TO_128_C 0b11000000 // 7 6 0 to 128 deg. C, 0.5 deg. C resolution +#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_40_TO_216_F 0b10000000 // 7 6 -40 to 216 deg. F, 1.0 deg. F resolution +#define RADIOLIB_SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_OFF 0b00000000 // 5 5 Kelvin to Celsius offset: disabled +#define RADIOLIB_SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_ON 0b00100000 // 5 5 enabled (default) +#define RADIOLIB_SI443X_TEMP_SENSOR_TRIM_OFF 0b00000000 // 4 4 temperature sensor trim: disabled (default) +#define RADIOLIB_SI443X_TEMP_SENSOR_TRIM_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_TEMP_SENSOR_TRIM_VALUE 0b00000000 // 3 0 temperature sensor trim value + +// RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_1 +#define RADIOLIB_SI443X_WAKEUP_TIMER_EXPONENT 0b00000011 // 4 0 wakeup timer value exponent + +// RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_2 + RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_3 +#define RADIOLIB_SI443X_WAKEUP_TIMER_MANTISSA_MSB 0x00 // 7 0 wakeup timer value: +#define RADIOLIB_SI443X_WAKEUP_TIMER_MANTISSA_LSB 0x01 // 7 0 T = (4 * RADIOLIB_SI443X_WAKEUP_TIMER_MANTISSA * 2 ^ RADIOLIB_SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms + +// RADIOLIB_SI443X_REG_LOW_DC_MODE_DURATION +#define RADIOLIB_SI443X_LOW_DC_MODE_DURATION_MANTISSA 0x01 // 7 0 low duty cycle mode duration: T = (4 * RADIOLIB_SI443X_LOW_DC_MODE_DURATION_MANTISSA * 2 ^ RADIOLIB_SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms + +// RADIOLIB_SI443X_REG_LOW_BATT_DET_THRESHOLD +#define RADIOLIB_SI443X_LOW_BATT_DET_THRESHOLD 0b00010100 // 4 0 low battery detection threshold: Vth = 1.7 + RADIOLIB_SI443X_LOW_BATT_DET_THRESHOLD * 0.05 V (defaults to 2.7 V) + +// RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH +#define RADIOLIB_SI443X_BYPASS_DEC_BY_3_OFF 0b00000000 // 7 7 bypass decimate-by-3 stage: disabled (default) +#define RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_SI443X_IF_FILTER_DEC_RATE 0b00000000 // 6 4 IF filter decimation rate +#define RADIOLIB_SI443X_IF_FILTER_COEFF_SET 0b00000001 // 3 0 IF filter coefficient set selection + +// RADIOLIB_SI443X_REG_AFC_LOOP_GEARSHIFT_OVERRIDE +#define RADIOLIB_SI443X_AFC_WIDEBAND_OFF 0b00000000 // 7 7 AFC wideband: disabled (default) +#define RADIOLIB_SI443X_AFC_WIDEBAND_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_SI443X_AFC_OFF 0b00000000 // 6 6 AFC: disabled +#define RADIOLIB_SI443X_AFC_ON 0b01000000 // 6 6 enabled (default) +#define RADIOLIB_SI443X_AFC_HIGH_GEAR_SETTING 0b00000000 // 5 3 AFC high gear setting +#define RADIOLIB_SI443X_SECOND_PHASE_BIAS_0_DB 0b00000100 // 2 2 second phase antenna selection bias: 0 dB (default) +#define RADIOLIB_SI443X_SECOND_PHASE_BIAS_1_5_DB 0b00000000 // 2 2 1.5 dB +#define RADIOLIB_SI443X_MOVING_AVERAGE_TAP_8 0b00000010 // 1 1 moving average filter tap length: 8*Tb +#define RADIOLIB_SI443X_MOVING_AVERAGE_TAP_4 0b00000000 // 1 1 4*Tb after first preamble (default) +#define RADIOLIB_SI443X_ZERO_PHASE_RESET_5 0b00000000 // 0 0 reset preamble detector after: 5 zero phases (default) +#define RADIOLIB_SI443X_ZERO_PHASE_RESET_2 0b00000001 // 0 0 3 zero phases + +// RADIOLIB_SI443X_REG_AFC_TIMING_CONTROL +#define RADIOLIB_SI443X_SW_ANT_TIMER 0b00000000 // 7 6 number of periods to wait for RSSI to stabilize during antenna switching +#define RADIOLIB_SI443X_SHORT_WAIT 0b00001000 // 5 3 period to wait after AFC correction +#define RADIOLIB_SI443X_ANTENNA_SWITCH_WAIT 0b00000010 // 2 0 antenna switching wait time + +// RADIOLIB_SI443X_REG_CLOCK_REC_GEARSHIFT_OVERRIDE +#define RADIOLIB_SI443X_CLOCK_RECOVER_FAST_GEARSHIFT 0b00000000 // 5 3 clock recovery fast gearshift value +#define RADIOLIB_SI443X_CLOCK_RECOVER_SLOW_GEARSHIFT 0b00000011 // 2 0 clock recovery slow gearshift value + +// RADIOLIB_SI443X_REG_CLOCK_REC_OVERSAMP_RATIO +#define RADIOLIB_SI443X_CLOCK_REC_OVERSAMP_RATIO_LSB 0b01100100 // 7 0 oversampling rate LSB, defaults to 12.5 clock cycles per bit + +// RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2 +#define RADIOLIB_SI443X_CLOCK_REC_OVERSAMP_RATIO_MSB 0b00000000 // 7 5 oversampling rate MSB, defaults to 12.5 clock cycles per bit +#define RADIOLIB_SI443X_SECOND_PHASE_SKIP_THRESHOLD 0b00000000 // 4 4 skip seconds phase antenna diversity threshold +#define RADIOLIB_SI443X_NCO_OFFSET_MSB 0b00000001 // 3 0 NCO offset MSB + +// RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_1 +#define RADIOLIB_SI443X_NCO_OFFSET_MID 0b01000111 // 7 0 NCO offset MID + +// RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_0 +#define RADIOLIB_SI443X_NCO_OFFSET_LSB 0b10101110 // 7 0 NCO offset LSB + +// RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1 +#define RADIOLIB_SI443X_RX_COMPENSATION_OFF 0b00000000 // 4 4 Rx compensation for high data rate: disabled (default) +#define RADIOLIB_SI443X_RX_COMPENSATION_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_CLOCK_REC_GAIN_DOUBLE_OFF 0b00000000 // 3 3 clock recovery gain doubling: disabled (default) +#define RADIOLIB_SI443X_CLOCK_REC_GAIN_DOUBLE_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_CLOCK_REC_LOOP_GAIN_MSB 0b00000010 // 2 0 clock recovery timing loop gain MSB + +// RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0 +#define RADIOLIB_SI443X_CLOCK_REC_LOOP_GAIN_LSB 0b10001111 // 7 0 clock recovery timing loop gain LSB + +// RADIOLIB_SI443X_REG_RSSI_CLEAR_CHANNEL_THRESHOLD +#define RADIOLIB_SI443X_RSSI_CLEAR_CHANNEL_THRESHOLD 0b00011110 // 7 0 RSSI clear channel interrupt threshold + +// RADIOLIB_SI443X_REG_AFC_LIMITER +#define RADIOLIB_SI443X_AFC_LIMITER 0x00 // 7 0 AFC limiter value + +// RADIOLIB_SI443X_REG_OOK_COUNTER_1 +#define RADIOLIB_SI443X_OOK_FREEZE_OFF 0b00000000 // 5 5 OOK moving average detector freeze: disabled (default) +#define RADIOLIB_SI443X_OOK_FREEZE_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SI443X_PEAK_DETECTOR_OFF 0b00000000 // 4 4 peak detector: disabled +#define RADIOLIB_SI443X_PEAK_DETECTOR_ON 0b00010000 // 4 4 enabled (default) +#define RADIOLIB_SI443X_OOK_MOVING_AVERAGE_OFF 0b00000000 // 3 3 OOK moving average: disabled +#define RADIOLIB_SI443X_OOK_MOVING_AVERAGE_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_SI443X_OOK_COUNTER_MSB 0b00000000 // 2 0 OOK counter MSB + +// RADIOLIB_SI443X_REG_OOK_COUNTER_2 +#define RADIOLIB_SI443X_OOK_COUNTER_LSB 0b10111100 // 7 0 OOK counter LSB + +// RADIOLIB_SI443X_REG_SLICER_PEAK_HOLD +#define RADIOLIB_SI443X_PEAK_DETECTOR_ATTACK 0b00010000 // 6 4 OOK peak detector attach time +#define RADIOLIB_SI443X_PEAK_DETECTOR_DECAY 0b00001100 // 3 0 OOK peak detector decay time + +// RADIOLIB_SI443X_REG_DATA_ACCESS_CONTROL +#define RADIOLIB_SI443X_PACKET_RX_HANDLING_OFF 0b00000000 // 7 7 packet Rx handling: disabled +#define RADIOLIB_SI443X_PACKET_RX_HANDLING_ON 0b10000000 // 7 7 enabled (default) +#define RADIOLIB_SI443X_LSB_FIRST_OFF 0b00000000 // 6 6 LSB first transmission: disabled (default) +#define RADIOLIB_SI443X_LSB_FIRST_ON 0b01000000 // 6 6 enabled +#define RADIOLIB_SI443X_CRC_DATA_ONLY_OFF 0b00000000 // 5 5 CRC calculated only from data fields: disabled (default) +#define RADIOLIB_SI443X_CRC_DATA_ONLY_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_OFF 0b00000000 // 4 4 skip second phase of preamble detection: disabled (default) +#define RADIOLIB_SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_PACKET_TX_HANDLING_OFF 0b00000000 // 3 3 packet Tx handling: disabled +#define RADIOLIB_SI443X_PACKET_TX_HANDLING_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_SI443X_CRC_OFF 0b00000000 // 2 2 CRC: disabled +#define RADIOLIB_SI443X_CRC_ON 0b00000100 // 2 2 enabled (default) +#define RADIOLIB_SI443X_CRC_CCITT 0b00000000 // 1 0 CRC type: CCITT +#define RADIOLIB_SI443X_CRC_IBM_CRC16 0b00000001 // 1 0 IBM CRC-16 (default) +#define RADIOLIB_SI443X_CRC_IEC16 0b00000010 // 1 0 IEC-16 +#define RADIOLIB_SI443X_CRC_BIACHEVA 0b00000011 // 1 0 Biacheva + +// RADIOLIB_SI443X_REG_EZMAC_STATUS +#define RADIOLIB_SI443X_CRC_ALL_ONE 0b01000000 // 6 6 last received CRC was all ones +#define RADIOLIB_SI443X_PACKET_SEARCHING 0b00100000 // 5 5 radio is searching for a valid packet +#define RADIOLIB_SI443X_PACKET_RECEIVING 0b00010000 // 4 4 radio is currently receiving packet +#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED 0b00001000 // 3 3 valid packet was received +#define RADIOLIB_SI443X_CRC_ERROR 0b00000100 // 2 2 CRC check failed +#define RADIOLIB_SI443X_PACKET_TRANSMITTING 0b00000010 // 1 1 radio is currently transmitting packet +#define RADIOLIB_SI443X_PACKET_SENT 0b00000001 // 0 0 packet sent + +// RADIOLIB_SI443X_REG_HEADER_CONTROL_1 +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_NONE 0b00000000 // 7 4 broadcast address check: none (default) +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE0 0b00010000 // 7 4 on byte 0 +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE1 0b00100000 // 7 4 on byte 1 +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE2 0b01000000 // 7 4 on byte 2 +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE3 0b10000000 // 7 4 on byte 3 +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_NONE 0b00000000 // 3 0 received header check: none +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE0 0b00000001 // 3 0 on byte 0 +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE1 0b00000010 // 3 0 on byte 1 +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE2 0b00000100 // 3 0 on byte 2 (default) +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE3 0b00001000 // 3 0 on byte 3 (default) + +// RADIOLIB_SI443X_REG_HEADER_CONTROL_2 +#define RADIOLIB_SI443X_SYNC_WORD_TIMEOUT_OFF 0b00000000 // 7 7 ignore timeout period when searching for sync word: disabled (default) +#define RADIOLIB_SI443X_SYNC_WORD_TIMEOUT_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_NONE 0b00000000 // 6 4 header length: none +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_3 0b00010000 // 6 4 header 3 +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_32 0b00100000 // 6 4 header 3 and 2 +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_321 0b00110000 // 6 4 header 3, 2 and 1 (default) +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_3210 0b01000000 // 6 4 header 3, 2, 1, and 0 +#define RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF 0b00000000 // 3 3 fixed packet length mode: disabled (default) +#define RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_3 0b00000000 // 2 1 sync word length: sync 3 +#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_32 0b00000010 // 2 1 sync 3 and 2 (default) +#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_321 0b00000100 // 2 1 sync 3, 2 and 1 +#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_3210 0b00000110 // 2 1 sync 3, 2, 1 and 0 +#define RADIOLIB_SI443X_PREAMBLE_LENGTH_MSB 0b00000000 // 0 0 preamble length MSB + +// RADIOLIB_SI443X_REG_PREAMBLE_LENGTH +#define RADIOLIB_SI443X_PREAMBLE_LENGTH_LSB 0b00001000 // 0 0 preamble length LSB, defaults to 32 bits + +// RADIOLIB_SI443X_REG_PREAMBLE_DET_CONTROL +#define RADIOLIB_SI443X_PREAMBLE_DET_THRESHOLD 0b00101000 // 7 3 number of 4-bit nibbles in valid preamble, defaults to 20 bits +#define RADIOLIB_SI443X_RSSI_OFFSET 0b00000010 // 2 0 RSSI calculation offset, defaults to +8 dB + +// RADIOLIB_SI443X_REG_SYNC_WORD_3 - RADIOLIB_SI443X_REG_SYNC_WORD_0 +#define RADIOLIB_SI443X_SYNC_WORD_3 0x2D // 7 0 sync word: 4th byte (MSB) +#define RADIOLIB_SI443X_SYNC_WORD_2 0xD4 // 7 0 3rd byte +#define RADIOLIB_SI443X_SYNC_WORD_1 0x00 // 7 0 2nd byte +#define RADIOLIB_SI443X_SYNC_WORD_0 0x00 // 7 0 1st byte (LSB) + +// RADIOLIB_SI443X_REG_CHANNEL_FILTER_COEFF +#define RADIOLIB_SI443X_INVALID_PREAMBLE_THRESHOLD 0b00000000 // 7 4 invalid preamble threshold in nibbles + +// RADIOLIB_SI443X_REG_XOSC_CONTROL_TEST +#define RADIOLIB_SI443X_STATE_LOW_POWER 0b00000000 // 7 5 chip power state: low power +#define RADIOLIB_SI443X_STATE_READY 0b00100000 // 7 5 ready +#define RADIOLIB_SI443X_STATE_TUNE 0b01100000 // 7 5 tune +#define RADIOLIB_SI443X_STATE_TX 0b01000000 // 7 5 Tx +#define RADIOLIB_SI443X_STATE_RX 0b11100000 // 7 5 Rx + +// RADIOLIB_SI443X_REG_AGC_OVERRIDE_1 +#define RADIOLIB_SI443X_AGC_GAIN_INCREASE_OFF 0b00000000 // 6 6 AGC gain increase override: disabled (default) +#define RADIOLIB_SI443X_AGC_GAIN_INCREASE_ON 0b01000000 // 6 6 enabled +#define RADIOLIB_SI443X_AGC_OFF 0b00000000 // 5 5 AGC loop: disabled +#define RADIOLIB_SI443X_AGC_ON 0b00100000 // 5 5 enabled (default) +#define RADIOLIB_SI443X_LNA_GAIN_MIN 0b00000000 // 4 4 LNA gain select: 5 dB (default) +#define RADIOLIB_SI443X_LNA_GAIN_MAX 0b00010000 // 4 4 25 dB +#define RADIOLIB_SI443X_PGA_GAIN_OVERRIDE 0b00000000 // 3 0 PGA gain override, gain = RADIOLIB_SI443X_PGA_GAIN_OVERRIDE * 3 dB + +// RADIOLIB_SI443X_REG_TX_POWER +#define RADIOLIB_SI443X_LNA_SWITCH_OFF 0b00000000 // 3 3 LNA switch control: disabled +#define RADIOLIB_SI443X_LNA_SWITCH_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_SI443X_OUTPUT_POWER 0b00000000 // 2 0 output power in 3 dB steps, 0 is chip min, 7 is chip max + +// RADIOLIB_SI443X_REG_TX_DATA_RATE_1 + RADIOLIB_SI443X_REG_TX_DATA_RATE_0 +#define RADIOLIB_SI443X_DATA_RATE_MSB 0x0A // 7 0 data rate: DR = 10^6 * (RADIOLIB_SI443X_DATA_RATE / 2^16) in high data rate mode or +#define RADIOLIB_SI443X_DATA_RATE_LSB 0x3D // 7 0 DR = 10^6 * (RADIOLIB_SI443X_DATA_RATE / 2^21) in low data rate mode (defaults to 40 kbps) + +// RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1 +#define RADIOLIB_SI443X_HIGH_DATA_RATE_MODE 0b00000000 // 5 5 data rate: above 30 kbps (default) +#define RADIOLIB_SI443X_LOW_DATA_RATE_MODE 0b00100000 // 5 5 below 30 kbps +#define RADIOLIB_SI443X_PACKET_HANDLER_POWER_DOWN_OFF 0b00000000 // 4 4 power off packet handler in low power mode: disabled (default) +#define RADIOLIB_SI443X_PACKET_HANDLER_POWER_DOWN_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_MANCHESTER_PREAMBLE_POL_LOW 0b00000000 // 3 3 preamble polarity in Manchester mode: low +#define RADIOLIB_SI443X_MANCHESTER_PREAMBLE_POL_HIGH 0b00001000 // 3 3 high (default) +#define RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF 0b00000000 // 2 2 inverted Manchester encoding: disabled +#define RADIOLIB_SI443X_MANCHESTER_INVERTED_ON 0b00000100 // 2 2 enabled (default) +#define RADIOLIB_SI443X_MANCHESTER_OFF 0b00000000 // 1 1 Manchester encoding: disabled (default) +#define RADIOLIB_SI443X_MANCHESTER_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_SI443X_WHITENING_OFF 0b00000000 // 0 0 data whitening: disabled (default) +#define RADIOLIB_SI443X_WHITENING_ON 0b00000001 // 0 0 enabled + +// RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2 +#define RADIOLIB_SI443X_TX_DATA_CLOCK_NONE 0b00000000 // 7 6 Tx data clock: disabled (default) +#define RADIOLIB_SI443X_TX_DATA_CLOCK_GPIO 0b01000000 // 7 6 GPIO pin +#define RADIOLIB_SI443X_TX_DATA_CLOCK_SDI 0b10000000 // 7 6 SDI pin +#define RADIOLIB_SI443X_TX_DATA_CLOCK_NIRQ 0b11000000 // 7 6 nIRQ pin +#define RADIOLIB_SI443X_TX_DATA_SOURCE_GPIO 0b00000000 // 5 4 Tx data source in direct mode: GPIO pin (default) +#define RADIOLIB_SI443X_TX_DATA_SOURCE_SDI 0b00010000 // 5 4 SDI pin +#define RADIOLIB_SI443X_TX_DATA_SOURCE_FIFO 0b00100000 // 5 4 FIFO +#define RADIOLIB_SI443X_TX_DATA_SOURCE_PN9 0b00110000 // 5 4 PN9 internal +#define RADIOLIB_SI443X_TX_RX_INVERTED_OFF 0b00000000 // 3 3 Tx/Rx data inverted: disabled (default) +#define RADIOLIB_SI443X_TX_RX_INVERTED_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_FREQUENCY_DEVIATION_MSB 0b00000000 // 2 2 frequency deviation MSB +#define RADIOLIB_SI443X_MODULATION_NONE 0b00000000 // 1 0 modulation type: unmodulated carrier (default) +#define RADIOLIB_SI443X_MODULATION_OOK 0b00000001 // 1 0 OOK +#define RADIOLIB_SI443X_MODULATION_FSK 0b00000010 // 1 0 FSK +#define RADIOLIB_SI443X_MODULATION_GFSK 0b00000011 // 1 0 GFSK + +// RADIOLIB_SI443X_REG_FREQUENCY_DEVIATION +#define RADIOLIB_SI443X_FREQUENCY_DEVIATION_LSB 0b00100000 // 7 0 frequency deviation LSB, Fd = 625 Hz * RADIOLIB_SI443X_FREQUENCY_DEVIATION, defaults to 20 kHz + +// RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_1 + RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_2 +#define RADIOLIB_SI443X_FREQUENCY_OFFSET_MSB 0x00 // 7 0 frequency offset: +#define RADIOLIB_SI443X_FREQUENCY_OFFSET_LSB 0x00 // 1 0 Foff = 156.25 Hz * (RADIOLIB_SI443X_BAND_SELECT + 1) * RADIOLIB_SI443X_FREQUENCY_OFFSET, defaults to 156.25 Hz + +// RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT +#define RADIOLIB_SI443X_SIDE_BAND_SELECT_LOW 0b00000000 // 6 6 Rx LO tuning: below channel frequency (default) +#define RADIOLIB_SI443X_SIDE_BAND_SELECT_HIGH 0b01000000 // 6 6 above channel frequency +#define RADIOLIB_SI443X_BAND_SELECT_LOW 0b00000000 // 5 5 band select: low, 240 - 479.9 MHz +#define RADIOLIB_SI443X_BAND_SELECT_HIGH 0b00100000 // 5 5 high, 480 - 960 MHz (default) +#define RADIOLIB_SI443X_FREQUENCY_BAND_SELECT 0b00010101 // 4 0 frequency band select + +// RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1 + RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0 +#define RADIOLIB_SI443X_NOM_CARRIER_FREQUENCY_MSB 0b10111011 // 7 0 nominal carrier frequency: +#define RADIOLIB_SI443X_NOM_CARRIER_FREQUENCY_LSB 0b10000000 // 7 0 Fc = (RADIOLIB_SI443X_BAND_SELECT + 1)*10*(RADIOLIB_SI443X_FREQUENCY_BAND_SELECT + 24) + (RADIOLIB_SI443X_NOM_CARRIER_FREQUENCY - RADIOLIB_SI443X_FREQUENCY_OFFSET)/6400 [MHz] + +// RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_CHANNEL_SEL +#define RADIOLIB_SI443X_FREQUENCY_HOPPING_CHANNEL 0x00 // 7 0 frequency hopping channel number + +// RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_STEP_SIZE +#define RADIOLIB_SI443X_FREQUENCY_HOPPING_STEP_SIZE 0x00 // 7 0 frequency hopping step size + +// RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_1 +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Tx FIFO almost full threshold + +// RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_2 +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_THRESHOLD 0x04 // 5 0 Tx FIFO almost full threshold + +// RADIOLIB_SI443X_REG_RX_FIFO_CONTROL +#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Rx FIFO almost full threshold + +/*! + \class Si443x + \brief Base class for Si443x series. All derived classes for Si443x (e.g. Si4431 or Si4432) inherit from this base class. + This class should not be instantiated directly from Arduino sketch, only from its derived classes. +*/ +class Si443x: public PhysicalLayer { + public: + // introduce PhysicalLayer overloads + using PhysicalLayer::transmit; + using PhysicalLayer::receive; + using PhysicalLayer::startTransmit; + using PhysicalLayer::readData; + + // constructor + + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + Si443x(Module* mod); + + // basic methods + + /*! + \brief Initialization method. + \param br Bit rate of the FSK transmission in kbps (kilobits per second). + \param freqDev Frequency deviation of the FSK transmission in kHz. + \param rxBw Receiver bandwidth in kHz. + \param preambleLen Preamble Length in bits. + \returns \ref status_codes + */ + int16_t begin(float br, float freqDev, float rxBw, uint8_t preambleLen); + + /*! + \brief Reset method. Will reset the chip to the default state using SDN pin. + */ + void reset(); + + /*! + \brief Binary transmit method. Will transmit arbitrary binary data up to 64 bytes long. + For overloads to transmit Arduino String or C-string, see PhysicalLayer::transmit. + \param data Binary data that will be transmitted. + \param len Length of binary data to transmit (in bytes). + \param addr Node address to transmit the packet to. + \returns \ref status_codes + */ + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Binary receive method. Will attempt to receive arbitrary binary data up to 64 bytes long. + For overloads to receive Arduino String, see PhysicalLayer::receive. + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \returns \ref status_codes + */ + int16_t receive(uint8_t* data, size_t len) override; + + /*! + \brief Sets the module to sleep to save power. %Module will not be able to transmit or receive any data while in sleep mode. + %Module will wake up automatically when methods like transmit or receive are called. + \returns \ref status_codes + */ + int16_t sleep(); + + /*! + \brief Sets the module to standby (with XTAL on). + \returns \ref status_codes + */ + int16_t standby() override; + + /*! + \brief Sets the module to standby. + \param mode Standby mode to be used. + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + + /*! + \brief Enables direct transmission mode. While in direct mode, the module will not be able to transmit or receive packets. + \param frf 24-bit raw frequency value to start transmitting at. Required for quick frequency shifts in RTTY. + \returns \ref status_codes + */ + int16_t transmitDirect(uint32_t frf = 0) override; + + /*! + \brief Enables direct reception mode. While in direct mode, the module will not be able to transmit or receive packets. + \returns \ref status_codes + */ + int16_t receiveDirect() override; + + /*! + \brief Disables direct mode and enables packet mode, allowing the module to receive packets. + \returns \ref status_codes + */ + int16_t packetMode(); + + // interrupt methods + + /*! + \brief Sets interrupt service routine to call when IRQ activates. + \param func ISR to call. + */ + void setIrqAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when IRQ activates. + */ + void clearIrqAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + + /*! + \brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 64 bytes long. + \param data Binary data that will be transmitted. + \param len Length of binary data to transmit (in bytes). + \param addr Node address to transmit the packet to. + \returns \ref status_codes + */ + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Clean up after transmission is done. + \returns \ref status_codes + */ + int16_t finishTransmit() override; + + /*! + \brief Interrupt-driven receive method. IRQ will be activated when full valid packet is received. + \returns \ref status_codes + */ + int16_t startReceive(); + + /*! + \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. + \param timeout Ignored. + \param irqFlags Ignored. + \param irqMask Ignored. + \param len Ignored. + \returns \ref status_codes + */ + int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + + /*! + \brief Reads data that was received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. + \returns \ref status_codes + */ + int16_t readData(uint8_t* data, size_t len) override; + + // configuration methods + + /*! + \brief Sets FSK bit rate. Allowed values range from 0.123 to 256.0 kbps. + \param br Bit rate to be set (in kbps). + \returns \ref status_codes + */ + int16_t setBitRate(float br); + + /*! + \brief Sets FSK frequency deviation from carrier frequency. Allowed values range from 0.625 to 320.0 kHz. + \param freqDev Frequency deviation to be set (in kHz). + \returns \ref status_codes + */ + int16_t setFrequencyDeviation(float freqDev) override; + + /*! + \brief Sets receiver bandwidth. Allowed values range from 2.6 to 620.7 kHz. + \param rxBw Receiver bandwidth to be set in kHz. + \returns \ref status_codes + */ + int16_t setRxBandwidth(float rxBw); + + /*! + \brief Sets sync word. Up to 4 bytes can be set as sync word. + \param syncWord Pointer to the array of sync word bytes. + \param len Sync word length in bytes. + */ + int16_t setSyncWord(uint8_t* syncWord, size_t len); + + /*! + \brief Sets preamble length. + \param preambleLen Preamble length to be set (in bits). + \returns \ref status_codes + */ + int16_t setPreambleLength(uint8_t preambleLen); + + /*! + \brief Query modem for the packet length of received payload. + \param update Update received packet length. Will return cached value when set to false. + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update = true) override; + + /*! + \brief Sets transmission encoding. Only available in FSK mode. + Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER and RADIOLIB_ENCODING_WHITENING. + \param encoding Encoding to be used. + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding) override; + + /*! + \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. Only available in FSK mode with FSK modulation. + Allowed values are RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. + \param sh Gaussian shaping bandwidth-time product that will be used for data shaping + \returns \ref status_codes + */ + int16_t setDataShaping(uint8_t sh) override; + + /*! \copydoc Module::setRfSwitchPins */ + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); + + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + + /*! + \brief Get one truly random byte from RSSI noise. + \returns TRNG byte. + */ + uint8_t randomByte(); + + /*! + \brief Read version SPI register. Should return RADIOLIB_SI443X_DEVICE_VERSION (0x06) if Si443x is connected and working. + \returns Version register contents or \ref status_codes + */ + int16_t getChipVersion(); + + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE + /*! + \brief Set interrupt service routine function to call when data bit is received in direct mode. + \param func Pointer to interrupt service routine. + */ + void setDirectAction(void (*func)(void)); + + /*! + \brief Function to read and process data bit in direct reception mode. + \param pin Pin on which to read. + */ + void readBit(uint32_t pin); + #endif + + /*! + \brief Set modem in fixed packet length mode. + \param len Packet length. + \returns \ref status_codes + */ + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SI443X_MAX_PACKET_LENGTH); + + /*! + \brief Set modem in variable packet length mode. + \param maxLen Maximum packet length. + \returns \ref status_codes + */ + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SI443X_MAX_PACKET_LENGTH); + +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL + protected: +#endif + Module* getMod(); + +#if !RADIOLIB_GODMODE + protected: +#endif + int16_t setFrequencyRaw(float newFreq); + +#if !RADIOLIB_GODMODE + private: +#endif + Module* mod; + + float bitRate = 0; + float frequencyDev = 0; + float frequency = 0; + + size_t packetLength = 0; + bool packetLengthQueried = false; + uint8_t packetLengthConfig = RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON; + + bool findChip(); + void clearIRQFlags(); + void clearFIFO(size_t count); + int16_t config(); + int16_t updateClockRecovery(); + int16_t directMode(); + int16_t setPacketMode(uint8_t mode, uint8_t len); +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/nRF24/nRF24.cpp b/lib/lib_rf/RadioLib/src/modules/nRF24/nRF24.cpp new file mode 100644 index 000000000..a54298844 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/nRF24/nRF24.cpp @@ -0,0 +1,657 @@ +#include "nRF24.h" +#include +#if !RADIOLIB_EXCLUDE_NRF24 + +nRF24::nRF24(Module* mod) : PhysicalLayer(RADIOLIB_NRF24_FREQUENCY_STEP_SIZE, RADIOLIB_NRF24_MAX_PACKET_LENGTH) { + this->mod = mod; +} + +int16_t nRF24::begin(int16_t freq, int16_t dr, int8_t pwr, uint8_t addrWidth) { + // set module properties + this->mod->SPIreadCommand = RADIOLIB_NRF24_CMD_READ; + this->mod->SPIwriteCommand = RADIOLIB_NRF24_CMD_WRITE; + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + + // set pin mode on RST (connected to nRF24 CE pin) + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + + // wait for minimum power-on reset duration + this->mod->hal->delay(100); + + // check SPI connection + int16_t val = this->mod->SPIgetRegValue(RADIOLIB_NRF24_REG_SETUP_AW); + if(!((val >= 0) && (val <= 3))) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No nRF24 found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tnRF24"); + + // configure settings inaccessible by public API + int16_t state = config(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // set frequency + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + // set data rate + state = setBitRate(dr); + RADIOLIB_ASSERT(state); + + // set output power + state = setOutputPower(pwr); + RADIOLIB_ASSERT(state); + + // set address width + state = setAddressWidth(addrWidth); + RADIOLIB_ASSERT(state); + + // set CRC + state = setCrcFiltering(true); + RADIOLIB_ASSERT(state); + + // set auto-ACK on all pipes + state = setAutoAck(true); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t nRF24::sleep() { + return(this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_POWER_DOWN, 1, 1)); +} + +int16_t nRF24::standby() { + return(standby(RADIOLIB_NRF24_POWER_UP)); +} + +int16_t nRF24::standby(uint8_t mode) { + // make sure carrier output is disabled + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_CONT_WAVE_OFF, 7, 7); + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_PLL_LOCK_OFF, 4, 4); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + + // use standby-1 mode + return(this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, mode, 1, 1)); +} + +int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { + // start transmission + int16_t state = startTransmit(data, len, addr); + RADIOLIB_ASSERT(state); + + // wait until transmission is finished + uint32_t start = this->mod->hal->micros(); + while(this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + + // check maximum number of retransmits + if(getStatus(RADIOLIB_NRF24_MAX_RT)) { + finishTransmit(); + return(RADIOLIB_ERR_ACK_NOT_RECEIVED); + } + + // check timeout: 15 retries * 4ms (max Tx time as per datasheet) + if(this->mod->hal->micros() - start >= 60000) { + finishTransmit(); + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + + return(finishTransmit()); +} + +int16_t nRF24::receive(uint8_t* data, size_t len) { + // start reception + int16_t state = startReceive(); + RADIOLIB_ASSERT(state); + + // wait for Rx_DataReady or timeout + uint32_t start = this->mod->hal->micros(); + while(this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + + // check timeout: 15 retries * 4ms (max Tx time as per datasheet) + if(this->mod->hal->micros() - start >= 60000) { + standby(); + clearIRQ(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } + + // read the received data + return(readData(data, len)); +} + +int16_t nRF24::transmitDirect(uint32_t frf) { + // set raw frequency value + if(frf != 0) { + uint8_t freqRaw = frf - 2400; + this->mod->SPIwriteRegister(RADIOLIB_NRF24_REG_RF_CH, freqRaw & 0b01111111); + } + + // output carrier + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_PTX, 0, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_CONT_WAVE_ON, 7, 7); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_PLL_LOCK_ON, 4, 4); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + return(state); +} + +int16_t nRF24::receiveDirect() { + // nRF24 is unable to directly output demodulated data + // this method is implemented only for PhysicalLayer compatibility + return(RADIOLIB_ERR_NONE); +} + +void nRF24::setIrqAction(void (*func)(void)) { + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptFalling); +} + +void nRF24::clearIrqAction() { + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); +} + +void nRF24::setPacketReceivedAction(void (*func)(void)) { + this->setIrqAction(func); +} + +void nRF24::clearPacketReceivedAction() { + this->clearIrqAction(); +} + +void nRF24::setPacketSentAction(void (*func)(void)) { + this->setIrqAction(func); +} + +void nRF24::clearPacketSentAction() { + this->clearIrqAction(); +} + +int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { + // suppress unused variable warning + (void)addr; + + // check packet length + if(len > RADIOLIB_NRF24_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // enable primary Tx mode + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_PTX, 0, 0); + + // clear interrupts + clearIRQ(); + + // enable Tx_DataSent interrupt + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_MASK_TX_DS_IRQ_ON, 5, 5); + RADIOLIB_ASSERT(state); + + // flush Tx FIFO + SPItransfer(RADIOLIB_NRF24_CMD_FLUSH_TX); + + // fill Tx FIFO + uint8_t buff[32]; + memset(buff, 0x00, 32); + memcpy(buff, data, len); + SPIwriteTxPayload(data, len); + + // CE high to start transmitting + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + this->mod->hal->delay(1); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + + return(state); +} + +int16_t nRF24::finishTransmit() { + // clear interrupt flags + clearIRQ(); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + +int16_t nRF24::startReceive() { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // enable primary Rx mode + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_PRX, 0, 0); + RADIOLIB_ASSERT(state); + + // enable Rx_DataReady interrupt + clearIRQ(); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_MASK_RX_DR_IRQ_ON, 6, 6); + RADIOLIB_ASSERT(state); + + // flush Rx FIFO + SPItransfer(RADIOLIB_NRF24_CMD_FLUSH_RX); + + // CE high to start receiving + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + + // wait to enter Rx state + this->mod->hal->delay(1); + + return(state); +} + +int16_t nRF24::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)timeout; + (void)irqFlags; + (void)irqMask; + (void)len; + return(startReceive()); +} + +int16_t nRF24::readData(uint8_t* data, size_t len) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // get packet length + size_t length = getPacketLength(); + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + length = len; + } + + // read packet data + SPIreadRxPayload(data, length); + + // clear interrupt + clearIRQ(); + + return(RADIOLIB_ERR_NONE); +} + +int16_t nRF24::setFrequency(float freq) { + RADIOLIB_CHECK_RANGE((uint16_t)freq, 2400, 2525, RADIOLIB_ERR_INVALID_FREQUENCY); + + // set frequency + uint8_t freqRaw = (uint16_t)freq - 2400; + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_CH, freqRaw, 6, 0); + + if(state == RADIOLIB_ERR_NONE) { + this->frequency = freq; + } + + return(state); +} + +int16_t nRF24::setBitRate(float br) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set data rate + uint16_t dataRate = (uint16_t)br; + if(dataRate == 250) { + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 5, 5); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 3, 3); + } else if(dataRate == 1000) { + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_1_MBPS, 5, 5); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_1_MBPS, 3, 3); + } else if(dataRate == 2000) { + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_2_MBPS, 5, 5); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_2_MBPS, 3, 3); + } else { + return(RADIOLIB_ERR_INVALID_DATA_RATE); + } + + if(state == RADIOLIB_ERR_NONE) { + this->dataRate = dataRate; + } + + + return(state); +} + +int16_t nRF24::setOutputPower(int8_t pwr) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // check allowed values + uint8_t powerRaw = 0; + switch(pwr) { + case -18: + powerRaw = RADIOLIB_NRF24_RF_PWR_18_DBM; + break; + case -12: + powerRaw = RADIOLIB_NRF24_RF_PWR_12_DBM; + break; + case -6: + powerRaw = RADIOLIB_NRF24_RF_PWR_6_DBM; + break; + case 0: + powerRaw = RADIOLIB_NRF24_RF_PWR_0_DBM; + break; + default: + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + + // write new register value + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, powerRaw, 2, 1); + + if(state == RADIOLIB_ERR_NONE) { + this->power = pwr; + } + + return(state); +} + +int16_t nRF24::setAddressWidth(uint8_t addrWidth) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set address width + switch(addrWidth) { + case 2: + // Even if marked as 'Illegal' on the datasheet this will work: + // http://travisgoodspeed.blogspot.com/2011/02/promiscuity-is-nrf24l01s-duty.html + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_2_BYTES, 1, 0); + break; + case 3: + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_3_BYTES, 1, 0); + break; + case 4: + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_4_BYTES, 1, 0); + break; + case 5: + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_5_BYTES, 1, 0); + break; + default: + return(RADIOLIB_ERR_INVALID_ADDRESS_WIDTH); + } + + // save address width + if(state == RADIOLIB_ERR_NONE) { + this->addressWidth = addrWidth; + } + + return(state); +} + +int16_t nRF24::setTransmitPipe(uint8_t* addr) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set transmit address + this->mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_TX_ADDR, addr, this->addressWidth); + + // set Rx pipe 0 address (for ACK) + this->mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_RX_ADDR_P0, addr, this->addressWidth); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P0_ON, 0, 0); + + return(state); +} + +int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t* addr) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // write full pipe 0 - 1 address and enable the pipe + switch(pipeNum) { + case 0: + this->mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_RX_ADDR_P0, addr, this->addressWidth); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P0_ON, 0, 0); + break; + case 1: + this->mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_RX_ADDR_P1, addr, this->addressWidth); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P1_ON, 1, 1); + break; + default: + return(RADIOLIB_ERR_INVALID_PIPE_NUMBER); + } + + return(state); +} + +int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t addrByte) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // write unique pipe 2 - 5 address and enable the pipe + switch(pipeNum) { + case 2: + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P2, addrByte); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P2_ON, 2, 2); + break; + case 3: + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P3, addrByte); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P3_ON, 3, 3); + break; + case 4: + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P4, addrByte); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P4_ON, 4, 4); + break; + case 5: + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P5, addrByte); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P5_ON, 5, 5); + break; + default: + return(RADIOLIB_ERR_INVALID_PIPE_NUMBER); + } + + return(state); +} + +int16_t nRF24::disablePipe(uint8_t pipeNum) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + switch(pipeNum) { + case 0: + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P0_OFF, 0, 0); + break; + case 1: + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P1_OFF, 1, 1); + break; + case 2: + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P2_OFF, 2, 2); + break; + case 3: + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P3_OFF, 3, 3); + break; + case 4: + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P4_OFF, 4, 4); + break; + case 5: + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P5_OFF, 5, 5); + break; + default: + return(RADIOLIB_ERR_INVALID_PIPE_NUMBER); + } + + return(state); +} + +int16_t nRF24::getStatus(uint8_t mask) { + return(this->mod->SPIgetRegValue(RADIOLIB_NRF24_REG_STATUS) & mask); +} + +bool nRF24::isCarrierDetected() { + return(this->mod->SPIgetRegValue(RADIOLIB_NRF24_REG_RPD, 0, 0) == 1); +} + +int16_t nRF24::setFrequencyDeviation(float freqDev) { + // nRF24 is unable to set frequency deviation + // this method is implemented only for PhysicalLayer compatibility + (void)freqDev; + return(RADIOLIB_ERR_NONE); +} + +size_t nRF24::getPacketLength(bool update) { + (void)update; + uint8_t length = 0; + SPItransfer(RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD_WIDTH, false, NULL, &length, 1); + return((size_t)length); +} + +int16_t nRF24::setCrcFiltering(bool crcOn) { + // Auto Ack needs to be disabled in order to disable CRC. + if (!crcOn) { + int16_t status = setAutoAck(false); + RADIOLIB_ASSERT(status) + } + + // Disable CRC + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, (crcOn ? RADIOLIB_NRF24_CRC_ON : RADIOLIB_NRF24_CRC_OFF), 3, 3); +} + +int16_t nRF24::setAutoAck(bool autoAckOn){ + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_ALL_ON : RADIOLIB_NRF24_AA_ALL_OFF), 5, 0); +} + +int16_t nRF24::setAutoAck(uint8_t pipeNum, bool autoAckOn){ + switch(pipeNum) { + case 0: + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P0_ON : RADIOLIB_NRF24_AA_P0_OFF), 0, 0); + break; + case 1: + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P1_ON : RADIOLIB_NRF24_AA_P1_OFF), 1, 1); + break; + case 2: + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P2_ON : RADIOLIB_NRF24_AA_P2_OFF), 2, 2); + break; + case 3: + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P3_ON : RADIOLIB_NRF24_AA_P3_OFF), 3, 3); + break; + case 4: + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P4_ON : RADIOLIB_NRF24_AA_P4_OFF), 4, 4); + break; + case 5: + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P5_ON : RADIOLIB_NRF24_AA_P5_OFF), 5, 5); + break; + default: + return (RADIOLIB_ERR_INVALID_PIPE_NUMBER); + } +} + +int16_t nRF24::setDataShaping(uint8_t sh) { + // nRF24 is unable to set data shaping + // this method is implemented only for PhysicalLayer compatibility + (void)sh; + return(RADIOLIB_ERR_NONE); +} + +int16_t nRF24::setEncoding(uint8_t encoding) { + // nRF24 is unable to set encoding + // this method is implemented only for PhysicalLayer compatibility + (void)encoding; + return(RADIOLIB_ERR_NONE); +} + +void nRF24::clearIRQ() { + // clear status bits + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_STATUS, RADIOLIB_NRF24_RX_DR | RADIOLIB_NRF24_TX_DS | RADIOLIB_NRF24_MAX_RT, 6, 4); + + // disable interrupts + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_MASK_RX_DR_IRQ_OFF | RADIOLIB_NRF24_MASK_TX_DS_IRQ_OFF | RADIOLIB_NRF24_MASK_MAX_RT_IRQ_OFF, 6, 4); +} + +int16_t nRF24::config() { + // enable 16-bit CRC + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_CRC_ON | RADIOLIB_NRF24_CRC_16, 3, 2); + RADIOLIB_ASSERT(state); + + // set 15 retries and delay 1500 (5*250) us + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_RETR, (5 << 4) | 5); + + // set features: dynamic payload on, payload with ACK packets off, dynamic ACK off + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_FEATURE, RADIOLIB_NRF24_DPL_ON | RADIOLIB_NRF24_ACK_PAY_OFF | RADIOLIB_NRF24_DYN_ACK_OFF, 2, 0); + RADIOLIB_ASSERT(state); + + // enable dynamic payloads + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_DYNPD, RADIOLIB_NRF24_DPL_ALL_ON, 5, 0); + RADIOLIB_ASSERT(state); + + // reset IRQ + clearIRQ(); + + // clear status + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_STATUS, RADIOLIB_NRF24_RX_DR | RADIOLIB_NRF24_TX_DS | RADIOLIB_NRF24_MAX_RT, 6, 4); + + // flush FIFOs + SPItransfer(RADIOLIB_NRF24_CMD_FLUSH_TX); + SPItransfer(RADIOLIB_NRF24_CMD_FLUSH_RX); + + // power up + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_POWER_UP, 1, 1); + this->mod->hal->delay(5); + + return(state); +} + +Module* nRF24::getMod() { + return(this->mod); +} + +void nRF24::SPIreadRxPayload(uint8_t* data, uint8_t numBytes) { + SPItransfer(RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD, false, NULL, data, numBytes); +} + +void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) { + SPItransfer(RADIOLIB_NRF24_CMD_WRITE_TX_PAYLOAD, true, data, NULL, numBytes); +} + +void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { + // prepare the buffers + size_t buffLen = 1 + numBytes; + #if RADIOLIB_STATIC_ONLY + uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* buffOut = new uint8_t[buffLen]; + uint8_t* buffIn = new uint8_t[buffLen]; + #endif + uint8_t* buffOutPtr = buffOut; + + // copy the command + *(buffOutPtr++) = cmd; + + // copy the data + if(write) { + memcpy(buffOutPtr, dataOut, numBytes); + } else { + memset(buffOutPtr, 0x00, numBytes); + } + + // do the transfer + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + this->mod->hal->spiBeginTransaction(); + this->mod->hal->spiTransfer(buffOut, buffLen, buffIn); + this->mod->hal->spiEndTransaction(); + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); + + // copy the data + if(!write) { + memcpy(dataIn, &buffIn[1], numBytes); + } + + #if !RADIOLIB_STATIC_ONLY + delete[] buffOut; + delete[] buffIn; + #endif +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/modules/nRF24/nRF24.h b/lib/lib_rf/RadioLib/src/modules/nRF24/nRF24.h new file mode 100644 index 000000000..54ed9c256 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/modules/nRF24/nRF24.h @@ -0,0 +1,491 @@ +#if !defined(_RADIOLIB_NRF24_H) && !RADIOLIB_EXCLUDE_NRF24 +#define _RADIOLIB_NRF24_H + +#include "../../Module.h" +#include "../../TypeDef.h" + +#include "../../protocols/PhysicalLayer/PhysicalLayer.h" + +// nRF24 physical layer properties +#define RADIOLIB_NRF24_FREQUENCY_STEP_SIZE 1000000.0 +#define RADIOLIB_NRF24_MAX_PACKET_LENGTH 32 + +// nRF24 SPI commands +#define RADIOLIB_NRF24_CMD_READ 0b00000000 +#define RADIOLIB_NRF24_CMD_WRITE 0b00100000 +#define RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD 0b01100001 +#define RADIOLIB_NRF24_CMD_WRITE_TX_PAYLOAD 0b10100000 +#define RADIOLIB_NRF24_CMD_FLUSH_TX 0b11100001 +#define RADIOLIB_NRF24_CMD_FLUSH_RX 0b11100010 +#define RADIOLIB_NRF24_CMD_REUSE_TX_PAXLOAD 0b11100011 +#define RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD_WIDTH 0b01100000 +#define RADIOLIB_NRF24_CMD_WRITE_ACK_PAYLOAD 0b10101000 +#define RADIOLIB_NRF24_CMD_WRITE_TX_PAYLOAD_NOACK 0b10110000 +#define RADIOLIB_NRF24_CMD_NOP 0b11111111 + +// nRF24 register map +#define RADIOLIB_NRF24_REG_CONFIG 0x00 +#define RADIOLIB_NRF24_REG_EN_AA 0x01 +#define RADIOLIB_NRF24_REG_EN_RXADDR 0x02 +#define RADIOLIB_NRF24_REG_SETUP_AW 0x03 +#define RADIOLIB_NRF24_REG_SETUP_RETR 0x04 +#define RADIOLIB_NRF24_REG_RF_CH 0x05 +#define RADIOLIB_NRF24_REG_RF_SETUP 0x06 +#define RADIOLIB_NRF24_REG_STATUS 0x07 +#define RADIOLIB_NRF24_REG_OBSERVE_TX 0x08 +#define RADIOLIB_NRF24_REG_RPD 0x09 +#define RADIOLIB_NRF24_REG_RX_ADDR_P0 0x0A +#define RADIOLIB_NRF24_REG_RX_ADDR_P1 0x0B +#define RADIOLIB_NRF24_REG_RX_ADDR_P2 0x0C +#define RADIOLIB_NRF24_REG_RX_ADDR_P3 0x0D +#define RADIOLIB_NRF24_REG_RX_ADDR_P4 0x0E +#define RADIOLIB_NRF24_REG_RX_ADDR_P5 0x0F +#define RADIOLIB_NRF24_REG_TX_ADDR 0x10 +#define RADIOLIB_NRF24_REG_RX_PW_P0 0x11 +#define RADIOLIB_NRF24_REG_RX_PW_P1 0x12 +#define RADIOLIB_NRF24_REG_RX_PW_P2 0x13 +#define RADIOLIB_NRF24_REG_RX_PW_P3 0x14 +#define RADIOLIB_NRF24_REG_RX_PW_P4 0x15 +#define RADIOLIB_NRF24_REG_RX_PW_P5 0x16 +#define RADIOLIB_NRF24_REG_FIFO_STATUS 0x17 +#define RADIOLIB_NRF24_REG_DYNPD 0x1C +#define RADIOLIB_NRF24_REG_FEATURE 0x1D + +// RADIOLIB_NRF24_REG_CONFIG MSB LSB DESCRIPTION +#define RADIOLIB_NRF24_MASK_RX_DR_IRQ_OFF 0b01000000 // 6 6 RX_DR will not be reflected on IRQ pin +#define RADIOLIB_NRF24_MASK_RX_DR_IRQ_ON 0b00000000 // 6 6 RX_DR will be reflected on IRQ pin as active low (default) +#define RADIOLIB_NRF24_MASK_TX_DS_IRQ_OFF 0b00100000 // 5 5 TX_DS will not be reflected on IRQ pin +#define RADIOLIB_NRF24_MASK_TX_DS_IRQ_ON 0b00000000 // 5 5 TX_DS will be reflected on IRQ pin as active low (default) +#define RADIOLIB_NRF24_MASK_MAX_RT_IRQ_OFF 0b00010000 // 4 4 MAX_RT will not be reflected on IRQ pin +#define RADIOLIB_NRF24_MASK_MAX_RT_IRQ_ON 0b00000000 // 4 4 MAX_RT will be reflected on IRQ pin as active low (default) +#define RADIOLIB_NRF24_CRC_OFF 0b00000000 // 3 3 CRC calculation: disabled +#define RADIOLIB_NRF24_CRC_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_NRF24_CRC_8 0b00000000 // 2 2 CRC scheme: CRC8 (default) +#define RADIOLIB_NRF24_CRC_16 0b00000100 // 2 2 CRC16 +#define RADIOLIB_NRF24_POWER_UP 0b00000010 // 1 1 power up +#define RADIOLIB_NRF24_POWER_DOWN 0b00000000 // 1 1 power down +#define RADIOLIB_NRF24_PTX 0b00000000 // 0 0 enable primary Tx +#define RADIOLIB_NRF24_PRX 0b00000001 // 0 0 enable primary Rx + +// RADIOLIB_NRF24_REG_EN_AA +#define RADIOLIB_NRF24_AA_ALL_OFF 0b00000000 // 5 0 auto-ACK on all pipes: disabled +#define RADIOLIB_NRF24_AA_ALL_ON 0b00111111 // 5 0 enabled (default) +#define RADIOLIB_NRF24_AA_P5_OFF 0b00000000 // 5 5 auto-ACK on pipe 5: disabled +#define RADIOLIB_NRF24_AA_P5_ON 0b00100000 // 5 5 enabled (default) +#define RADIOLIB_NRF24_AA_P4_OFF 0b00000000 // 4 4 auto-ACK on pipe 4: disabled +#define RADIOLIB_NRF24_AA_P4_ON 0b00010000 // 4 4 enabled (default) +#define RADIOLIB_NRF24_AA_P3_OFF 0b00000000 // 3 3 auto-ACK on pipe 3: disabled +#define RADIOLIB_NRF24_AA_P3_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_NRF24_AA_P2_OFF 0b00000000 // 2 2 auto-ACK on pipe 2: disabled +#define RADIOLIB_NRF24_AA_P2_ON 0b00000100 // 2 2 enabled (default) +#define RADIOLIB_NRF24_AA_P1_OFF 0b00000000 // 1 1 auto-ACK on pipe 1: disabled +#define RADIOLIB_NRF24_AA_P1_ON 0b00000010 // 1 1 enabled (default) +#define RADIOLIB_NRF24_AA_P0_OFF 0b00000000 // 0 0 auto-ACK on pipe 0: disabled +#define RADIOLIB_NRF24_AA_P0_ON 0b00000001 // 0 0 enabled (default) + +// RADIOLIB_NRF24_REG_EN_RXADDR +#define RADIOLIB_NRF24_P5_OFF 0b00000000 // 5 5 receive pipe 5: disabled (default) +#define RADIOLIB_NRF24_P5_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_NRF24_P4_OFF 0b00000000 // 4 4 receive pipe 4: disabled (default) +#define RADIOLIB_NRF24_P4_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_NRF24_P3_OFF 0b00000000 // 3 3 receive pipe 3: disabled (default) +#define RADIOLIB_NRF24_P3_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_NRF24_P2_OFF 0b00000000 // 2 2 receive pipe 2: disabled (default) +#define RADIOLIB_NRF24_P2_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_NRF24_P1_OFF 0b00000000 // 1 1 receive pipe 1: disabled +#define RADIOLIB_NRF24_P1_ON 0b00000010 // 1 1 enabled (default) +#define RADIOLIB_NRF24_P0_OFF 0b00000000 // 0 0 receive pipe 0: disabled +#define RADIOLIB_NRF24_P0_ON 0b00000001 // 0 0 enabled (default) + +// RADIOLIB_NRF24_REG_SETUP_AW +#define RADIOLIB_NRF24_ADDRESS_2_BYTES 0b00000000 // 1 0 address width: 2 bytes +#define RADIOLIB_NRF24_ADDRESS_3_BYTES 0b00000001 // 1 0 3 bytes +#define RADIOLIB_NRF24_ADDRESS_4_BYTES 0b00000010 // 1 0 4 bytes +#define RADIOLIB_NRF24_ADDRESS_5_BYTES 0b00000011 // 1 0 5 bytes (default) + +// RADIOLIB_NRF24_REG_SETUP_RETR +#define RADIOLIB_NRF24_ARD 0b00000000 // 7 4 auto retransmit delay: t[us] = (NRF24_ARD + 1) * 250 us +#define RADIOLIB_NRF24_ARC_OFF 0b00000000 // 3 0 auto retransmit count: auto retransmit disabled +#define RADIOLIB_NRF24_ARC 0b00000011 // 3 0 up to 3 retransmits on AA fail (default) + +// RADIOLIB_NRF24_REG_RF_CH +#define RADIOLIB_NRF24_RF_CH 0b00000010 // 6 0 RF channel: f_CH[MHz] = 2400 MHz + NRF24_RF_CH + +// RADIOLIB_NRF24_REG_RF_SETUP +#define RADIOLIB_NRF24_CONT_WAVE_OFF 0b00000000 // 7 7 continuous carrier transmit: disabled (default) +#define RADIOLIB_NRF24_CONT_WAVE_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_NRF24_DR_250_KBPS 0b00100000 // 5 5 data rate: 250 kbps +#define RADIOLIB_NRF24_DR_1_MBPS 0b00000000 // 3 3 1 Mbps (default) +#define RADIOLIB_NRF24_DR_2_MBPS 0b00001000 // 3 3 2 Mbps +#define RADIOLIB_NRF24_PLL_LOCK_ON 0b00010000 // 4 4 force PLL lock: enabled +#define RADIOLIB_NRF24_PLL_LOCK_OFF 0b00000000 // 4 4 disabled (default) +#define RADIOLIB_NRF24_RF_PWR_18_DBM 0b00000000 // 2 1 output power: -18 dBm +#define RADIOLIB_NRF24_RF_PWR_12_DBM 0b00000010 // 2 1 -12 dBm +#define RADIOLIB_NRF24_RF_PWR_6_DBM 0b00000100 // 2 1 -6 dBm +#define RADIOLIB_NRF24_RF_PWR_0_DBM 0b00000110 // 2 1 0 dBm (default) + +// RADIOLIB_NRF24_REG_STATUS +#define RADIOLIB_NRF24_RX_DR 0b01000000 // 6 6 Rx data ready +#define RADIOLIB_NRF24_TX_DS 0b00100000 // 5 5 Tx data sent +#define RADIOLIB_NRF24_MAX_RT 0b00010000 // 4 4 maximum number of retransmits reached (must be cleared to continue) +#define RADIOLIB_NRF24_RX_FIFO_EMPTY 0b00001110 // 3 1 Rx FIFO is empty +#define RADIOLIB_NRF24_RX_P_NO 0b00000000 // 3 1 number of data pipe that received data +#define RADIOLIB_NRF24_TX_FIFO_FULL 0b00000001 // 0 0 Tx FIFO is full + +// RADIOLIB_NRF24_REG_OBSERVE_TX +#define RADIOLIB_NRF24_PLOS_CNT 0b00000000 // 7 4 number of lost packets +#define RADIOLIB_NRF24_ARC_CNT 0b00000000 // 3 0 number of retransmitted packets + +// RADIOLIB_NRF24_REG_RPD +#define RADIOLIB_NRF24_RP_BELOW_64_DBM 0b00000000 // 0 0 received power in the current channel: less than -64 dBm +#define RADIOLIB_NRF24_RP_ABOVE_64_DBM 0b00000001 // 0 0 more than -64 dBm + +// RADIOLIB_NRF24_REG_FIFO_STATUS +#define RADIOLIB_NRF24_TX_REUSE 0b01000000 // 6 6 reusing last transmitted payload +#define RADIOLIB_NRF24_TX_FIFO_FULL_FLAG 0b00100000 // 5 5 Tx FIFO is full +#define RADIOLIB_NRF24_TX_FIFO_EMPTY_FLAG 0b00010000 // 4 4 Tx FIFO is empty +#define RADIOLIB_NRF24_RX_FIFO_FULL_FLAG 0b00000010 // 1 1 Rx FIFO is full +#define RADIOLIB_NRF24_RX_FIFO_EMPTY_FLAG 0b00000001 // 0 0 Rx FIFO is empty + +// RADIOLIB_NRF24_REG_DYNPD +#define RADIOLIB_NRF24_DPL_P5_OFF 0b00000000 // 5 5 dynamic payload length on pipe 5: disabled (default) +#define RADIOLIB_NRF24_DPL_P5_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_NRF24_DPL_P4_OFF 0b00000000 // 4 4 dynamic payload length on pipe 4: disabled (default) +#define RADIOLIB_NRF24_DPL_P4_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_NRF24_DPL_P3_OFF 0b00000000 // 3 3 dynamic payload length on pipe 3: disabled (default) +#define RADIOLIB_NRF24_DPL_P3_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_NRF24_DPL_P2_OFF 0b00000000 // 2 2 dynamic payload length on pipe 2: disabled (default) +#define RADIOLIB_NRF24_DPL_P2_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_NRF24_DPL_P1_OFF 0b00000000 // 1 1 dynamic payload length on pipe 1: disabled (default) +#define RADIOLIB_NRF24_DPL_P1_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_NRF24_DPL_P0_OFF 0b00000000 // 0 0 dynamic payload length on pipe 0: disabled (default) +#define RADIOLIB_NRF24_DPL_P0_ON 0b00000001 // 0 0 enabled +#define RADIOLIB_NRF24_DPL_ALL_OFF 0b00000000 // 5 0 disable all dynamic payloads +#define RADIOLIB_NRF24_DPL_ALL_ON 0b00111111 // 5 0 enable all dynamic payloads + +// RADIOLIB_NRF24_REG_FEATURE +#define RADIOLIB_NRF24_DPL_OFF 0b00000000 // 2 2 dynamic payload length: disabled (default) +#define RADIOLIB_NRF24_DPL_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_NRF24_ACK_PAY_OFF 0b00000000 // 1 1 payload with ACK packets: disabled (default) +#define RADIOLIB_NRF24_ACK_PAY_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_NRF24_DYN_ACK_OFF 0b00000000 // 0 0 payloads without ACK: disabled (default) +#define RADIOLIB_NRF24_DYN_ACK_ON 0b00000001 // 0 0 enabled + +// RadioLib defaults +#define RADIOLIB_NRF24_DEFAULT_FREQ 2400 +#define RADIOLIB_NRF24_DEFAULT_DR 1000 +#define RADIOLIB_NRF24_DEFAULT_POWER -12 +#define RADIOLIB_NRF24_DEFAULT_ADDRWIDTH 5 + +/*! + \class nRF24 + \brief Control class for %nRF24 module. +*/ +class nRF24: public PhysicalLayer { + public: + // introduce PhysicalLayer overloads + using PhysicalLayer::transmit; + using PhysicalLayer::receive; + using PhysicalLayer::startTransmit; + using PhysicalLayer::readData; + + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + nRF24(Module* mod); + + // basic methods + + /*! + \brief Initialization method. + \param freq Carrier frequency in MHz. Defaults to 2400 MHz. + \param dr Data rate to be used in kbps. Defaults to 1000 kbps. + \param pwr Output power in dBm. Defaults to -12 dBm. + \param addrWidth Address width in bytes. Defaults to 5 bytes. + \returns \ref status_codes + */ + int16_t begin( + int16_t freq = RADIOLIB_NRF24_DEFAULT_FREQ, + int16_t dr = RADIOLIB_NRF24_DEFAULT_DR, + int8_t pwr = RADIOLIB_NRF24_DEFAULT_POWER, + uint8_t addrWidth = RADIOLIB_NRF24_DEFAULT_ADDRWIDTH); + + /*! + \brief Sets the module to sleep mode. + \returns \ref status_codes + */ + int16_t sleep(); + + /*! + \brief Sets the module to standby mode. + \returns \ref status_codes + */ + int16_t standby() override; + + /*! + \brief Sets the module to standby. + \param mode Standby mode to be used. + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + + /*! + \brief Blocking binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \param addr Dummy address parameter, to ensure PhysicalLayer compatibility. + \returns \ref status_codes + */ + int16_t transmit(uint8_t* data, size_t len, uint8_t addr) override; + + /*! + \brief Blocking binary receive method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \returns \ref status_codes + */ + int16_t receive(uint8_t* data, size_t len) override; + + /*! + \brief Starts direct mode transmission. + \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. + \returns \ref status_codes + */ + int16_t transmitDirect(uint32_t frf = 0) override; + + /*! + \brief Dummy direct mode reception method, to ensure PhysicalLayer compatibility. + \returns \ref status_codes + */ + int16_t receiveDirect() override; + + // interrupt methods + + /*! + \brief Sets interrupt service routine to call when IRQ activates. + \param func ISR to call. + */ + void setIrqAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine . + */ + void clearIrqAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + + /*! + \brief Interrupt-driven binary transmit method. IRQ will be activated when full packet is transmitted. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \param addr Dummy address parameter, to ensure PhysicalLayer compatibility. + \returns \ref status_codes + */ + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr) override; + + /*! + \brief Clean up after transmission is done. + \returns \ref status_codes + */ + int16_t finishTransmit() override; + + /*! + \brief Interrupt-driven receive method. IRQ will be activated when full packet is received. + \returns \ref status_codes + */ + int16_t startReceive(); + + /*! + \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. + \param timeout Ignored. + \param irqFlags Ignored. + \param irqMask Ignored. + \param len Ignored. + \returns \ref status_codes + */ + int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + + /*! + \brief Reads data received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \returns \ref status_codes + */ + int16_t readData(uint8_t* data, size_t len) override; + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values range from 2400 MHz to 2525 MHz. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets bit rate. Allowed values are 2000, 1000 or 250 kbps. + \param br Bit rate to be set in kbps. + \returns \ref status_codes + */ + int16_t setBitRate(float br); + + /*! + \brief Sets output power. Allowed values are -18, -12, -6 or 0 dBm. + \param pwr Output power to be set in dBm. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t pwr); + + /*! + \brief Sets address width of transmit and receive pipes in bytes. Allowed values are 3, 4 or 5 bytes. + \param addrWidth Address width to be set in bytes. + \returns \ref status_codes + */ + int16_t setAddressWidth(uint8_t addrWidth); + + /*! + \brief Sets address of transmit pipe. The address width must be the same as the same + as the configured in setAddressWidth. + \param addr Address to which the next packet shall be transmitted. + \returns \ref status_codes + */ + int16_t setTransmitPipe(uint8_t* addr); + + /*! + \brief Sets address of receive pipes 0 or 1. The address width must be the same as the same + as the configured in setAddressWidth. + \param pipeNum Number of pipe to which the address shall be set. Either 0 or 1, + other pipes are handled using overloaded method. + \param addr Address from which %nRF24 shall receive new packets on the specified pipe. + \returns \ref status_codes + */ + int16_t setReceivePipe(uint8_t pipeNum, uint8_t* addr); + + /*! + \brief Sets address of receive pipes 2 - 5. The first 2 - 4 address bytes for these pipes + are the same as for address pipe 1, only the last byte can be set. + \param pipeNum Number of pipe to which the address shall be set. Allowed values range from 2 to 5. + \param addrByte LSB of address from which %nRF24 shall receive new packets on the specified pipe. + \returns \ref status_codes + */ + int16_t setReceivePipe(uint8_t pipeNum, uint8_t addrByte); + + /*! + \brief Disables specified receive pipe. + \param pipeNum Receive pipe to be disabled. + \returns \ref status_codes + */ + int16_t disablePipe(uint8_t pipeNum); + + /*! + \brief Gets nRF24 status register. + \param mask Bit mask to be used on the returned register value. + \returns Status register value or \ref status_codes + */ + int16_t getStatus(uint8_t mask = 0xFF); + + /*! + \brief Checks if carrier was detected during last RX + \returns Whatever the carrier was above threshold. + */ + bool isCarrierDetected(); + + /*! + \brief Dummy configuration method, to ensure PhysicalLayer compatibility. + \param freqDev Dummy frequency deviation parameter, no configuration will be changed. + \returns \ref status_codes + */ + int16_t setFrequencyDeviation(float freqDev) override; + + /*! + \brief Query modem for the packet length of received payload. + \param update Update received packet length. Will return cached value when set to false. + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update = true) override; + + /*! + \brief Enable CRC filtering and generation. + \param crcOn Set or unset CRC check. + \returns \ref status_codes + */ + int16_t setCrcFiltering(bool crcOn = true); + + /*! + \brief Enable or disable auto-acknowledge packets on all pipes. + \param autoAckOn Enable (true) or disable (false) auto-acks. + \returns \ref status_codes + */ + int16_t setAutoAck(bool autoAckOn = true); + + /*! + \brief Enable or disable auto-acknowledge packets on given pipe. + \param pipeNum Number of pipe to which enable / disable auto-acks. + \param autoAckOn Enable (true) or disable (false) auto-acks. + \returns \ref status_codes + */ + int16_t setAutoAck(uint8_t pipeNum, bool autoAckOn); + + /*! + \brief Dummy data shaping configuration method, to ensure PhysicalLayer compatibility. + \param sh Ignored. + \returns \ref status_codes + */ + int16_t setDataShaping(uint8_t sh) override; + + /*! + \brief Dummy encoding configuration method, to ensure PhysicalLayer compatibility. + \param sh Ignored. + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding) override; + +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL + protected: +#endif + Module* getMod(); + + void SPIreadRxPayload(uint8_t* data, uint8_t numBytes); + void SPIwriteTxPayload(uint8_t* data, uint8_t numBytes); + void SPItransfer(uint8_t cmd, bool write = false, uint8_t* dataOut = NULL, uint8_t* dataIn = NULL, uint8_t numBytes = 0); + +#if !RADIOLIB_GODMODE + private: +#endif + Module* mod; + + int16_t frequency = RADIOLIB_NRF24_DEFAULT_FREQ; + int16_t dataRate = RADIOLIB_NRF24_DEFAULT_DR; + int8_t power = RADIOLIB_NRF24_DEFAULT_POWER; + uint8_t addressWidth = RADIOLIB_NRF24_DEFAULT_ADDRWIDTH; + + int16_t config(); + void clearIRQ(); +}; + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/AFSK/AFSK.cpp b/lib/lib_rf/RadioLib/src/protocols/AFSK/AFSK.cpp new file mode 100644 index 000000000..bf0ddc4c2 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/AFSK/AFSK.cpp @@ -0,0 +1,42 @@ +#include "AFSK.h" +#if !RADIOLIB_EXCLUDE_AFSK + +AFSKClient::AFSKClient(PhysicalLayer* phy, uint32_t pin): outPin(pin) { + phyLayer = phy; +} + +AFSKClient::AFSKClient(AFSKClient* aud) { + phyLayer = aud->phyLayer; + outPin = aud->outPin; +} + +int16_t AFSKClient::begin() { + return(phyLayer->startDirect()); +} + +int16_t AFSKClient::tone(uint16_t freq, bool autoStart) { + if(freq == 0) { + return(RADIOLIB_ERR_INVALID_FREQUENCY); + } + + if(autoStart) { + int16_t state = phyLayer->transmitDirect(); + RADIOLIB_ASSERT(state); + } + + Module* mod = phyLayer->getMod(); + mod->hal->tone(outPin, freq); + return(RADIOLIB_ERR_NONE); +} + +int16_t AFSKClient::noTone(bool keepOn) { + Module* mod = phyLayer->getMod(); + mod->hal->noTone(outPin); + if(keepOn) { + return(0); + } + + return(phyLayer->standby()); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/AFSK/AFSK.h b/lib/lib_rf/RadioLib/src/protocols/AFSK/AFSK.h new file mode 100644 index 000000000..ea48630e9 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/AFSK/AFSK.h @@ -0,0 +1,70 @@ +#if !defined(_RADIOLIB_AFSK_H) +#define _RADIOLIB_AFSK_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_AFSK + +#include "../../Module.h" + +#include "../PhysicalLayer/PhysicalLayer.h" + +/*! + \class AFSKClient + \brief Client for audio-based transmissions. Requires Arduino tone() function, and a module capable of direct mode transmission using DIO pins. +*/ +class AFSKClient { + public: + /*! + \brief Default contructor. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + \param pin The pin that will be used for audio output. + */ + AFSKClient(PhysicalLayer* phy, uint32_t pin); + + /*! + \brief Copy contructor. + \param aud Pointer to the AFSKClient instance to copy. + */ + AFSKClient(AFSKClient* aud); + + /*! + \brief Initialization method. + \returns \ref status_codes + */ + int16_t begin(); + + /*! + \brief Start transmitting audio tone. + \param freq Frequency of the tone in Hz. + \param autoStart Whether to automatically enter transmission mode. Defaults to true. + \returns \ref status_codes + */ + int16_t tone(uint16_t freq, bool autoStart = true); + + /*! + \brief Stops transmitting audio tone. + \param freq Keep transmitter on - this may limit noise when switching transmitter on or off. + \returns \ref status_codes + */ + int16_t noTone(bool keepOn = false); + +#if !RADIOLIB_GODMODE + private: +#endif + PhysicalLayer* phyLayer; + uint32_t outPin; + + // allow specific classes access the private PhysicalLayer pointer + friend class RTTYClient; + friend class MorseClient; + friend class HellClient; + friend class SSTVClient; + friend class AX25Client; + friend class FSK4Client; + friend class BellClient; +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/APRS/APRS.cpp b/lib/lib_rf/RadioLib/src/protocols/APRS/APRS.cpp new file mode 100644 index 000000000..55b034d17 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/APRS/APRS.cpp @@ -0,0 +1,267 @@ +#include "APRS.h" +#include +#include +#include +#if !RADIOLIB_EXCLUDE_APRS + +APRSClient::APRSClient(AX25Client* ax) { + axClient = ax; + phyLayer = nullptr; +} + +APRSClient::APRSClient(PhysicalLayer* phy) { + axClient = nullptr; + phyLayer = phy; +} + +int16_t APRSClient::begin(char sym, char* callsign, uint8_t ssid, bool alt) { + RADIOLIB_CHECK_RANGE(sym, ' ', '}', RADIOLIB_ERR_INVALID_SYMBOL); + symbol = sym; + + if(alt) { + table = '\\'; + } else { + table = '/'; + } + + if(strlen(callsign) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) { + return(RADIOLIB_ERR_INVALID_CALLSIGN); + } + + memcpy(this->src, callsign, strlen(callsign)); + this->id = ssid; + + return(RADIOLIB_ERR_NONE); +} + +int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg, char* time) { + size_t len = 1 + strlen(lat) + 1 + strlen(lon); + if(msg != NULL) { + len += 1 + strlen(msg); + } + if(time != NULL) { + len += strlen(time); + } + #if !RADIOLIB_STATIC_ONLY + char* info = new char[len + 1]; + #else + char info[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + + // build the info field + if((msg == NULL) && (time == NULL)) { + // no message, no timestamp + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_NO_MSG "%s%c%s%c", lat, table, lon, symbol); + } else if((msg != NULL) && (time == NULL)) { + // message, no timestamp + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_MSG "%s%c%s%c%s", lat, table, lon, symbol, msg); + } else if((msg == NULL) && (time != NULL)) { + // timestamp, no message + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_NO_MSG "%s%s%c%s%c", time, lat, table, lon, symbol); + } else { + // timestamp and message + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "%s%s%c%s%c%s", time, lat, table, lon, symbol, msg); + } + info[len] = '\0'; + + // send the frame + int16_t state = sendFrame(destCallsign, destSSID, info); + #if !RADIOLIB_STATIC_ONLY + delete[] info; + #endif + return(state); +} + +int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t speed, uint8_t type, uint8_t* telem, size_t telemLen, char* grid, char* status, int32_t alt) { + // sanity checks first + if(((telemLen == 0) && (telem != NULL)) || ((telemLen != 0) && (telem == NULL))) { + return(RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY); + } + + if((telemLen != 0) && (telemLen != 2) && (telemLen != 5)) { + return(RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY_LENGTH); + } + + if((telemLen > 0) && ((grid != NULL) || (status != NULL) || (alt != RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED))) { + // can't have both telemetry and status + return(RADIOLIB_ERR_MIC_E_TELEMETRY_STATUS); + } + + // prepare buffers + char destCallsign[7]; + #if !RADIOLIB_STATIC_ONLY + size_t infoLen = 10; + if(telemLen > 0) { + infoLen += 1 + telemLen; + } else { + if(grid != NULL) { + infoLen += strlen(grid) + 2; + } + if(status != NULL) { + infoLen += strlen(status); + } + if(alt > RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED) { + infoLen += 4; + } + } + char* info = new char[infoLen]; + #else + char info[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + size_t infoPos = 0; + + // the following is based on APRS Mic-E implementation by https://github.com/omegat + // as discussed in https://github.com/jgromes/RadioLib/issues/430 + + // latitude first, because that is in the destination field + float lat_abs = RADIOLIB_ABS(lat); + int lat_deg = (int)lat_abs; + int lat_min = (lat_abs - (float)lat_deg) * 60.0f; + int lat_hun = (((lat_abs - (float)lat_deg) * 60.0f) - lat_min) * 100.0f; + destCallsign[0] = lat_deg/10; + destCallsign[1] = lat_deg%10; + destCallsign[2] = lat_min/10; + destCallsign[3] = lat_min%10; + destCallsign[4] = lat_hun/10; + destCallsign[5] = lat_hun%10; + + // next, add the extra bits + if(type & 0x04) { destCallsign[0] += RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET; } + if(type & 0x02) { destCallsign[1] += RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET; } + if(type & 0x01) { destCallsign[2] += RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET; } + if(lat >= 0) { destCallsign[3] += RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET; } + if(lon >= 100 || lon <= -100) { destCallsign[4] += RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET; } + if(lon < 0) { destCallsign[5] += RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET; } + destCallsign[6] = '\0'; + + // now convert to Mic-E characters to get the "callsign" + for(uint8_t i = 0; i < 6; i++) { + if(destCallsign[i] <= 9) { + destCallsign[i] += '0'; + } else { + destCallsign[i] += ('A' - 10); + } + } + + // setup the information field + info[infoPos++] = RADIOLIB_APRS_MIC_E_GPS_DATA_CURRENT; + + // encode the longtitude + float lon_abs = RADIOLIB_ABS(lon); + int32_t lon_deg = (int32_t)lon_abs; + int32_t lon_min = (lon_abs - (float)lon_deg) * 60.0f; + int32_t lon_hun = (((lon_abs - (float)lon_deg) * 60.0f) - lon_min) * 100.0f; + + if(lon_deg <= 9) { + info[infoPos++] = lon_deg + 118; + } else if(lon_deg <= 99) { + info[infoPos++] = lon_deg + 28; + } else if(lon_deg <= 109) { + info[infoPos++] = lon_deg + 8; + } else { + info[infoPos++] = lon_deg - 72; + } + + if(lon_min <= 9){ + info[infoPos++] = lon_min + 88; + } else { + info[infoPos++] = lon_min + 28; + } + + info[infoPos++] = lon_hun + 28; + + // now the speed and heading - this gets really weird + int32_t speed_hun_ten = speed/10; + int32_t speed_uni = speed%10; + int32_t head_hun = heading/100; + int32_t head_ten_uni = heading%100; + + if(speed <= 199) { + info[infoPos++] = speed_hun_ten + 'l'; + } else { + info[infoPos++] = speed_hun_ten + '0'; + } + + info[infoPos++] = speed_uni*10 + head_hun + 32; + info[infoPos++] = head_ten_uni + 28; + info[infoPos++] = symbol; + info[infoPos++] = table; + + // onto the optional stuff - check telemetry first + if(telemLen > 0) { + if(telemLen == 2) { + info[infoPos++] = RADIOLIB_APRS_MIC_E_TELEMETRY_LEN_2; + } else { + info[infoPos++] = RADIOLIB_APRS_MIC_E_TELEMETRY_LEN_5; + } + for(uint8_t i = 0; i < telemLen; i++) { + sprintf(&(info[infoPos]), "%02X", telem[i]); + infoPos += 2; + } + + } else { + if(grid != NULL) { + memcpy(&(info[infoPos]), grid, strlen(grid)); + infoPos += strlen(grid); + info[infoPos++] = '/'; + info[infoPos++] = 'G'; + } + if(status != NULL) { + info[infoPos++] = ' '; + memcpy(&(info[infoPos]), status, strlen(status)); + infoPos += strlen(status); + } + if(alt > RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED) { + // altitude is offset by -10 km + int32_t alt_val = alt + 10000; + + // ... and encoded in base 91 for some reason + info[infoPos++] = (alt_val / 8281) + 33; + info[infoPos++] = ((alt_val % 8281) / 91) + 33; + info[infoPos++] = ((alt_val % 8281) % 91) + 33; + info[infoPos++] = '}'; + } + } + info[infoPos++] = '\0'; + + // send the frame + uint8_t destSSID = 0; + if(this->phyLayer != nullptr) { + // TODO make SSID configurable? + destSSID = 1; + } + int16_t state = sendFrame(destCallsign, destSSID, info); + #if !RADIOLIB_STATIC_ONLY + delete[] info; + #endif + return(state); +} + +int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) { + // encoding depends on whether AX.25 should be used or not + if(this->axClient != nullptr) { + // AX.25/classical mode, get AX.25 callsign + char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; + axClient->getCallsign(srcCallsign); + + AX25Frame frameUI(destCallsign, destSSID, srcCallsign, axClient->getSSID(), RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | + RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME, + RADIOLIB_AX25_PID_NO_LAYER_3, (const char*)info); + + return(axClient->sendFrame(&frameUI)); + + } else if(this->phyLayer != nullptr) { + // non-AX.25/LoRa mode + size_t len = RADIOLIB_APRS_LORA_HEADER_LEN + strlen(this->src) + 4 + strlen(destCallsign) + 11 + strlen(info); + char* buff = new char[len]; + snprintf(buff, len, RADIOLIB_APRS_LORA_HEADER "%s-%d>%s,WIDE%d-%d:%s", this->src, this->id, destCallsign, destSSID, destSSID, info); + + int16_t res = this->phyLayer->transmit((uint8_t*)buff, strlen(buff)); + delete[] buff; + return(res); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/APRS/APRS.h b/lib/lib_rf/RadioLib/src/protocols/APRS/APRS.h new file mode 100644 index 000000000..66555334e --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/APRS/APRS.h @@ -0,0 +1,148 @@ +#if !defined(_RADIOLIB_APRS_H) +#define _RADIOLIB_APRS_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_APRS + +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../AX25/AX25.h" + +// APRS data type identifiers +#define RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_NO_MSG "!" +#define RADIOLIB_APRS_DATA_TYPE_GPS_RAW "$" +#define RADIOLIB_APRS_DATA_TYPE_ITEM ")" +#define RADIOLIB_APRS_DATA_TYPE_TEST "," +#define RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_NO_MSG "/" +#define RADIOLIB_APRS_DATA_TYPE_MSG ":" +#define RADIOLIB_APRS_DATA_TYPE_OBJECT ";" +#define RADIOLIB_APRS_DATA_TYPE_STATION_CAPABILITES "<" +#define RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_MSG "=" +#define RADIOLIB_APRS_DATA_TYPE_STATUS ">" +#define RADIOLIB_APRS_DATA_TYPE_QUERY "?" +#define RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "@" +#define RADIOLIB_APRS_DATA_TYPE_TELEMETRY "T" +#define RADIOLIB_APRS_DATA_TYPE_MAIDENHEAD_BEACON "[" +#define RADIOLIB_APRS_DATA_TYPE_WEATHER_REPORT "_" +#define RADIOLIB_APRS_DATA_TYPE_USER_DEFINED "{" +#define RADIOLIB_APRS_DATA_TYPE_THIRD_PARTY "}" + +/*! + \defgroup mic_e_message_types Mic-E message types. + + \{ +*/ +#define RADIOLIB_APRS_MIC_E_TYPE_OFF_DUTY 0b00000111 +#define RADIOLIB_APRS_MIC_E_TYPE_EN_ROUTE 0b00000110 +#define RADIOLIB_APRS_MIC_E_TYPE_IN_SERVICE 0b00000101 +#define RADIOLIB_APRS_MIC_E_TYPE_RETURNING 0b00000100 +#define RADIOLIB_APRS_MIC_E_TYPE_COMMITTED 0b00000011 +#define RADIOLIB_APRS_MIC_E_TYPE_SPECIAL 0b00000010 +#define RADIOLIB_APRS_MIC_E_TYPE_PRIORITY 0b00000001 +#define RADIOLIB_APRS_MIC_E_TYPE_EMERGENCY 0b00000000 +/*! + \} +*/ + +// magic offset applied to encode extra bits in the Mic-E destination field +#define RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET 25 + +// Mic-E data types +#define RADIOLIB_APRS_MIC_E_GPS_DATA_CURRENT '`' +#define RADIOLIB_APRS_MIC_E_GPS_DATA_OLD '\'' + +// Mic-E telemetry flags +#define RADIOLIB_APRS_MIC_E_TELEMETRY_LEN_2 '`' +#define RADIOLIB_APRS_MIC_E_TELEMETRY_LEN_5 '\'' + +// alias for unused altitude in Mic-E +#define RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED -1000000 + +// special header applied for APRS over LoRa +#define RADIOLIB_APRS_LORA_HEADER "<\xff\x01" +#define RADIOLIB_APRS_LORA_HEADER_LEN (3) + +/*! + \class APRSClient + \brief Client for APRS communication. +*/ +class APRSClient { + public: + /*! + \brief Constructor for "classic" mode using AX.25/AFSK. + \param ax Pointer to the instance of AX25Client to be used for APRS. + */ + explicit APRSClient(AX25Client* ax); + + /*! + \brief Constructor for LoRa mode. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + */ + explicit APRSClient(PhysicalLayer* phy); + + // basic methods + + /*! + \brief Initialization method. + \param sym APRS symbol to be displayed. + \param callsign Source callsign. Required and only used for APRS over LoRa, ignored in classic mode. + \param ssid Source SSID. Only used for APRS over LoRa, ignored in classic mode, defaults to 0. + \param alt Whether to use the primary (false) or alternate (true) symbol table. Defaults to primary table. + \returns \ref status_codes + */ + int16_t begin(char sym, char* callsign = NULL, uint8_t ssid = 0, bool alt = false); + + /*! + \brief Transmit position. + \param destCallsign Destination station callsign. + \param destSSID Destination station SSID. + \param lat Latitude as a null-terminated string. + \param long Longitude as a null-terminated string. + \param msg Message to be transmitted. Defaults to NULL (no message). + \param msg Position timestamp. Defaults to NULL (no timestamp). + \returns \ref status_codes + */ + int16_t sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg = NULL, char* time = NULL); + + /*! + \brief Transmit position using Mic-E encoding. + \param lat Geographical latitude, positive for north, negative for south. + \param lon Geographical longitude, positive for east, negative for west. + \param heading Heading in degrees. + \param speed Speed in knots. + \param type Mic-E message type - see \ref mic_e_message_types. + \param telem Pointer to telemetry array (either 2 or 5 bytes long). NULL when telemetry is not used. + \param telemLen Telemetry length, 2 or 5. 0 when telemetry is not used. + \param grid Maidenhead grid locator. NULL when not used. + \param status Status message to send. NULL when not used. + \param alt Altitude to send. RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED when not used. + */ + int16_t sendMicE(float lat, float lon, uint16_t heading, uint16_t speed, uint8_t type, uint8_t* telem = NULL, size_t telemLen = 0, char* grid = NULL, char* status = NULL, int32_t alt = RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED); + + /*! + \brief Transmit generic APRS frame. + \param destCallsign Destination station callsign. + \param destSSID Destination station SSID. + \param info AX.25 info field contents. + \returns \ref status_codes + */ + int16_t sendFrame(char* destCallsign, uint8_t destSSID, char* info); + +#if !RADIOLIB_GODMODE + private: +#endif + AX25Client* axClient; + PhysicalLayer* phyLayer; + + // default APRS symbol (car) + char symbol = '>'; + char table = '/'; + + // source callsign when using APRS over LoRa + char src[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = { 0 }; + uint8_t id = 0; +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/AX25/AX25.cpp b/lib/lib_rf/RadioLib/src/protocols/AX25/AX25.cpp new file mode 100644 index 000000000..7fe3f4969 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/AX25/AX25.cpp @@ -0,0 +1,450 @@ +#include "AX25.h" +#include +#if !RADIOLIB_EXCLUDE_AX25 + +AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control) +: AX25Frame(destCallsign, destSSID, srcCallsign, srcSSID, control, 0, NULL, 0) { + +} + +AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, const char* info) + : AX25Frame(destCallsign, destSSID, srcCallsign, srcSSID, control, protocolID, (uint8_t*)info, strlen(info)) { + +} + +AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, uint8_t* info, uint16_t infoLen) { + // destination callsign/SSID + memcpy(this->destCallsign, destCallsign, strlen(destCallsign)); + this->destCallsign[strlen(destCallsign)] = '\0'; + this->destSSID = destSSID; + + // source callsign/SSID + memcpy(this->srcCallsign, srcCallsign, strlen(srcCallsign)); + this->srcCallsign[strlen(srcCallsign)] = '\0'; + this->srcSSID = srcSSID; + + // set repeaters + this->numRepeaters = 0; + #if !RADIOLIB_STATIC_ONLY + this->repeaterCallsigns = NULL; + this->repeaterSSIDs = NULL; + #endif + + // control field + this->control = control; + + // sequence numbers + this->rcvSeqNumber = 0; + this->sendSeqNumber = 0; + + // PID field + this->protocolID = protocolID; + + // info field + this->infoLen = infoLen; + if(infoLen > 0) { + #if !RADIOLIB_STATIC_ONLY + this->info = new uint8_t[infoLen]; + #endif + memcpy(this->info, info, infoLen); + } +} + +AX25Frame::AX25Frame(const AX25Frame& frame) { + *this = frame; +} + +AX25Frame::~AX25Frame() { + #if !RADIOLIB_STATIC_ONLY + // deallocate info field + if(infoLen > 0) { + delete[] this->info; + } + + // deallocate repeaters + if(this->numRepeaters > 0) { + for(uint8_t i = 0; i < this->numRepeaters; i++) { + delete[] this->repeaterCallsigns[i]; + } + delete[] this->repeaterCallsigns; + delete[] this->repeaterSSIDs; + } + #endif +} + +AX25Frame& AX25Frame::operator=(const AX25Frame& frame) { + // destination callsign/SSID + memcpy(this->destCallsign, frame.destCallsign, strlen(frame.destCallsign)); + this->destCallsign[strlen(frame.destCallsign)] = '\0'; + this->destSSID = frame.destSSID; + + // source callsign/SSID + memcpy(this->srcCallsign, frame.srcCallsign, strlen(frame.srcCallsign)); + this->srcCallsign[strlen(frame.srcCallsign)] = '\0'; + this->srcSSID = frame.srcSSID; + + // repeaters + this->numRepeaters = frame.numRepeaters; + for(uint8_t i = 0; i < this->numRepeaters; i++) { + memcpy(this->repeaterCallsigns[i], frame.repeaterCallsigns[i], strlen(frame.repeaterCallsigns[i])); + } + memcpy(this->repeaterSSIDs, frame.repeaterSSIDs, this->numRepeaters); + + // control field + this->control = frame.control; + + // sequence numbers + this->rcvSeqNumber = frame.rcvSeqNumber; + this->sendSeqNumber = frame.sendSeqNumber; + + // PID field + this->protocolID = frame.protocolID; + + // info field + this->infoLen = frame.infoLen; + memcpy(this->info, frame.info, this->infoLen); + + return(*this); +} + +int16_t AX25Frame::setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters) { + // check number of repeaters + if((numRepeaters < 1) || (numRepeaters > 8)) { + return(RADIOLIB_ERR_INVALID_NUM_REPEATERS); + } + + // check repeater configuration + if((repeaterCallsigns == NULL) || (repeaterSSIDs == NULL)) { + return(RADIOLIB_ERR_INVALID_NUM_REPEATERS); + } + for(uint16_t i = 0; i < numRepeaters; i++) { + if(strlen(repeaterCallsigns[i]) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) { + return(RADIOLIB_ERR_INVALID_REPEATER_CALLSIGN); + } + } + + // create buffers + #if !RADIOLIB_STATIC_ONLY + this->repeaterCallsigns = new char*[numRepeaters]; + for(uint8_t i = 0; i < numRepeaters; i++) { + this->repeaterCallsigns[i] = new char[strlen(repeaterCallsigns[i]) + 1]; + } + this->repeaterSSIDs = new uint8_t[numRepeaters]; + #endif + + // copy data + this->numRepeaters = numRepeaters; + for(uint8_t i = 0; i < numRepeaters; i++) { + memcpy(this->repeaterCallsigns[i], repeaterCallsigns[i], strlen(repeaterCallsigns[i])); + this->repeaterCallsigns[i][strlen(repeaterCallsigns[i])] = '\0'; + } + memcpy(this->repeaterSSIDs, repeaterSSIDs, numRepeaters); + + return(RADIOLIB_ERR_NONE); +} + +void AX25Frame::setRecvSequence(uint8_t seqNumber) { + this->rcvSeqNumber = seqNumber; +} + +void AX25Frame::setSendSequence(uint8_t seqNumber) { + this->sendSeqNumber = seqNumber; +} + +AX25Client::AX25Client(PhysicalLayer* phy) { + phyLayer = phy; + #if !RADIOLIB_EXCLUDE_AFSK + bellModem = nullptr; + #endif +} + +#if !RADIOLIB_EXCLUDE_AFSK +AX25Client::AX25Client(AFSKClient* audio) { + phyLayer = audio->phyLayer; + bellModem = new BellClient(audio); + bellModem->setModem(Bell202); +} + +int16_t AX25Client::setCorrection(int16_t mark, int16_t space, float length) { + BellModem_t modem; + modem.freqMark = Bell202.freqMark + mark; + modem.freqSpace = Bell202.freqSpace + space; + modem.freqMarkReply = modem.freqMark; + modem.freqSpaceReply = modem.freqSpace; + modem.baudRate = length*(float)Bell202.baudRate; + bellModem->setModem(modem); + return(RADIOLIB_ERR_NONE); +} +#endif + +int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t preLen) { + // set source SSID + sourceSSID = srcSSID; + + // check source callsign length (6 characters max) + if(strlen(srcCallsign) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) { + return(RADIOLIB_ERR_INVALID_CALLSIGN); + } + + // copy callsign + memcpy(sourceCallsign, srcCallsign, strlen(srcCallsign)); + sourceCallsign[strlen(srcCallsign)] = '\0'; + + // save preamble length + preambleLen = preLen; + + // configure for direct mode + #if !RADIOLIB_EXCLUDE_AFSK + if(bellModem != nullptr) { + return(phyLayer->startDirect()); + } + #endif + return(RADIOLIB_ERR_NONE); +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t AX25Client::transmit(String& str, const char* destCallsign, uint8_t destSSID) { + return(transmit(str.c_str(), destCallsign, destSSID)); +} +#endif + +int16_t AX25Client::transmit(const char* str, const char* destCallsign, uint8_t destSSID) { + // create control field + uint8_t controlField = RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME; + + // build the frame + AX25Frame frame(destCallsign, destSSID, sourceCallsign, sourceSSID, controlField, RADIOLIB_AX25_PID_NO_LAYER_3, (uint8_t*)str, strlen(str)); + + // send Unnumbered Information frame + return(sendFrame(&frame)); +} + +int16_t AX25Client::sendFrame(AX25Frame* frame) { + // check destination callsign length (6 characters max) + if(strlen(frame->destCallsign) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) { + return(RADIOLIB_ERR_INVALID_CALLSIGN); + } + + // check repeater configuration + #if !RADIOLIB_STATIC_ONLY + if(!(((frame->repeaterCallsigns == NULL) && (frame->repeaterSSIDs == NULL) && (frame->numRepeaters == 0)) || + ((frame->repeaterCallsigns != NULL) && (frame->repeaterSSIDs != NULL) && (frame->numRepeaters != 0)))) { + return(RADIOLIB_ERR_INVALID_NUM_REPEATERS); + } + for(uint16_t i = 0; i < frame->numRepeaters; i++) { + if(strlen(frame->repeaterCallsigns[i]) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) { + return(RADIOLIB_ERR_INVALID_REPEATER_CALLSIGN); + } + } + #endif + + // calculate frame length without FCS (destination address, source address, repeater addresses, control, PID, info) + size_t frameBuffLen = ((2 + frame->numRepeaters)*(RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1)) + 1 + 1 + frame->infoLen; + // create frame buffer without preamble, start or stop flags + #if !RADIOLIB_STATIC_ONLY + uint8_t* frameBuff = new uint8_t[frameBuffLen + 2]; + #else + uint8_t frameBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + uint8_t* frameBuffPtr = frameBuff; + + // set destination callsign - all address field bytes are shifted by one bit to make room for HDLC address extension bit + memset(frameBuffPtr, ' ' << 1, RADIOLIB_AX25_MAX_CALLSIGN_LEN); + for(size_t i = 0; i < strlen(frame->destCallsign); i++) { + *(frameBuffPtr + i) = frame->destCallsign[i] << 1; + } + frameBuffPtr += RADIOLIB_AX25_MAX_CALLSIGN_LEN; + + // set destination SSID + *(frameBuffPtr++) = RADIOLIB_AX25_SSID_RESPONSE_DEST | RADIOLIB_AX25_SSID_RESERVED_BITS | (frame->destSSID & 0x0F) << 1 | RADIOLIB_AX25_SSID_HDLC_EXTENSION_CONTINUE; + + // set source callsign - all address field bytes are shifted by one bit to make room for HDLC address extension bit + memset(frameBuffPtr, ' ' << 1, RADIOLIB_AX25_MAX_CALLSIGN_LEN); + for(size_t i = 0; i < strlen(frame->srcCallsign); i++) { + *(frameBuffPtr + i) = frame->srcCallsign[i] << 1; + } + frameBuffPtr += RADIOLIB_AX25_MAX_CALLSIGN_LEN; + + // set source SSID + *(frameBuffPtr++) = RADIOLIB_AX25_SSID_COMMAND_SOURCE | RADIOLIB_AX25_SSID_RESERVED_BITS | (frame->srcSSID & 0x0F) << 1 | RADIOLIB_AX25_SSID_HDLC_EXTENSION_CONTINUE; + + // set repeater callsigns + for(uint16_t i = 0; i < frame->numRepeaters; i++) { + memset(frameBuffPtr, ' ' << 1, RADIOLIB_AX25_MAX_CALLSIGN_LEN); + for(size_t j = 0; j < strlen(frame->repeaterCallsigns[i]); j++) { + *(frameBuffPtr + j) = frame->repeaterCallsigns[i][j] << 1; + } + frameBuffPtr += RADIOLIB_AX25_MAX_CALLSIGN_LEN; + *(frameBuffPtr++) = RADIOLIB_AX25_SSID_HAS_NOT_BEEN_REPEATED | RADIOLIB_AX25_SSID_RESERVED_BITS | (frame->repeaterSSIDs[i] & 0x0F) << 1 | RADIOLIB_AX25_SSID_HDLC_EXTENSION_CONTINUE; + } + + // set HDLC extension end bit + *(frameBuffPtr - 1) |= RADIOLIB_AX25_SSID_HDLC_EXTENSION_END; + + // set sequence numbers of the frames that have it + uint8_t controlField = frame->control; + if((frame->control & 0x01) == 0) { + // information frame, set both sequence numbers + controlField |= frame->rcvSeqNumber << 5; + controlField |= frame->sendSeqNumber << 1; + } else if((frame->control & 0x02) == 0) { + // supervisory frame, set only receive sequence number + controlField |= frame->rcvSeqNumber << 5; + } + + // set control field + *(frameBuffPtr++) = controlField; + + // set PID field of the frames that have it + if(frame->protocolID != 0x00) { + *(frameBuffPtr++) = frame->protocolID; + } + + // set info field of the frames that have it + if(frame->infoLen > 0) { + memcpy(frameBuffPtr, frame->info, frame->infoLen); + frameBuffPtr += frame->infoLen; + } + + // flip bit order + for(size_t i = 0; i < frameBuffLen; i++) { + frameBuff[i] = Module::reflect(frameBuff[i], 8); + } + + // calculate + RadioLibCRCInstance.size = 16; + RadioLibCRCInstance.poly = RADIOLIB_CRC_CCITT_POLY; + RadioLibCRCInstance.init = RADIOLIB_CRC_CCITT_INIT; + RadioLibCRCInstance.out = RADIOLIB_CRC_CCITT_OUT; + RadioLibCRCInstance.refIn = false; + RadioLibCRCInstance.refOut = false; + uint16_t fcs = RadioLibCRCInstance.checksum(frameBuff, frameBuffLen); + *(frameBuffPtr++) = (uint8_t)((fcs >> 8) & 0xFF); + *(frameBuffPtr++) = (uint8_t)(fcs & 0xFF); + + // prepare buffer for the final frame (stuffed, with added preamble + flags and NRZI-encoded) + #if !RADIOLIB_STATIC_ONLY + // worst-case scenario: sequence of 1s, will have 120% of the original length, stuffed frame also includes both flags + uint8_t* stuffedFrameBuff = new uint8_t[preambleLen + 1 + (6*frameBuffLen)/5 + 2]; + #else + uint8_t stuffedFrameBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + + // initialize buffer to all zeros + memset(stuffedFrameBuff, 0x00, preambleLen + 1 + (6*frameBuffLen)/5 + 2); + + // stuff bits (skip preamble and both flags) + uint16_t stuffedFrameBuffLenBits = 8*(preambleLen + 1); + uint8_t count = 0; + for(size_t i = 0; i < frameBuffLen + 2; i++) { + for(int8_t shift = 7; shift >= 0; shift--) { + uint16_t stuffedFrameBuffPos = stuffedFrameBuffLenBits + 7 - 2*(stuffedFrameBuffLenBits%8); + if((frameBuff[i] >> shift) & 0x01) { + // copy 1 and increment counter + SET_BIT_IN_ARRAY(stuffedFrameBuff, stuffedFrameBuffPos); + stuffedFrameBuffLenBits++; + count++; + + // check 5 consecutive 1s + if(count == 5) { + // get the new position in stuffed frame + stuffedFrameBuffPos = stuffedFrameBuffLenBits + 7 - 2*(stuffedFrameBuffLenBits%8); + + // insert 0 and reset counter + CLEAR_BIT_IN_ARRAY(stuffedFrameBuff, stuffedFrameBuffPos); + stuffedFrameBuffLenBits++; + count = 0; + } + + } else { + // copy 0 and reset counter + CLEAR_BIT_IN_ARRAY(stuffedFrameBuff, stuffedFrameBuffPos); + stuffedFrameBuffLenBits++; + count = 0; + } + + } + } + + // deallocate memory + #if !RADIOLIB_STATIC_ONLY + delete[] frameBuff; + #endif + + // set preamble bytes and start flag field + for(uint16_t i = 0; i < preambleLen + 1; i++) { + stuffedFrameBuff[i] = RADIOLIB_AX25_FLAG; + } + + // get stuffed frame length in bytes + size_t stuffedFrameBuffLen = stuffedFrameBuffLenBits/8 + 1; + uint8_t trailingLen = stuffedFrameBuffLenBits % 8; + + // set end flag field (may be split into two bytes due to misalignment caused by extra stuffing bits) + if(trailingLen != 0) { + stuffedFrameBuffLen++; + stuffedFrameBuff[stuffedFrameBuffLen - 2] |= RADIOLIB_AX25_FLAG >> trailingLen; + stuffedFrameBuff[stuffedFrameBuffLen - 1] = RADIOLIB_AX25_FLAG << (8 - trailingLen); + } else { + stuffedFrameBuff[stuffedFrameBuffLen - 1] = RADIOLIB_AX25_FLAG; + } + + // convert to NRZI + for(size_t i = preambleLen + 1; i < stuffedFrameBuffLen*8; i++) { + size_t currBitPos = i + 7 - 2*(i%8); + size_t prevBitPos = (i - 1) + 7 - 2*((i - 1)%8); + if(TEST_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos)) { + // bit is 1, no change, copy previous bit + if(TEST_BIT_IN_ARRAY(stuffedFrameBuff, prevBitPos)) { + SET_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos); + } else { + CLEAR_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos); + } + + } else { + // bit is 0, transition, copy inversion of the previous bit + if(TEST_BIT_IN_ARRAY(stuffedFrameBuff, prevBitPos)) { + CLEAR_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos); + } else { + SET_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos); + } + } + } + + // transmit + int16_t state = RADIOLIB_ERR_NONE; + #if !RADIOLIB_EXCLUDE_AFSK + if(bellModem != nullptr) { + bellModem->idle(); + + // iterate over all bytes in the buffer + for(uint32_t i = 0; i < stuffedFrameBuffLen; i++) { + bellModem->write(stuffedFrameBuff[i]); + } + + bellModem->standby(); + + } else { + #endif + state = phyLayer->transmit(stuffedFrameBuff, stuffedFrameBuffLen); + #if !RADIOLIB_EXCLUDE_AFSK + } + #endif + + // deallocate memory + #if !RADIOLIB_STATIC_ONLY + delete[] stuffedFrameBuff; + #endif + + return(state); +} + +void AX25Client::getCallsign(char* buff) { + strncpy(buff, sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1); +} + +uint8_t AX25Client::getSSID() { + return(sourceSSID); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/AX25/AX25.h b/lib/lib_rf/RadioLib/src/protocols/AX25/AX25.h new file mode 100644 index 000000000..d1688d9e1 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/AX25/AX25.h @@ -0,0 +1,326 @@ +#if !defined(_RADIOLIB_AX25_H) +#define _RADIOLIB_AX25_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_AX25 + +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" +#include "../BellModem/BellModem.h" +#include "../../utils/CRC.h" + +// macros to access bits in byte array, from http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html +#define SET_BIT_IN_ARRAY(A, k) ( A[(k/8)] |= (1 << (k%8)) ) +#define CLEAR_BIT_IN_ARRAY(A, k) ( A[(k/8)] &= ~(1 << (k%8)) ) +#define TEST_BIT_IN_ARRAY(A, k) ( A[(k/8)] & (1 << (k%8)) ) +#define GET_BIT_IN_ARRAY(A, k) ( (A[(k/8)] & (1 << (k%8))) ? 1 : 0 ) + +// maximum callsign length in bytes +#define RADIOLIB_AX25_MAX_CALLSIGN_LEN 6 + +// flag field MSB LSB DESCRIPTION +#define RADIOLIB_AX25_FLAG 0b01111110 // 7 0 AX.25 frame start/end flag + +// address field +#define RADIOLIB_AX25_SSID_COMMAND_DEST 0b10000000 // 7 7 frame type: command (set in destination SSID) +#define RADIOLIB_AX25_SSID_COMMAND_SOURCE 0b00000000 // 7 7 command (set in source SSID) +#define RADIOLIB_AX25_SSID_RESPONSE_DEST 0b00000000 // 7 7 response (set in destination SSID) +#define RADIOLIB_AX25_SSID_RESPONSE_SOURCE 0b10000000 // 7 7 response (set in source SSID) +#define RADIOLIB_AX25_SSID_HAS_NOT_BEEN_REPEATED 0b00000000 // 7 7 not repeated yet (set in repeater SSID) +#define RADIOLIB_AX25_SSID_HAS_BEEN_REPEATED 0b10000000 // 7 7 repeated (set in repeater SSID) +#define RADIOLIB_AX25_SSID_RESERVED_BITS 0b01100000 // 6 5 reserved bits in SSID +#define RADIOLIB_AX25_SSID_HDLC_EXTENSION_CONTINUE 0b00000000 // 0 0 HDLC extension bit: next octet contains more address information +#define RADIOLIB_AX25_SSID_HDLC_EXTENSION_END 0b00000001 // 0 0 address field end + +// control field +#define RADIOLIB_AX25_CONTROL_U_SET_ASYNC_BAL_MODE 0b01101100 // 7 2 U frame type: set asynchronous balanced mode (connect request) +#define RADIOLIB_AX25_CONTROL_U_SET_ASYNC_BAL_MODE_EXT 0b00101100 // 7 2 set asynchronous balanced mode extended (connect request with module 128) +#define RADIOLIB_AX25_CONTROL_U_DISCONNECT 0b01000000 // 7 2 disconnect request +#define RADIOLIB_AX25_CONTROL_U_DISCONNECT_MODE 0b00001100 // 7 2 disconnect mode (system busy or disconnected) +#define RADIOLIB_AX25_CONTROL_U_UNNUMBERED_ACK 0b01100000 // 7 2 unnumbered acknowledge +#define RADIOLIB_AX25_CONTROL_U_FRAME_REJECT 0b10000100 // 7 2 frame reject +#define RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION 0b00000000 // 7 2 unnumbered information +#define RADIOLIB_AX25_CONTROL_U_EXHANGE_IDENTIFICATION 0b10101100 // 7 2 exchange ID +#define RADIOLIB_AX25_CONTROL_U_TEST 0b11100000 // 7 2 test +#define RADIOLIB_AX25_CONTROL_POLL_FINAL_ENABLED 0b00010000 // 4 4 control field poll/final bit: enabled +#define RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED 0b00000000 // 4 4 disabled +#define RADIOLIB_AX25_CONTROL_S_RECEIVE_READY 0b00000000 // 3 2 S frame type: receive ready (system ready to receive) +#define RADIOLIB_AX25_CONTROL_S_RECEIVE_NOT_READY 0b00000100 // 3 2 receive not ready (TNC buffer full) +#define RADIOLIB_AX25_CONTROL_S_REJECT 0b00001000 // 3 2 reject (out of sequence or duplicate) +#define RADIOLIB_AX25_CONTROL_S_SELECTIVE_REJECT 0b00001100 // 3 2 selective reject (single frame repeat request) +#define RADIOLIB_AX25_CONTROL_INFORMATION_FRAME 0b00000000 // 0 0 frame type: information (I frame) +#define RADIOLIB_AX25_CONTROL_SUPERVISORY_FRAME 0b00000001 // 1 0 supervisory (S frame) +#define RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME 0b00000011 // 1 0 unnumbered (U frame) + +// protocol identifier field +#define RADIOLIB_AX25_PID_ISO_8208 0x01 +#define RADIOLIB_AX25_PID_TCP_IP_COMPRESSED 0x06 +#define RADIOLIB_AX25_PID_TCP_IP_UNCOMPRESSED 0x07 +#define RADIOLIB_AX25_PID_SEGMENTATION_FRAGMENT 0x08 +#define RADIOLIB_AX25_PID_TEXNET_DATAGRAM_PROTOCOL 0xC3 +#define RADIOLIB_AX25_PID_LINK_QUALITY_PROTOCOL 0xC4 +#define RADIOLIB_AX25_PID_APPLETALK 0xCA +#define RADIOLIB_AX25_PID_APPLETALK_ARP 0xCB +#define RADIOLIB_AX25_PID_ARPA_INTERNET_PROTOCOL 0xCC +#define RADIOLIB_AX25_PID_ARPA_ADDRESS_RESOLUTION 0xCD +#define RADIOLIB_AX25_PID_FLEXNET 0xCE +#define RADIOLIB_AX25_PID_NET_ROM 0xCF +#define RADIOLIB_AX25_PID_NO_LAYER_3 0xF0 +#define RADIOLIB_AX25_PID_ESCAPE_CHARACTER 0xFF + +/*! + \class AX25Frame + \brief Abstraction of AX.25 frame format. +*/ +class AX25Frame { + public: + /*! + \brief Callsign of the destination station. + */ + char destCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; + + /*! + \brief SSID of the destination station. + */ + uint8_t destSSID; + + /*! + \brief Callsign of the source station. + */ + char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; + + /*! + \brief SSID of the source station. + */ + uint8_t srcSSID; + + /*! + \brief Number of repeaters to be used. + */ + uint8_t numRepeaters; + + /*! + \brief The control field. + */ + uint8_t control; + + /*! + \brief The protocol identifier (PID) field. + */ + uint8_t protocolID; + + /*! + \brief Number of bytes in the information field. + */ + uint16_t infoLen; + + /*! + \brief Receive sequence number. + */ + uint8_t rcvSeqNumber; + + /*! + \brief Send sequence number. + */ + uint16_t sendSeqNumber; + + #if !RADIOLIB_STATIC_ONLY + /*! + \brief The info field. + */ + uint8_t* info; + + /*! + \brief Array of repeater callsigns. + */ + char** repeaterCallsigns; + + /*! + \brief Array of repeater SSIDs. + */ + uint8_t* repeaterSSIDs; + #else + /*! + \brief The info field. + */ + uint8_t info[RADIOLIB_STATIC_ARRAY_SIZE]; + + /*! + \brief Array of repeater callsigns. + */ + char repeaterCallsigns[8][RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; + + /*! + \brief Array of repeater SSIDs. + */ + uint8_t repeaterSSIDs[8]; + #endif + + /*! + \brief Overloaded constructor, for frames without info field. + \param destCallsign Callsign of the destination station. + \param destSSID SSID of the destination station. + \param srcCallsign Callsign of the source station. + \param srcSSID SSID of the source station. + \param control The control field. + */ + AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control); + + /*! + \brief Overloaded constructor, for frames with C-string info field. + \param destCallsign Callsign of the destination station. + \param destSSID SSID of the destination station. + \param srcCallsign Callsign of the source station. + \param srcSSID SSID of the source station. + \param control The control field. + \param protocolID The protocol identifier (PID) field. Set to zero if the frame doesn't have this field. + \param info Information field, in the form of null-terminated C-string. + */ + AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, const char* info); + + /*! + \brief Default constructor. + \param destCallsign Callsign of the destination station. + \param destSSID SSID of the destination station. + \param srcCallsign Callsign of the source station. + \param srcSSID SSID of the source station. + \param control The control field. + \param protocolID The protocol identifier (PID) field. Set to zero if the frame doesn't have this field. + \param info Information field, in the form of arbitrary binary buffer. + \param infoLen Number of bytes in the information field. + */ + AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, uint8_t* info, uint16_t infoLen); + + /*! + \brief Copy constructor. + \param frame AX25Frame instance to copy. + */ + AX25Frame(const AX25Frame& frame); + + /*! + \brief Default destructor. + */ + ~AX25Frame(); + + /*! + \brief Overload for assignment operator. + \param frame rvalue AX25Frame. + */ + AX25Frame& operator=(const AX25Frame& frame); + + /*! + \brief Method to set the repeater callsigns and SSIDs. + \param repeaterCallsigns Array of repeater callsigns in the form of null-terminated C-strings. + \param repeaterSSIDs Array of repeater SSIDs. + \param numRepeaters Number of repeaters, maximum is 8. + \returns \ref status_codes + */ + int16_t setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters); + + /*! + \brief Method to set receive sequence number. + \param seqNumber Sequence number to set, 0 to 7. + */ + void setRecvSequence(uint8_t seqNumber); + + /*! + \brief Method to set send sequence number. + \param seqNumber Sequence number to set, 0 to 7. + */ + void setSendSequence(uint8_t seqNumber); +}; + +/*! + \class AX25Client + \brief Client for AX25 communication. +*/ +class AX25Client { + public: + /*! + \brief Constructor for 2-FSK mode. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + */ + explicit AX25Client(PhysicalLayer* phy); + + #if !RADIOLIB_EXCLUDE_AFSK + /*! + \brief Constructor for AFSK mode. + \param audio Pointer to the AFSK instance providing audio. + */ + explicit AX25Client(AFSKClient* audio); + + /*! + \brief Set AFSK tone correction offset. On some platforms, this is required to get the audio produced + by the setup to match the expected 1200/2200 Hz tones. + \param mark Positive or negative correction offset for mark audio frequency in Hz. + \param space Positive or negative correction offset for space audio frequency in Hz. + \param length Audio tone length modifier, defaults to 1.0. + \returns \ref status_codes + */ + int16_t setCorrection(int16_t mark, int16_t space, float length = 1.0f); + #endif + + // basic methods + + /*! + \brief Initialization method. + \param srcCallsign Callsign of the source station. + \param srcSSID 4-bit SSID of the source station (in case there are more stations with the same callsign). + Defaults to 0. + \param preLen Number of "preamble" bytes (RADIOLIB_AX25_FLAG) sent ahead of the actual AX.25 frame. + Does not include the first RADIOLIB_AX25_FLAG byte, which is considered part of the frame. Defaults to 8. + \returns \ref status_codes + */ + int16_t begin(const char* srcCallsign, uint8_t srcSSID = 0x00, uint8_t preLen = 8); + + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Transmit unnumbered information (UI) frame. + \param str Data to be sent as Arduino String. + \param destCallsign Callsign of the destination station. + \param destSSID 4-bit SSID of the destination station (in case there are more stations with the same callsign). + Defaults to 0. + \returns \ref status_codes + */ + int16_t transmit(String& str, const char* destCallsign, uint8_t destSSID = 0x00); + #endif + + /*! + \brief Transmit unnumbered information (UI) frame. + \param str Data to be sent. + \param destCallsign Callsign of the destination station. + \param destSSID 4-bit SSID of the destination station (in case there are more stations with the same callsign). + Defaults to 0. + \returns \ref status_codes + */ + int16_t transmit(const char* str, const char* destCallsign, uint8_t destSSID = 0x00); + + /*! + \brief Transmit arbitrary AX.25 frame. + \param frame Frame to be sent. + \returns \ref status_codes + */ + int16_t sendFrame(AX25Frame* frame); + +#if !RADIOLIB_GODMODE + private: +#endif + friend class APRSClient; + + PhysicalLayer* phyLayer; + #if !RADIOLIB_EXCLUDE_AFSK + BellClient* bellModem; + #endif + + char sourceCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = {0, 0, 0, 0, 0, 0, 0}; + uint8_t sourceSSID = 0; + uint16_t preambleLen = 0; + + void getCallsign(char* buff); + uint8_t getSSID(); +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/BellModem/BellModem.cpp b/lib/lib_rf/RadioLib/src/protocols/BellModem/BellModem.cpp new file mode 100644 index 000000000..8d08943ee --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/BellModem/BellModem.cpp @@ -0,0 +1,98 @@ +#include "BellModem.h" +#if !RADIOLIB_EXCLUDE_BELL + +const struct BellModem_t Bell101 { + .freqMark = 1270, + .freqSpace = 1070, + .baudRate = 110, + .freqMarkReply = 2225, + .freqSpaceReply = 2025, +}; + +const struct BellModem_t Bell103 { + .freqMark = 1270, + .freqSpace = 1070, + .baudRate = 300, + .freqMarkReply = 2225, + .freqSpaceReply = 2025, +}; + +const struct BellModem_t Bell202 { + .freqMark = 1200, + .freqSpace = 2200, + .baudRate = 1200, + .freqMarkReply = 1200, + .freqSpaceReply = 2200, +}; + +BellClient::BellClient(PhysicalLayer* phy, uint32_t pin) : AFSKClient(phy, pin) { + this->reply = false; +} + +BellClient::BellClient(AFSKClient* aud) : AFSKClient(aud) { + this->reply = false; +} + +int16_t BellClient::begin(const BellModem_t& modem) { + int16_t state = setModem(modem); + RADIOLIB_ASSERT(state); + + state = phyLayer->startDirect(); + return(state); +} + +int16_t BellClient::setModem(const BellModem_t& modem) { + this->modemType = modem; + this->toneLen = (1000000.0/(float)this->modemType.baudRate)*this->correction; + return(RADIOLIB_ERR_NONE); +} + +int16_t BellClient::setCorrection(float corr) { + this->correction = corr; + return(RADIOLIB_ERR_NONE); +} + +size_t BellClient::write(uint8_t b) { + // first get the frequencies + uint16_t toneMark = this->modemType.freqMark; + uint16_t toneSpace = this->modemType.freqSpace; + if(this->reply) { + toneMark = this->modemType.freqMarkReply; + toneMark = this->modemType.freqSpaceReply; + } + + // get the Module pointer to access HAL + Module* mod = this->phyLayer->getMod(); + + if(this->autoStart) { + phyLayer->transmitDirect(); + } + + // iterate over the bits and set correct frequencies + for(uint16_t mask = 0x80; mask >= 0x01; mask >>= 1) { + uint32_t start = mod->hal->micros(); + if(b & mask) { + this->tone(toneMark, false); + } else { + this->tone(toneSpace, false); + } + mod->waitForMicroseconds(start, this->toneLen); + } + + if(this->autoStart) { + phyLayer->standby(); + } + return(1); +} + +int16_t BellClient::idle() { + this->autoStart = false; + return(phyLayer->transmitDirect()); +} + +int16_t BellClient::standby() { + this->autoStart = true; + return(phyLayer->standby()); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/BellModem/BellModem.h b/lib/lib_rf/RadioLib/src/protocols/BellModem/BellModem.h new file mode 100644 index 000000000..b98479e4e --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/BellModem/BellModem.h @@ -0,0 +1,131 @@ +#if !defined(_RADIOLIB_BELL_MODEM_H) +#define _RADIOLIB_BELL_MODEM_H + +#include "../../TypeDef.h" +#include "../../Module.h" +#if defined(RADIOLIB_BUILD_ARDUINO) +#include "../../ArduinoHal.h" +#endif + +#if !RADIOLIB_EXCLUDE_BELL + +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" +#include "../Print/Print.h" +#include "../Print/ITA2String.h" + +/*! + \struct BellModem_t + \brief Definition of the Bell-compatible modem. +*/ +struct BellModem_t { + /*! + \brief Frequency of the mark tone. + */ + int16_t freqMark; + + /*! + \brief Frequency of the space tone. + */ + int16_t freqSpace; + + /*! + \brief Baud rate. + */ + int16_t baudRate; + + /*! + \brief Frequency of the mark tone when replying. + */ + int16_t freqMarkReply; + + /*! + \brief Frequency of the space tone when replying. + */ + int16_t freqSpaceReply; +}; + +// currently implemented Bell modems +extern const struct BellModem_t Bell101; +extern const struct BellModem_t Bell103; +extern const struct BellModem_t Bell202; + +/*! + \class BellClient + \brief Client for Bell modem communication. The public interface is the same as Arduino Serial. +*/ +class BellClient: public AFSKClient, public RadioLibPrint { + + public: + + /*! + \brief Whether the modem is replying. + On some modems, the replying station has different tone frequencies. + */ + bool reply; + + /*! + \brief Default constructor. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + \param pin The GPIO pin at which the tones will be generated. + */ + explicit BellClient(PhysicalLayer* phy, uint32_t pin); + + /*! + \brief Audio-client constructor. Can be used when AFSKClient instance already exists. + \param aud Audio client to use. + */ + BellClient(AFSKClient* aud); + + /*! + \brief Initialization method. + \param modem Definition of the Bell modem to use for communication. + \returns \ref status_codes + */ + int16_t begin(const BellModem_t& modem); + + /*! + \brief Set Bell modem. + \param modem Definition of the Bell modem to use for communication. + \returns \ref status_codes + */ + int16_t setModem(const BellModem_t& modem); + + /*! + \brief Set correction coefficient for tone length. + \param correction Timing correction factor, used to adjust the length of tones. + Less than 1.0 leads to shorter tones, defaults to 1.0 (no correction). + \returns \ref status_codes + */ + int16_t setCorrection(float corr); + + /*! + \brief Write one byte. Implementation of interface of the RadioLibPrint/Print class. + \param b Byte to write. + \returns 1 if the byte was written, 0 otherwise. + */ + size_t write(uint8_t b); + + /*! + \brief Set the modem to idle (ready to transmit). + */ + int16_t idle(); + + /*! + \brief Set the modem to standby (transmitter off). + */ + int16_t standby(); + +#if !RADIOLIB_GODMODE + private: +#endif + BellModem_t modemType; + float correction = 1.0; + uint16_t toneLen = 0; + bool autoStart = true; + +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/ExternalRadio/ExternalRadio.cpp b/lib/lib_rf/RadioLib/src/protocols/ExternalRadio/ExternalRadio.cpp new file mode 100644 index 000000000..0748b4955 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/ExternalRadio/ExternalRadio.cpp @@ -0,0 +1,47 @@ +#include "ExternalRadio.h" + +#if defined(RADIOLIB_BUILD_ARDUINO) +ExternalRadio::ExternalRadio(uint32_t pin) : PhysicalLayer(1, 0) { + mod = new Module(RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, pin); + mod->hal->pinMode(pin, mod->hal->GpioModeOutput); + this->prevFrf = 0; +} +#endif + +ExternalRadio::ExternalRadio(RadioLibHal *hal, uint32_t pin) : PhysicalLayer(1, 0) { + mod = new Module(hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, pin); + mod->hal->pinMode(pin, mod->hal->GpioModeOutput); + this->prevFrf = 0; +} + +Module* ExternalRadio::getMod() { + return(mod); +} + +int16_t ExternalRadio::setFrequencyDeviation(float freqDev) { + (void)freqDev; + return(RADIOLIB_ERR_NONE); +} + +int16_t ExternalRadio::setDataShaping(uint8_t sh) { + (void)sh; + return(RADIOLIB_ERR_NONE); +} + +int16_t ExternalRadio::setEncoding(uint8_t encoding) { + (void)encoding; + return(RADIOLIB_ERR_NONE); +} + +int16_t ExternalRadio::transmitDirect(uint32_t frf) { + if(frf != this->prevFrf) { + uint32_t val = this->mod->hal->GpioLevelLow; + if(frf > this->prevFrf) { + val = this->mod->hal->GpioLevelHigh; + } + this->prevFrf = frf; + this->mod->hal->digitalWrite(this->mod->getGpio(), val); + } + + return(RADIOLIB_ERR_NONE); +} \ No newline at end of file diff --git a/lib/lib_rf/RadioLib/src/protocols/ExternalRadio/ExternalRadio.h b/lib/lib_rf/RadioLib/src/protocols/ExternalRadio/ExternalRadio.h new file mode 100644 index 000000000..25908fd0b --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/ExternalRadio/ExternalRadio.h @@ -0,0 +1,69 @@ +#if !defined(_RADIOLIB_EXTERNAL_RADIO_H) +#define _RADIOLIB_EXTERNAL_RADIO_H + +#include "../../TypeDef.h" +#include "../../Module.h" +#if defined(RADIOLIB_BUILD_ARDUINO) +#include "../../ArduinoHal.h" +#endif + +#include "../PhysicalLayer/PhysicalLayer.h" + +class ExternalRadio: public PhysicalLayer { + public: + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Default constructor. + \param pin Output pin when using direct transmission, defaults to unused pin. + */ + ExternalRadio(uint32_t pin = RADIOLIB_NC); + #endif + + /*! + \brief Default constructor. + \param hal Pointer to the hardware abstraction layer to use. + \param pin Output pin when using direct transmission, defaults to unused pin. + */ + ExternalRadio(RadioLibHal *hal, uint32_t pin = RADIOLIB_NC); + + /*! + \brief Method to retrieve pointer to the underlying Module instance. + \returns Pointer to the Module instance. + */ + Module* getMod(); + + /*! + \brief Dummy implementation overriding PhysicalLayer. + \param freqDev Ignored. + \returns \ref status_codes + */ + int16_t setFrequencyDeviation(float freqDev) override; + + /*! + \brief Dummy implementation overriding PhysicalLayer. + \param sh Ignored. + \returns \ref status_codes + */ + int16_t setDataShaping(uint8_t sh) override; + + /*! + \brief Dummy implementation overriding PhysicalLayer. + \param encoding Ignored. + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding) override; + + /*! + \brief Direct transmission to drive external radio. + \param frf "Frequency" to control the output pin. If the frequency is higher than the one sent previously, + the output pin will be set to logic high. Otherwise it will be set to logic low. + \returns \ref status_codes + */ + int16_t transmitDirect(uint32_t frf = 0); + + private: + Module* mod; + uint32_t prevFrf; +}; + +#endif \ No newline at end of file diff --git a/lib/lib_rf/RadioLib/src/protocols/FSK4/FSK4.cpp b/lib/lib_rf/RadioLib/src/protocols/FSK4/FSK4.cpp new file mode 100644 index 000000000..f589f4595 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/FSK4/FSK4.cpp @@ -0,0 +1,129 @@ +#include "FSK4.h" +#include +#if !RADIOLIB_EXCLUDE_FSK4 + +FSK4Client::FSK4Client(PhysicalLayer* phy) { + phyLayer = phy; + #if !RADIOLIB_EXCLUDE_AFSK + audioClient = nullptr; + #endif +} + +#if !RADIOLIB_EXCLUDE_AFSK + FSK4Client::FSK4Client(AFSKClient* audio) { + phyLayer = audio->phyLayer; + audioClient = audio; + } +#endif + +int16_t FSK4Client::begin(float base, uint32_t shift, uint16_t rate) { + // save configuration + baseFreqHz = base; + shiftFreqHz = shift; + + // calculate duration of 1 bit + bitDuration = (uint32_t)1000000/rate; + + // calculate carrier shift + shiftFreq = getRawShift(shift); + + // Write resultant tones into arrays for quick lookup when modulating. + for(uint8_t i = 0; i < 4; i++) { + tones[i] = shiftFreq*i; + tonesHz[i] = shiftFreqHz*i; + } + + // calculate 24-bit frequency + baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); + + // configure for direct mode + return(phyLayer->startDirect()); +} + +void FSK4Client::idle() { + // Idle at Tone 0. + tone(0); +} + +int16_t FSK4Client::setCorrection(int16_t offsets[], float length) { + for(uint8_t i = 0; i < 4; i++) { + tones[i] += getRawShift(offsets[i]); + tonesHz[i] += offsets[i]; + } + bitDuration *= length; + return(RADIOLIB_ERR_NONE); +} + +size_t FSK4Client::write(uint8_t* buff, size_t len) { + size_t n = 0; + for(size_t i = 0; i < len; i++) { + n += FSK4Client::write(buff[i]); + } + FSK4Client::standby(); + return(n); +} + +size_t FSK4Client::write(uint8_t b) { + // send symbols MSB first + for(uint8_t i = 0; i < 4; i++) { + // Extract 4FSK symbol (2 bits) + uint8_t symbol = (b & 0xC0) >> 6; + + // Modulate + FSK4Client::tone(symbol); + + // Shift to next symbol + b = b << 2; + } + + return(1); +} + +void FSK4Client::tone(uint8_t i) { + Module* mod = phyLayer->getMod(); + uint32_t start = mod->hal->micros(); + transmitDirect(baseFreq + tones[i], baseFreqHz + tonesHz[i]); + mod->waitForMicroseconds(start, bitDuration); +} + +int16_t FSK4Client::transmitDirect(uint32_t freq, uint32_t freqHz) { + #if !RADIOLIB_EXCLUDE_AFSK + if(audioClient != nullptr) { + return(audioClient->tone(freqHz)); + } + #endif + return(phyLayer->transmitDirect(freq)); +} + +int16_t FSK4Client::standby() { + // ensure everything is stopped in interrupt timing mode + Module* mod = phyLayer->getMod(); + mod->waitForMicroseconds(0, 0); + #if !RADIOLIB_EXCLUDE_AFSK + if(audioClient != nullptr) { + return(audioClient->noTone()); + } + #endif + return(phyLayer->standby()); +} + +int32_t FSK4Client::getRawShift(int32_t shift) { + // calculate module carrier frequency resolution + int32_t step = round(phyLayer->getFreqStep()); + + // check minimum shift value + if(abs(shift) < step / 2) { + return(0); + } + + // round shift to multiples of frequency step size + if(abs(shift) % step < (step / 2)) { + return(shift / step); + } + if(shift < 0) { + return((shift / step) - 1); + } + return((shift / step) + 1); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/FSK4/FSK4.h b/lib/lib_rf/RadioLib/src/protocols/FSK4/FSK4.h new file mode 100644 index 000000000..a1e91e372 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/FSK4/FSK4.h @@ -0,0 +1,99 @@ +#if !defined(_RADIOLIB_FSK4_H) +#define _RADIOLIB_FSK4_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_FSK4 + +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" + +/*! + \class FSK4Client + \brief Client for FSK-4 communication. The public interface is the same as Arduino Serial. +*/ +class FSK4Client { + public: + /*! + \brief Constructor for FSK-4 mode. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + */ + explicit FSK4Client(PhysicalLayer* phy); + + #if !RADIOLIB_EXCLUDE_AFSK + /*! + \brief Constructor for AFSK mode. + \param audio Pointer to the AFSK instance providing audio. + */ + explicit FSK4Client(AFSKClient* audio); + #endif + + // basic methods + + /*! + \brief Initialization method. + \param base Base (space) frequency to be used in MHz (in FSK-4 mode), + or the space tone frequency in Hz (in AFSK mode) + \param shift Frequency shift between each tone in Hz. + \param rate Baud rate to be used during transmission. + \returns \ref status_codes + */ + int16_t begin(float base, uint32_t shift, uint16_t rate); + + /*! + \brief Send out idle condition (RF tone at mark frequency). + */ + void idle(); + + /*! + \brief Set correction coefficients for frequencies and tone length. + \param offsets Four positive or negative correction offsets for audio frequencies in Hz. + \param length Tone length modifier, defaults to 1.0. + \returns \ref status_codes + */ + int16_t setCorrection(int16_t offsets[4], float length = 1.0f); + + /*! + \brief Transmit binary data. + \param buff Buffer to transmit. + \param len Number of bytes to transmit. + \returns Number of transmitted bytes. + */ + size_t write(uint8_t* buff, size_t len); + + /*! + \brief Transmit a single byte. + \param b Byte to transmit. + \returns Number of transmitted bytes. + */ + size_t write(uint8_t b); + + /*! + \brief Stop transmitting. + \returns \ref status_codes + */ + int16_t standby(); + +#if !RADIOLIB_GODMODE + private: +#endif + PhysicalLayer* phyLayer; + #if !RADIOLIB_EXCLUDE_AFSK + AFSKClient* audioClient; + #endif + + uint32_t baseFreq = 0, baseFreqHz = 0; + uint32_t shiftFreq = 0, shiftFreqHz = 0; + uint32_t bitDuration = 0; + uint32_t tones[4]; + uint32_t tonesHz[4]; + + void tone(uint8_t i); + + int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); + int32_t getRawShift(int32_t shift); +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/Hellschreiber/Hellschreiber.cpp b/lib/lib_rf/RadioLib/src/protocols/Hellschreiber/Hellschreiber.cpp new file mode 100644 index 000000000..f23bc40fa --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -0,0 +1,102 @@ +#include "Hellschreiber.h" + +#if !RADIOLIB_EXCLUDE_HELLSCHREIBER + +HellClient::HellClient(PhysicalLayer* phy) { + phyLayer = phy; + lineFeed = " "; + #if !RADIOLIB_EXCLUDE_AFSK + audioClient = nullptr; + #endif +} + +#if !RADIOLIB_EXCLUDE_AFSK +HellClient::HellClient(AFSKClient* audio) { + phyLayer = audio->phyLayer; + lineFeed = " "; + audioClient = audio; +} +#endif + +int16_t HellClient::begin(float base, float rate) { + // calculate 24-bit frequency + baseFreqHz = base; + baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); + + // calculate "pixel" duration + pixelDuration = 1000000.0/rate; + + // configure for direct mode + return(phyLayer->startDirect()); +} + +size_t HellClient::printGlyph(uint8_t* buff) { + // print the character + Module* mod = phyLayer->getMod(); + bool transmitting = false; + for(uint8_t mask = 0x40; mask >= 0x01; mask >>= 1) { + for(int8_t i = RADIOLIB_HELL_FONT_HEIGHT - 1; i >= 0; i--) { + uint32_t start = mod->hal->micros(); + if((buff[i] & mask) && (!transmitting)) { + transmitting = true; + transmitDirect(baseFreq, baseFreqHz); + } else if((!(buff[i] & mask)) && (transmitting)) { + transmitting = false; + standby(); + } + mod->waitForMicroseconds(start, pixelDuration); + } + } + + // make sure transmitter is off + standby(); + + return(1); +} + +void HellClient::setInversion(bool inv) { + invert = inv; +} + +size_t HellClient::write(uint8_t b) { + // convert to position in font buffer + uint8_t pos = b; + if((pos >= ' ') && (pos <= '_')) { + pos -= ' '; + } else if((pos >= 'a') && (pos <= 'z')) { + pos -= (2*' '); + } else { + return(0); + } + + // fetch character from flash + uint8_t buff[RADIOLIB_HELL_FONT_WIDTH]; + buff[0] = 0x00; + for(uint8_t i = 0; i < RADIOLIB_HELL_FONT_WIDTH - 2; i++) { + buff[i + 1] = RADIOLIB_NONVOLATILE_READ_BYTE(&HellFont[pos][i]); + } + buff[RADIOLIB_HELL_FONT_WIDTH - 1] = 0x00; + + // print the character + return(printGlyph(buff)); +} + +int16_t HellClient::transmitDirect(uint32_t freq, uint32_t freqHz) { + #if !RADIOLIB_EXCLUDE_AFSK + if(audioClient != nullptr) { + return(audioClient->tone(freqHz)); + } + #endif + return(phyLayer->transmitDirect(freq)); +} + +int16_t HellClient::standby() { + #if !RADIOLIB_EXCLUDE_AFSK + if(audioClient != nullptr) { + return(audioClient->noTone(invert)); + } + #endif + return(phyLayer->standby(RADIOLIB_STANDBY_WARM)); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/Hellschreiber/Hellschreiber.h b/lib/lib_rf/RadioLib/src/protocols/Hellschreiber/Hellschreiber.h new file mode 100644 index 000000000..3ee42174d --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/Hellschreiber/Hellschreiber.h @@ -0,0 +1,156 @@ +#if !defined(_RADIOLIB_HELLSCHREIBER_H) +#define _RADIOLIB_HELLSCHREIBER_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_HELLSCHREIBER + +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" +#include "../Print/Print.h" + +#define RADIOLIB_HELL_FONT_WIDTH 7 +#define RADIOLIB_HELL_FONT_HEIGHT 7 + +// font definition: characters are stored in rows, +// least significant byte of each character is the first row +// Hellschreiber use 7x7 characters, but this simplified font uses only 5x5 +// the extra bytes aren't stored +static const uint8_t HellFont[64][RADIOLIB_HELL_FONT_WIDTH - 2] RADIOLIB_NONVOLATILE = { + { 0b0000000, 0b0000000, 0b0000000, 0b0000000, 0b0000000 }, // space + { 0b0001000, 0b0001000, 0b0001000, 0b0000000, 0b0001000 }, // ! + { 0b0010100, 0b0010100, 0b0000000, 0b0000000, 0b0000000 }, // " + { 0b0010100, 0b0111110, 0b0010100, 0b0111110, 0b0010100 }, // # + { 0b0111110, 0b0101000, 0b0111110, 0b0001010, 0b0111110 }, // $ + { 0b0110010, 0b0110100, 0b0001000, 0b0010110, 0b0100110 }, // % + { 0b0010000, 0b0101000, 0b0010000, 0b0101000, 0b0110100 }, // & + { 0b0001000, 0b0001000, 0b0000000, 0b0000000, 0b0000000 }, // ' + { 0b0000100, 0b0001000, 0b0001000, 0b0001000, 0b0000100 }, // ( + { 0b0010000, 0b0001000, 0b0001000, 0b0001000, 0b0010000 }, // ) + { 0b0010100, 0b0001000, 0b0010100, 0b0000000, 0b0000000 }, // * + { 0b0001000, 0b0001000, 0b0111110, 0b0001000, 0b0001000 }, // + + { 0b0000000, 0b0000000, 0b0000000, 0b0001000, 0b0010000 }, // , + { 0b0000000, 0b0000000, 0b0111110, 0b0000000, 0b0000000 }, // - + { 0b0000000, 0b0000000, 0b0000000, 0b0000000, 0b0001000 }, // . + { 0b0000010, 0b0000100, 0b0001000, 0b0010000, 0b0100000 }, // / + { 0b0011100, 0b0100110, 0b0101010, 0b0110010, 0b0011100 }, // 0 + { 0b0011000, 0b0001000, 0b0001000, 0b0001000, 0b0001000 }, // 1 + { 0b0011000, 0b0100100, 0b0001000, 0b0010000, 0b0111100 }, // 2 + { 0b0111100, 0b0000100, 0b0011100, 0b0000100, 0b0111100 }, // 3 + { 0b0100100, 0b0100100, 0b0111100, 0b0000100, 0b0000100 }, // 4 + { 0b0011100, 0b0100000, 0b0111100, 0b0000100, 0b0111100 }, // 5 + { 0b0111100, 0b0100000, 0b0111100, 0b0100100, 0b0111100 }, // 6 + { 0b0111100, 0b0000100, 0b0001000, 0b0010000, 0b0100000 }, // 7 + { 0b0111100, 0b0100100, 0b0011000, 0b0100100, 0b0111100 }, // 8 + { 0b0111100, 0b0100100, 0b0111100, 0b0000100, 0b0111100 }, // 9 + { 0b0000000, 0b0001000, 0b0000000, 0b0000000, 0b0001000 }, // : + { 0b0000000, 0b0001000, 0b0000000, 0b0001000, 0b0001000 }, // ; + { 0b0000100, 0b0001000, 0b0010000, 0b0001000, 0b0000100 }, // < + { 0b0000000, 0b0111110, 0b0000000, 0b0111110, 0b0000000 }, // = + { 0b0010000, 0b0001000, 0b0000100, 0b0001000, 0b0010000 }, // > + { 0b0011100, 0b0000100, 0b0001000, 0b0000000, 0b0001000 }, // ? + { 0b0011100, 0b0100010, 0b0101110, 0b0101010, 0b0001100 }, // @ + { 0b0111110, 0b0100010, 0b0111110, 0b0100010, 0b0100010 }, // A + { 0b0111100, 0b0010010, 0b0011110, 0b0010010, 0b0111100 }, // B + { 0b0011110, 0b0110000, 0b0100000, 0b0110000, 0b0011110 }, // C + { 0b0111100, 0b0100010, 0b0100010, 0b0100010, 0b0111100 }, // D + { 0b0111110, 0b0100000, 0b0111100, 0b0100000, 0b0111110 }, // E + { 0b0111110, 0b0100000, 0b0111100, 0b0100000, 0b0100000 }, // F + { 0b0111110, 0b0100000, 0b0101110, 0b0100010, 0b0111110 }, // G + { 0b0100010, 0b0100010, 0b0111110, 0b0100010, 0b0100010 }, // H + { 0b0011100, 0b0001000, 0b0001000, 0b0001000, 0b0011100 }, // I + { 0b0111100, 0b0001000, 0b0001000, 0b0101000, 0b0111000 }, // J + { 0b0100100, 0b0101000, 0b0110000, 0b0101000, 0b0100100 }, // K + { 0b0100000, 0b0100000, 0b0100000, 0b0100000, 0b0111100 }, // L + { 0b0100010, 0b0110110, 0b0101010, 0b0100010, 0b0100010 }, // M + { 0b0100010, 0b0110010, 0b0101010, 0b0100110, 0b0100010 }, // N + { 0b0011100, 0b0100010, 0b0100010, 0b0100010, 0b0011100 }, // O + { 0b0111110, 0b0100010, 0b0111110, 0b0100000, 0b0100000 }, // P + { 0b0111110, 0b0100010, 0b0100010, 0b0100110, 0b0111110 }, // Q + { 0b0111110, 0b0100010, 0b0111110, 0b0100100, 0b0100010 }, // R + { 0b0111110, 0b0100000, 0b0111110, 0b0000010, 0b0111110 }, // S + { 0b0111110, 0b0001000, 0b0001000, 0b0001000, 0b0001000 }, // T + { 0b0100010, 0b0100010, 0b0100010, 0b0100010, 0b0111110 }, // U + { 0b0100010, 0b0100010, 0b0010100, 0b0010100, 0b0001000 }, // V + { 0b0100010, 0b0100010, 0b0101010, 0b0110110, 0b0100010 }, // W + { 0b0100010, 0b0010100, 0b0001000, 0b0010100, 0b0100010 }, // X + { 0b0100010, 0b0010100, 0b0001000, 0b0001000, 0b0001000 }, // Y + { 0b0111110, 0b0000100, 0b0001000, 0b0010000, 0b0111110 }, // Z + { 0b0001100, 0b0001000, 0b0001000, 0b0001000, 0b0001100 }, // [ + { 0b0100000, 0b0010000, 0b0001000, 0b0000100, 0b0000010 }, // backslash + { 0b0011000, 0b0001000, 0b0001000, 0b0001000, 0b0011000 }, // ] + { 0b0001000, 0b0010100, 0b0000000, 0b0000000, 0b0000000 }, // ^ + { 0b0000000, 0b0000000, 0b0000000, 0b0000000, 0b0111110 } // _ +}; + +/*! + \class HellClient + \brief Client for Hellschreiber transmissions. +*/ +class HellClient: public RadioLibPrint { + public: + /*! + \brief Constructor for 2-FSK mode. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + */ + explicit HellClient(PhysicalLayer* phy); + + #if !RADIOLIB_EXCLUDE_AFSK + /*! + \brief Constructor for AFSK mode. + \param audio Pointer to the AFSK instance providing audio. + */ + explicit HellClient(AFSKClient* audio); + #endif + + // basic methods + + /*! + \brief Initialization method. + \param base Base RF frequency to be used in MHz (in 2-FSK mode), or the tone frequency in Hz (in AFSK mode). + \param rate Baud rate to be used during transmission. Defaults to 122.5 ("Feld Hell") + */ + int16_t begin(float base, float rate = 122.5); + + /*! + \brief Method to "print" a buffer of pixels, this is exposed to allow users to send custom characters. + \param buff Buffer of pixels to send, in a 7x7 pixel array. + \returns Always returns the number of printed glyphs (1). + */ + size_t printGlyph(uint8_t* buff); + + /*! + \brief Invert text color. + \param inv Whether to enable color inversion (white text on black background), or not (black text on white background) + */ + void setInversion(bool inv); + + /*! + \brief Write one byte. Implementation of interface of the RadioLibPrint/Print class. + \param b Byte to write. + \returns 1 if the byte was written, 0 otherwise. + */ + size_t write(uint8_t b); + +#if !RADIOLIB_GODMODE + private: +#endif + PhysicalLayer* phyLayer; + #if !RADIOLIB_EXCLUDE_AFSK + AFSKClient* audioClient; + #endif + + uint32_t baseFreq = 0, baseFreqHz = 0; + uint32_t pixelDuration = 0; + bool invert = false; + + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); + + int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); + int16_t standby(); +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp b/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp new file mode 100644 index 000000000..0e7692c3a --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -0,0 +1,2922 @@ +#include "LoRaWAN.h" +#include +#if defined(ESP_PLATFORM) +#include "esp_attr.h" +#endif + +#if !RADIOLIB_EXCLUDE_LORAWAN + +// flag to indicate whether there was some action during Rx mode (timeout or downlink) +static volatile bool downlinkAction = false; + +// interrupt service routine to handle downlinks automatically +#if defined(ESP8266) || defined(ESP32) + IRAM_ATTR +#endif +static void LoRaWANNodeOnDownlinkAction(void) { + downlinkAction = true; +} + +uint8_t getDownlinkDataRate(uint8_t uplink, uint8_t offset, uint8_t base, uint8_t min, uint8_t max) { + int8_t dr = uplink - offset + base; + if(dr < min) { + dr = min; + } else if (dr > max) { + dr = max; + } + return(dr); +} + +LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t subBand) { + this->phyLayer = phy; + this->band = band; + this->rx2 = this->band->rx2; + this->txPowerMax = this->band->powerMax; + this->subBand = subBand; + this->difsSlots = 2; + this->backoffMax = 6; + this->enableCSMA = false; +} + +void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA) { + this->backoffMax = backoffMax; + this->difsSlots = difsSlots; + this->enableCSMA = enableCSMA; +} + +void LoRaWANNode::wipe() { + memset(this->bufferNonces, 0, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + memset(this->bufferSession, 0, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); +} + +uint8_t* LoRaWANNode::getBufferNonces() { + return(this->bufferNonces); +} + +int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) { + if(this->isJoined()) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active"); + return(RADIOLIB_ERR_NONE); + } + + int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + RADIOLIB_ASSERT(state); + + // copy the whole buffer over + memcpy(this->bufferNonces, persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + + // revert to inactive as long as no session is restored + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; + + return(state); +} + +uint8_t* LoRaWANNode::getBufferSession() { + // update buffer contents + this->saveSession(); + + return(this->bufferSession); +} + +int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { + if(this->isJoined()) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active"); + return(RADIOLIB_ERR_NONE); + } + + int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); + RADIOLIB_ASSERT(state); + + // the Nonces buffer holds a checksum signature - compare this to the signature that is in the session buffer + uint16_t signatureNonces = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE]); + uint16_t signatureInSession = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE]); + if(signatureNonces != signatureInSession) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The supplied session buffer does not match the Nonces buffer"); + return(RADIOLIB_ERR_CHECKSUM_MISMATCH); + } + + // copy the whole buffer over + memcpy(this->bufferSession, persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); + + // as both the Nonces and session are restored, revert to active session + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; + + return(state); +} + +int16_t LoRaWANNode::checkBufferCommon(uint8_t *buffer, uint16_t size) { + // check if there are actually values in the buffer + size_t i = 0; + for(; i < size; i++) { + if(buffer[i]) { + break; + } + } + if(i == size) { + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + + // check integrity of the whole buffer (compare checksum to included checksum) + uint16_t checkSum = LoRaWANNode::checkSum16(buffer, size - 2); + uint16_t signature = LoRaWANNode::ntoh(&buffer[size - 2]); + if(signature != checkSum) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Calculated checksum: %04X, expected: %04X", checkSum, signature); + return(RADIOLIB_ERR_CHECKSUM_MISMATCH); + } + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass, uint8_t freqPlan) { + // if already joined, ignore + if(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE) { + return(RADIOLIB_ERR_NONE); + } + + bool isSameKeys = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM]) == checkSum; + bool isSameMode = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE]) == lwMode; + bool isSameClass = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS]) == lwClass; + bool isSamePlan = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN]) == freqPlan; + + // check if Nonces buffer matches the current configuration + if(!isSameKeys || !isSameMode || !isSameClass || !isSamePlan) { + // if configuration did not match, discard whatever is currently in the buffers and start fresh + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (checksum: %d, mode: %d, class: %d, plan: %d)", isSameKeys, isSameMode, isSameClass, isSamePlan); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Nonces buffer:"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Clearing buffer and starting fresh"); + this->wipe(); + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + + if(lwMode == RADIOLIB_LORAWAN_MODE_OTAA) { + // Nonces buffer is OK, so we can at least restore Nonces + this->devNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE]); + this->joinNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], 3); + } + + // uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION]; + // if (RADIOLIB_LORAWAN_NONCES_VERSION_VAL > nvm_table_version) { + // // set default values for variables that are new or something + // } + + if(this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] == 0) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("No active session in progress; please join the network"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + + // pull all authentication keys from persistent storage + this->devAddr = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR]); + memcpy(this->appSKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->nwkSEncKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->fNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->sNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); + + // restore session parameters + this->rev = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN session: v1.%d", this->rev); + this->homeNetId = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID]); + this->aFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN]); + this->nFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN]); + this->confFcntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP]); + this->confFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN]); + this->adrFcnt = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT]); + this->fcntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP]); + + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // for dynamic bands, first restore the defined channels before restoring ADR + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + // restore the defined channels + state = this->restoreChannels(); + RADIOLIB_ASSERT(state); + } + + // restore the complete MAC state + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, + .payload = { 0 }, + .len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn, + .repeat = 0, + }; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], cmd.len); + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], cmd.len); + (void)execMacCommand(&cmd); + + // for fixed bands, first restore ADR, then the defined channels + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + state = this->restoreChannels(); + RADIOLIB_ASSERT(state); + } + + cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], cmd.len); + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], cmd.len); + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], cmd.len); + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP], cmd.len); + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP], cmd.len); + (void)execMacCommand(&cmd); + + // copy uplink MAC command queue back in place + memcpy(&this->commandsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], sizeof(LoRaWANMacCommandQueue_t)); + + state = this->setPhyProperties(); + RADIOLIB_ASSERT(state); + + // full session is restored, so set joined flag to whichever mode is restored + this->activeMode = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE]); + + return(state); +} + +int16_t LoRaWANNode::restoreChannels() { + // first do the default channels, in case these are not covered by restored channels + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + this->setupChannelsDyn(false); + } else { // RADIOLIB_LORAWAN_BAND_FIXED + this->setupChannelsFix(this->subBand); + } + + uint8_t bufferZeroes[5] = { 0 }; + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; + + LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, .payload = { 0 }, .len = 0, .repeat = 0 }; + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; + memcpy(cmd.payload, startChannelsUp + (i * cmd.len), cmd.len); + if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes + cmd.repeat = 1; + (void)execMacCommand(&cmd); + } + } + + uint8_t *startChannelsDown = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS]; + + cmd.cid = RADIOLIB_LORAWAN_MAC_DL_CHANNEL; + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; + memcpy(cmd.payload, startChannelsDown + (i * cmd.len), cmd.len); + if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes + (void)execMacCommand(&cmd); + } + } + + } else { // RADIOLIB_LORAWAN_BAND_FIXED + uint8_t *startMACpayload = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; + + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .payload = { 0 }, + .len = 0, + .repeat = 0, + }; + + // there are at most 8 channel masks present + for(int i = 0; i < 8; i++) { + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + memcpy(cmd.payload, startMACpayload + (i * cmd.len), cmd.len); + // there COULD, according to spec, be an all zeroes ADR command - meh + if(memcmp(cmd.payload, bufferZeroes, cmd.len) == 0) { + break; + } + cmd.repeat = (i+1); + (void)execMacCommand(&cmd); + } + } + return(RADIOLIB_ERR_NONE); +} + +void LoRaWANNode::beginCommon(uint8_t initialDr) { + // in case a new session is started while there is an ongoing session + // clear the MAC queues completely + memset(&(this->commandsUp), 0, sizeof(LoRaWANMacCommandQueue_t)); + memset(&(this->commandsDown), 0, sizeof(LoRaWANMacCommandQueue_t)); + + uint8_t drUp = 0; + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + // if join datarate is user-specified and valid, select that value + if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(initialDr >= this->band->txFreqs[0].drMin && initialDr <= this->band->txFreqs[0].drMax) { + drUp = initialDr; + } else { + // if there is no channel that allowed the user-specified datarate, revert to default datarate + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); + initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + } + } + + // if there is no (channel that allowed the) user-specified datarate, use a default datarate + // we use the floor of the average datarate of the first default channel + if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + drUp = (this->band->txFreqs[0].drMin + this->band->txFreqs[0].drMax) / 2; + } + + } else { + // if the user specified a certain datarate, check if any of the configured channels allows it + if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + uint8_t i = 0; + for(; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + if(initialDr >= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin + && initialDr <= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax) { + break; + } + } + } + // if there is no channel that allowed the user-specified datarate, revert to default datarate + if(i == RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); + initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + } + } + + // if there is no (channel that allowed the) user-specified datarate, use a default datarate + // we use the join-request datarate for one of the available channels + if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + // randomly select one of 8 or 9 channels and find corresponding datarate + uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; + uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 + if(rand <= 8) { + drUp = this->band->txSpans[0].joinRequestDataRate; // if one of the first 8 channels, select datarate of span 0 + } else { + drUp = this->band->txSpans[1].joinRequestDataRate; // if ninth channel, select datarate of span 1 + } + } + + } + + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .payload = { 0 }, + .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .repeat = 0, + }; + cmd.payload[0] = (drUp << 4); // set uplink datarate + cmd.payload[0] |= 0; // default to max Tx Power + cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; + uint8_t maxDCyclePower; + switch(this->band->dutyCycle) { + case(0): + maxDCyclePower = 0; + break; + case(3600): + maxDCyclePower = 10; + break; + case(36000): + maxDCyclePower = 7; + break; + default: + maxDCyclePower = 0; + break; + } + cmd.payload[0] = maxDCyclePower; + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LORAWAN_RX1_DR_OFFSET << 4); + cmd.payload[0] |= this->rx2.drMax; // may be set by user, otherwise band's default upon initialization + uint32_t rx2Freq = uint32_t(this->rx2.freq * 10000); + LoRaWANNode::hton(&cmd.payload[1], rx2Freq, 3); + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS / 1000); + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn; + cmd.payload[0] = (this->band->dwellTimeDn > 0 ? 1 : 0) << 5; + cmd.payload[0] |= (this->band->dwellTimeUp > 0 ? 1 : 0) << 4; + uint8_t maxEIRPRaw; + switch(this->band->powerMax) { + case(12): + maxEIRPRaw = 2; + break; + case(14): + maxEIRPRaw = 4; + break; + case(16): + maxEIRPRaw = 5; + break; + case(19): // this option does not exist for the TxParamSetupReq but will be caught during execution + maxEIRPRaw = 7; + break; + case(30): + maxEIRPRaw = 13; + break; + default: + maxEIRPRaw = 2; + break; + } + cmd.payload[0] |= maxEIRPRaw; + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP << 4); + cmd.payload[0] |= RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP; + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N << 4); + cmd.payload[0] |= RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N; + (void)execMacCommand(&cmd); +} + +int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force, uint8_t joinDr) { + // if not forced and already joined, don't do anything + if(!force && this->isJoined()) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("beginOTAA(): Did not rejoin: session already active"); + return(RADIOLIB_ERR_NONE); + } + + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // generate activation key checksum + uint16_t checkSum = 0; + checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&joinEUI), 8); + checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&devEUI), 8); + checkSum ^= LoRaWANNode::checkSum16(nwkKey, 16); + checkSum ^= LoRaWANNode::checkSum16(appKey, 16); + + // if The Force is used, disable the active session; + // as a result, restore() will only restore Nonces if they are available, not the session + if(force) { + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; + } + + state = this->restore(checkSum, RADIOLIB_LORAWAN_MODE_OTAA, RADIOLIB_LORAWAN_CLASS_A, this->band->bandNum); + + if(!force) { + return(state); + } + + Module* mod = this->phyLayer->getMod(); + + // setup join-request uplink/downlink frequencies and datarates + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + state = this->setupChannelsDyn(true); + } else { + state = this->setupChannelsFix(this->subBand); + } + RADIOLIB_ASSERT(state); + + // on fixed bands, the join-datarate is specified per specification + // therefore, we ignore the value that was specified by the user + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + } + // setup all MAC properties to default values + this->beginCommon(joinDr); + + // set the physical layer configuration + state = this->setPhyProperties(); + RADIOLIB_ASSERT(state); + + // select a random pair of Tx/Rx channels + state = this->selectChannels(); + RADIOLIB_ASSERT(state); + + // configure for uplink with default configuration + state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); + RADIOLIB_ASSERT(state); + + // copy devNonce currently in use + uint16_t devNonceUsed = this->devNonce; + // increment devNonce as we are sending another join-request + this->devNonce += 1; + + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE], this->devNonce); + + // build the join-request message + uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; + + // set the packet fields + joinRequestMsg[0] = RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], joinEUI); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS], devEUI); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed); + + // add the authentication code + uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), nwkKey); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t)], mic); + + // send it + state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); + this->rxDelayStart = mod->hal->millis(); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Join-request sent <-- Rx Delay start"); + RADIOLIB_ASSERT(state); + + // configure Rx delay for join-accept message - these are re-configured once a valid join-request is received + this->rxDelays[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS; + this->rxDelays[1] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS; + + // handle Rx1 and Rx2 windows - returns RADIOLIB_ERR_NONE if a downlink is received + state = downlinkCommon(); + RADIOLIB_ASSERT(state); + + // build the buffer for the reply data + uint8_t joinAcceptMsgEnc[RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN]; + + // check received length + size_t lenRx = this->phyLayer->getPacketLength(true); + if((lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) && (lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN)) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply length mismatch, expected %luB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); + } + + // read the packet + state = this->phyLayer->readData(joinAcceptMsgEnc, lenRx); + // downlink frames are sent without CRC, which will raise error on SX127x + // we can ignore that error + if(state != RADIOLIB_ERR_LORA_HEADER_DAMAGED) { + RADIOLIB_ASSERT(state); + } + + // check reply message type + if((joinAcceptMsgEnc[0] & RADIOLIB_LORAWAN_MHDR_MTYPE_MASK) != RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); + } + + // decrypt the join accept message + // this is done by encrypting again in ECB mode + // the first byte is the MAC header which is not encrypted + uint8_t joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN]; + joinAcceptMsg[0] = joinAcceptMsgEnc[0]; + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]); + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAcceptMsg:"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(joinAcceptMsg, lenRx); + + // get current JoinNonce from downlink and previous JoinNonce from persistent storage + uint32_t joinNonceNew = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinNoncePrev: %d, JoinNonce: %d", this->joinNonce, joinNonceNew); + // JoinNonce received must be greater than the last JoinNonce heard, else error + if((this->joinNonce > 0) && (joinNonceNew <= this->joinNonce)) { + return(RADIOLIB_ERR_JOIN_NONCE_INVALID); + } + this->joinNonce = joinNonceNew; + + this->homeNetId = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], 3); + this->devAddr = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS]); + + // check LoRaWAN revision (the MIC verification depends on this) + uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS]; + this->rev = (dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) >> 7; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN revision: 1.%d", this->rev); + + // verify MIC + if(this->rev == 1) { + // 1.1 version, first we need to derive the join accept integrity key + uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_INT_KEY; + LoRaWANNode::hton(&keyDerivationBuff[1], devEUI); + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->jSIntKey); + + // prepare the buffer for MIC calculation + uint8_t micBuff[3*RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + micBuff[0] = RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE; + LoRaWANNode::hton(&micBuff[1], joinEUI); + LoRaWANNode::hton(&micBuff[9], devNonceUsed); + memcpy(&micBuff[11], joinAcceptMsg, lenRx); + + if(!verifyMIC(micBuff, lenRx + 11, this->jSIntKey)) { + return(RADIOLIB_ERR_CRC_MISMATCH); + } + + } else { + // 1.0 version + if(!verifyMIC(joinAcceptMsg, lenRx, nwkKey)) { + return(RADIOLIB_ERR_CRC_MISMATCH); + } + + } + + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, + .payload = { 0 }, + .len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn, + .repeat = 0, + }; + cmd.payload[0] = dlSettings & 0x7F; + uint32_t rx2Freq = uint32_t(this->rx2.freq * 10000); // default Rx2 frequency + LoRaWANNode::hton(&cmd.payload[1], rx2Freq, 3); + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; + cmd.payload[0] = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]; + (void)execMacCommand(&cmd); + + // in case of dynamic band, setup the default channels first + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + this->setupChannelsDyn(false); + } + // process CFlist if present + if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) { + uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; + memcpy(&cfList[0], &joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS], RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); + this->processCFList(cfList); + } + // if no CFList was received, default or subband are already setup so don't need to do anything else + + // prepare buffer for key derivation + uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], joinNonce, 3); + + // check protocol version (1.0 vs 1.1) + if(this->rev == 1) { + // 1.1 version, derive the keys + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], devNonceUsed); + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; + + RadioLibAES128Instance.init(appKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); + + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY; + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey); + + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_S_NWK_S_INT_KEY; + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->sNwkSIntKey); + + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_NWK_S_ENC_KEY; + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey); + + // enqueue the RekeyInd MAC command to be sent in the next uplink + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_REKEY, + .payload = { this->rev }, + .len = sizeof(uint8_t), + .repeat = 0x01 << RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP, + }; + state = pushMacCommand(&cmd, &this->commandsUp); + RADIOLIB_ASSERT(state); + + } else { + // 1.0 version, just derive the keys + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed); + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); + + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY; + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey); + + memcpy(this->sNwkSIntKey, this->fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->nwkSEncKey, this->fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); + + } + + // reset all frame counters + this->fcntUp = 0; + this->aFcntDown = 0; + this->nFcntDown = 0; + this->confFcntUp = RADIOLIB_LORAWAN_FCNT_NONE; + this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + this->adrFcnt = 0; + + // save the activation keys checksum, device address & keys as well as JoinAccept values; these are only ever set when joining + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], RADIOLIB_LORAWAN_MODE_OTAA); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], RADIOLIB_LORAWAN_CLASS_A); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], checkSum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], this->joinNonce, 3); + + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; + this->activeMode = RADIOLIB_LORAWAN_MODE_OTAA; + + // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, bool force, uint8_t initialDr) { + // if not forced and already joined, don't do anything + if(!force && this->isJoined()) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("beginABP(): Did not rejoin: session already active"); + return(RADIOLIB_ERR_NONE); + } + + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // check if we actually need to restart from a clean session + uint16_t checkSum = 0; + checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&addr), 4); + checkSum ^= LoRaWANNode::checkSum16(nwkSKey, 16); + checkSum ^= LoRaWANNode::checkSum16(appSKey, 16); + if(fNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); } + if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); } + + // if The Force is used, disable the active session; + // as a result, restore() will not restore the session (and there are no Nonces in ABP mode) + if(force) { + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; + } + + state = this->restore(checkSum, RADIOLIB_LORAWAN_MODE_ABP, RADIOLIB_LORAWAN_CLASS_A, this->band->bandNum); + + if(!force) { + return(state); + } + + this->devAddr = addr; + memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->nwkSEncKey, nwkSKey, RADIOLIB_AES128_KEY_SIZE); + if(fNwkSIntKey) { + this->rev = 1; + memcpy(this->fNwkSIntKey, fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); + } else { + memcpy(this->fNwkSIntKey, nwkSKey, RADIOLIB_AES128_KEY_SIZE); + } + if(sNwkSIntKey) { + memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); + } + + // setup the uplink/downlink channels and initial datarate + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + this->setupChannelsDyn(); + } else { + this->setupChannelsFix(this->subBand); + } + + // setup all MAC properties to default values + this->beginCommon(initialDr); + + // set the physical layer configuration + state = this->setPhyProperties(); + RADIOLIB_ASSERT(state); + + // reset all frame counters + this->fcntUp = 0; + this->aFcntDown = 0; + this->nFcntDown = 0; + this->confFcntUp = RADIOLIB_LORAWAN_FCNT_NONE; + this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + this->adrFcnt = 0; + + // save the activation keys checksum, mode, class, frequency plan + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], RADIOLIB_LORAWAN_MODE_ABP); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], RADIOLIB_LORAWAN_CLASS_A); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], checkSum); + + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; + this->activeMode = RADIOLIB_LORAWAN_MODE_ABP; + + // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + + return(RADIOLIB_ERR_NONE); +} + +bool LoRaWANNode::isJoined() { + return(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE); +} + +int16_t LoRaWANNode::saveSession() { + // store DevAddr and all keys + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + + // copy the signature of the Nonces buffer over to the Session buffer + uint16_t noncesSignature = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE]); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], noncesSignature); + + // store network parameters + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); + + // store all frame counters + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN], this->aFcntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN], this->nFcntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP], this->confFcntUp); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN], this->confFcntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT], this->adrFcnt); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP], this->fcntUp); + + // save the current uplink MAC command queue + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); + + // generate the signature of the Session buffer, and store it in the last two bytes of the Session buffer + uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LORAWAN_SESSION_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SIGNATURE], signature); + + return(RADIOLIB_ERR_NONE); +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t LoRaWANNode::uplink(String& str, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { + return(this->uplink(str.c_str(), port, isConfirmed, event)); +} +#endif + +int16_t LoRaWANNode::uplink(const char* str, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { + return(this->uplink((uint8_t*)str, strlen(str), port, isConfirmed, event)); +} + +int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { + // if not joined, don't do anything + if(!this->isJoined()) { + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + + Module* mod = this->phyLayer->getMod(); + + // check if the Rx windows were closed after sending the previous uplink + // this FORCES a user to call downlink() after an uplink() + if(this->rxDelayEnd < this->rxDelayStart) { + // not enough time elapsed since the last uplink, we may still be in an Rx window + return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); + } + + // if adhering to dutyCycle and the time since last uplink + interval has not elapsed, return an error + if(this->dutyCycleEnabled && this->rxDelayStart + dutyCycleInterval(this->dutyCycle, this->lastToA) > mod->hal->millis()) { + return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); + } + + // check destination port + if(port > 0xDF) { + return(RADIOLIB_ERR_INVALID_PORT); + } + // port 0 is only allowed for MAC-only payloads + if(port == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + if (!this->isMACPayload) { + return(RADIOLIB_ERR_INVALID_PORT); + } + // if this is MAC only payload, continue and reset for next uplink + this->isMACPayload = false; + } + + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) + uint8_t foptsLen = 0; + size_t foptsBufSize = 0; + if(this->commandsUp.numCommands > 0 && port != RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + // there are, assume the maximum possible FOpts len for buffer allocation + foptsLen = this->commandsUp.len; + foptsBufSize = 15; + } + + // check maximum payload len as defined in phy + if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + // if testing with TS009 specification verification protocol, don't throw error but clip the message + // len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]; + } + + bool adrAckReq = false; + if(this->adrEnabled) { + // check if we need to do ADR stuff + uint32_t adrLimit = 0x01 << this->adrLimitExp; + uint32_t adrDelay = 0x01 << this->adrDelayExp; + if((this->fcntUp - this->adrFcnt) >= adrLimit) { + adrAckReq = true; + } + // if we hit the Limit + Delay, try one of three, in order: + // set TxPower to max, set DR to min, enable all default channels + if ((this->fcntUp - this->adrFcnt) == (adrLimit + adrDelay)) { + uint8_t adrStage = 1; + while(adrStage != 0) { + switch(adrStage) { + case(1): { + // if the TxPower field has some offset, remove it and switch to maximum power + if(this->txPowerCur > 0) { + // set the maximum power supported by both the module and the band + state = this->setTxPower(this->txPowerMax); + if(state == RADIOLIB_ERR_NONE) { + this->txPowerCur = 0; + adrStage = 0; // successfully did some ADR stuff + } + } + if(adrStage == 1) { // if nothing succeeded, proceed to stage 2 + adrStage = 2; + } + } + break; + case(2): { + // try to decrease the datarate + if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > 0) { + if(this->setDatarate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] - 1) == RADIOLIB_ERR_NONE) { + adrStage = 0; // successfully did some ADR stuff + } + } + if(adrStage == 2) { // if nothing succeeded, proceed to stage 3 + adrStage = 3; + } + } + break; + case(3): { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + this->setupChannelsDyn(false); // revert to default frequencies + } else { + // go back to default selected subband + // hopefully it'll help something, but probably not; at least we tried.. + this->setupChannelsFix(this->subBand); + } + adrStage = 0; // nothing else to do, so end the cycle + } + break; + } + } + + // we tried something to improve the range, so increase the ADR frame counter by 'ADR delay' + this->adrFcnt += adrDelay; + } + } + + // configure for uplink + this->selectChannels(); + state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); + RADIOLIB_ASSERT(state); + + // if dwell time is imposed, calculated expected time on air and cancel if exceeds + if(this->dwellTimeEnabledUp && this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen) - 16)/1000 > this->dwellTimeUp) { + return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); + } + + // build the uplink message + // the first 16 bytes are reserved for MIC calculation blocks + size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsBufSize); + #if RADIOLIB_STATIC_ONLY + uint8_t uplinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* uplinkMsg = new uint8_t[uplinkMsgLen]; + #endif + + // set the packet fields + if(isConfirmed) { + uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_UP; + this->confFcntUp = this->fcntUp; + } else { + uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP; + } + uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] |= RADIOLIB_LORAWAN_MHDR_MAJOR_R1; + LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS], this->devAddr); + + // length of fopts will be added later + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00; + if(this->adrEnabled) { + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED; + if(adrAckReq) { + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ; + } + } + + // if the saved confirm-fcnt is set, set the ACK bit + bool isConfirmingDown = false; + if(this->confFcntDown != RADIOLIB_LORAWAN_FCNT_NONE) { + isConfirmingDown = true; + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ACK; + } + + LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS], (uint16_t)this->fcntUp); + + // check if we have some MAC commands to append + if(foptsLen > 0) { + // assume maximum possible buffer size + uint8_t foptsBuff[15]; + uint8_t* foptsPtr = foptsBuff; + + // append all MAC replies into fopts buffer + int16_t i = 0; + for (; i < this->commandsUp.numCommands; i++) { + LoRaWANMacCommand_t cmd = this->commandsUp.commands[i]; + memcpy(foptsPtr, &cmd, 1 + cmd.len); + foptsPtr += cmd.len + 1; + } + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(foptsBuff, foptsLen); + + // pop the commands from back to front + for (; i >= 0; i--) { + if(this->commandsUp.commands[i].repeat > 0) { + this->commandsUp.commands[i].repeat--; + } else { + deleteMacCommand(this->commandsUp.commands[i].cid, &this->commandsUp); + } + } + + uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen); + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= foptsLen; + + // encrypt it + processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fcntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true); + + } + + // set the port + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)] = port; + + // select encryption key based on the target port + uint8_t* encKey = this->appSKey; + if(port == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + encKey = this->nwkSEncKey; + } + + // encrypt the frame payload + processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(foptsLen)], this->fcntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x00, true); + + // create blocks for MIC calculation + uint8_t block0[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + block0[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; + block0[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; + LoRaWANNode::hton(&block0[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&block0[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], this->fcntUp); + block0[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = uplinkMsgLen - RADIOLIB_AES128_BLOCK_SIZE - sizeof(uint32_t); + + uint8_t block1[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + memcpy(block1, block0, RADIOLIB_AES128_BLOCK_SIZE); + if(this->confFcntDown != RADIOLIB_LORAWAN_FCNT_NONE) { + LoRaWANNode::hton(&block1[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntDown); + } + block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; + block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx; + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FcntUp = %d) decoded:", this->fcntUp); + + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(uplinkMsg, uplinkMsgLen); + + // calculate authentication codes + memcpy(uplinkMsg, block1, RADIOLIB_AES128_BLOCK_SIZE); + uint32_t micS = this->generateMIC(uplinkMsg, uplinkMsgLen - sizeof(uint32_t), this->sNwkSIntKey); + memcpy(uplinkMsg, block0, RADIOLIB_AES128_BLOCK_SIZE); + uint32_t micF = this->generateMIC(uplinkMsg, uplinkMsgLen - sizeof(uint32_t), this->fNwkSIntKey); + + // check LoRaWAN revision + if(this->rev == 1) { + uint32_t mic = ((uint32_t)(micF & 0x0000FF00) << 16) | ((uint32_t)(micF & 0x0000000FF) << 16) | ((uint32_t)(micS & 0x0000FF00) >> 0) | ((uint32_t)(micS & 0x0000000FF) >> 0); + LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], mic); + } else { + LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); + } + + // perform CSMA if enabled. + if (enableCSMA) { + performCSMA(); + } + + // send it (without the MIC calculation blocks) + state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS); + + // set the timestamp so that we can measure when to start receiving + this->rxDelayStart = mod->hal->millis(); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink sent <-- Rx Delay start"); + + // calculate Time on Air of this uplink in milliseconds + this->lastToA = this->phyLayer->getTimeOnAir(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS) / 1000; + + #if !RADIOLIB_STATIC_ONLY + delete[] uplinkMsg; + #endif + RADIOLIB_ASSERT(state); + + // the downlink confirmation was acknowledged, so clear the counter value + this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + + // pass the extra info if requested + if(event) { + event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; + event->confirmed = isConfirmed; + event->confirming = isConfirmingDown; + event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; + event->freq = currentChannels[event->dir].freq; + event->power = this->txPowerMax - this->txPowerCur * 2; + event->fcnt = this->fcntUp; + event->port = port; + } + + // increase frame counter by one for the next uplink + this->fcntUp += 1; + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::downlinkCommon() { + Module* mod = this->phyLayer->getMod(); + const uint32_t scanGuard = 10; + + // check if there are any upcoming Rx windows + // if the Rx1 window has already started, you're too late, because most downlinks happen in Rx1 + if(mod->hal->millis() - this->rxDelayStart > (this->rxDelays[0] - scanGuard)) { + // if between start of Rx1 and end of Rx2, wait until Rx2 closes + if(mod->hal->millis() - this->rxDelayStart < this->rxDelays[1]) { + mod->hal->delay(this->rxDelays[1] + this->rxDelayStart - mod->hal->millis()); + } + // update the end timestamp in case user got stuck between uplink and downlink + this->rxDelayEnd = mod->hal->millis(); + return(RADIOLIB_ERR_NO_RX_WINDOW); + } + + // configure for downlink + int16_t state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK); + RADIOLIB_ASSERT(state); + + // downlink messages are sent with inverted IQ + if(!this->FSK) { + state = this->phyLayer->invertIQ(true); + RADIOLIB_ASSERT(state); + } + + // create the masks that are required for receiving downlinks + uint16_t irqFlags = 0x0000; + uint16_t irqMask = 0x0000; + this->phyLayer->irqRxDoneRxTimeout(irqFlags, irqMask); + + this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlinkAction); + + // perform listening in the two Rx windows + for(uint8_t i = 0; i < 2; i++) { + downlinkAction = false; + + // calculate the Rx timeout + // according to the spec, this must be at least enough time to effectively detect a preamble + // but pad it a bit on both sides (start and end) to make sure it is wide enough + uint32_t timeoutHost = this->phyLayer->getTimeOnAir(0) + 2*scanGuard*1000; + uint32_t timeoutMod = this->phyLayer->calculateRxTimeout(timeoutHost); + + // wait for the start of the Rx window + // the waiting duration is shortened a bit to cover any possible timing errors + uint32_t waitLen = this->rxDelays[i] - (mod->hal->millis() - this->rxDelayStart); + if(waitLen > scanGuard) { + waitLen -= scanGuard; + } + mod->hal->delay(waitLen); + + // open Rx window by starting receive with specified timeout + state = this->phyLayer->startReceive(timeoutMod, irqFlags, irqMask, 0); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d us timeout)... <-- Rx Delay end ", i+1, timeoutHost); + + // wait for the timeout to complete (and a small additional delay) + mod->hal->delay(timeoutHost / 1000 + scanGuard / 2); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", i+1); + + // check if the IRQ bit for Rx Timeout is set + if(!this->phyLayer->isRxTimeout()) { + break; + + } else if(i == 0) { + // nothing in the first window, configure for the second + this->phyLayer->standby(); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %6.3f MHz", 'D', this->rx2.freq); + state = this->phyLayer->setFrequency(this->rx2.freq); + RADIOLIB_ASSERT(state); + + DataRate_t dataRate; + findDataRate(this->rx2.drMax, &dataRate); + state = this->phyLayer->setDataRate(dataRate); + RADIOLIB_ASSERT(state); + } + + } + // Rx windows are now closed + this->rxDelayEnd = mod->hal->millis(); + + // if we got here due to a timeout, stop ongoing activities + if(this->phyLayer->isRxTimeout()) { + this->phyLayer->standby(); // TODO check: this should be done automagically due to RxSingle? + if(!this->FSK) { + this->phyLayer->invertIQ(false); + } + + return(RADIOLIB_ERR_RX_TIMEOUT); + } + + // wait for the DIO to fire indicating a downlink is received + while(!downlinkAction) { + mod->hal->yield(); + } + + // we have a message, clear actions, go to standby and reset the IQ inversion + this->phyLayer->standby(); // TODO check: this should be done automagically due to RxSingle? + this->phyLayer->clearPacketReceivedAction(); + if(!this->FSK) { + state = this->phyLayer->invertIQ(false); + RADIOLIB_ASSERT(state); + } + + return(RADIOLIB_ERR_NONE); +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t LoRaWANNode::downlink(String& str, LoRaWANEvent_t* event) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // build a temporary buffer + // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL + size_t length = 0; + uint8_t data[251]; + + // wait for downlink + state = this->downlink(data, &length, event); + if(state == RADIOLIB_ERR_NONE) { + // add null terminator + data[length] = '\0'; + + // initialize Arduino String class + str = String((char*)data); + } + + return(state); +} +#endif + +int16_t LoRaWANNode::downlink(LoRaWANEvent_t* event) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // build a temporary buffer + // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL + size_t length = 0; + uint8_t data[251]; + + // wait for downlink + state = this->downlink(data, &length, event); + + return(state); +} + +int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) { + // handle Rx1 and Rx2 windows - returns RADIOLIB_ERR_NONE if a downlink is received + int16_t state = downlinkCommon(); + RADIOLIB_ASSERT(state); + + // get the packet length + size_t downlinkMsgLen = this->phyLayer->getPacketLength(); + + // check the minimum required frame length + // an extra byte is subtracted because downlink frames may not have a port + if(downlinkMsgLen < RADIOLIB_LORAWAN_FRAME_LEN(0, 0) - 1 - RADIOLIB_AES128_BLOCK_SIZE) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink message too short (%lu bytes)", downlinkMsgLen); + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); + } + + // build the buffer for the downlink message + // the first 16 bytes are reserved for MIC calculation block + #if !RADIOLIB_STATIC_ONLY + uint8_t* downlinkMsg = new uint8_t[RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen]; + #else + uint8_t downlinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + + // set the MIC calculation block + memset(downlinkMsg, 0x00, RADIOLIB_AES128_BLOCK_SIZE); + downlinkMsg[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); + downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; + downlinkMsg[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = downlinkMsgLen - sizeof(uint32_t); + + // read the data + state = this->phyLayer->readData(&downlinkMsg[RADIOLIB_AES128_BLOCK_SIZE], downlinkMsgLen); + // downlink frames are sent without CRC, which will raise error on SX127x + // we can ignore that error + if(state == RADIOLIB_ERR_LORA_HEADER_DAMAGED) { + state = RADIOLIB_ERR_NONE; + } + + if(state != RADIOLIB_ERR_NONE) { + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(state); + } + + // get the frame counter and set it to the MIC calculation block + uint16_t fcnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt16); + + // if this downlink is confirming an uplink, its MIC was generated with the least-significant 16 bits of that fcntUp + bool isConfirmingUp = false; + if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FCTRL_ACK) && (this->rev == 1)) { + isConfirmingUp = true; + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntUp); + } + + // calculate length of FOpts and payload + uint8_t foptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; + int payLen = downlinkMsgLen - 8 - foptsLen - sizeof(uint32_t); + + // in LoRaWAN v1.1, a frame can be a network frame if there is no Application payload + // i.e., no payload at all (empty frame or FOpts only), or MAC only payload (FPort = 0) + // TODO "NFCntDown is used for MAC communication on port 0 and when the FPort field is missing" + // so what about empty frames for ACK? Per TS008, these should be Application downlinks + bool isAppDownlink = true; + if(payLen <= 0) { + if(this->rev == 1) { + isAppDownlink = false; + } + } + else if(downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)] == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + foptsLen = payLen - 1; + if(this->rev == 1) { + isAppDownlink = false; + } + } + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFcntDown = %d) encoded:", isAppDownlink ? "A" : "N", fcnt16); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); + + // check the FcntDown value (Network or Application) + uint32_t fcntDownPrev = 0; + if (isAppDownlink) { + fcntDownPrev = this->aFcntDown; + } else { + fcntDownPrev = this->nFcntDown; + } + + // if this is not the first downlink... + // assume a 16-bit to 32-bit rollover if difference between counters in LSB is smaller than MAX_FCNT_GAP + // if that isn't the case and the received fcnt is smaller or equal to the last heard fcnt, then error + uint32_t fcnt32 = fcnt16; + if(fcntDownPrev > 0) { + if((fcnt16 <= fcntDownPrev) && ((0xFFFF - (uint16_t)fcntDownPrev + fcnt16) > RADIOLIB_LORAWAN_MAX_FCNT_GAP)) { + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + if (isAppDownlink) { + return(RADIOLIB_ERR_A_FCNT_DOWN_INVALID); + } else { + return(RADIOLIB_ERR_N_FCNT_DOWN_INVALID); + } + } else if (fcnt16 <= fcntDownPrev) { + uint16_t msb = (fcntDownPrev >> 16) + 1; // assume a rollover + fcnt32 |= ((uint32_t)msb << 16); // add back the MSB part + } + } + + // check the MIC + if(!verifyMIC(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen, this->sNwkSIntKey)) { + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_CRC_MISMATCH); + } + + // save current fcnt to respective frame counter + if (isAppDownlink) { + this->aFcntDown = fcnt32; + } else { + this->nFcntDown = fcnt32; + } + + // if this is a confirmed frame, save the downlink number (only app frames can be confirmed) + bool isConfirmedDown = false; + if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] & 0xFE) == RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_DOWN) { + this->confFcntDown = this->aFcntDown; + isConfirmedDown = true; + } + + // check the address + uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]); + if(addr != this->devAddr) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Device address mismatch, expected 0x%08X, got 0x%08X", this->devAddr, addr); + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); + } + + // process FOpts (if there are any) + if(foptsLen > 0) { + // there are some Fopts, decrypt them + #if !RADIOLIB_STATIC_ONLY + uint8_t* fopts = new uint8_t[RADIOLIB_MAX(RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK, (int)foptsLen)]; + #else + uint8_t fopts[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + + // TODO it COULD be the case that the assumed FCnt rollover is incorrect, if possible figure out a way to catch this and retry with just fcnt16 + // if there are <= 15 bytes of FOpts, they are in the FHDR, otherwise they are in the payload + // in case of the latter, process AES is if it were a normal payload but using the NwkSEncKey + if(foptsLen <= RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK) { + uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, ctrId, true); + } else { + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); + } + + bool hasADR = false; + uint8_t numADR = 0; + uint8_t lastCID = 0; + + // process the MAC command(s) + int8_t remLen = foptsLen; + uint8_t* foptsPtr = fopts; + while(remLen > 0) { + uint8_t cid = *foptsPtr; + uint8_t macLen = getMacPayloadLength(cid); + if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) { + // if there was an earlier ADR command but it was not the last, ignore it + if(hasADR && lastCID != RADIOLIB_LORAWAN_MAC_LINK_ADR) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Encountered non-consecutive block of ADR commands - skipping"); + remLen -= (macLen + 1); + foptsPtr += (macLen + 1); + lastCID = cid; + continue; + } + // otherwise, set ADR flag to true and increase counter + hasADR = true; + numADR++; + } + if(macLen + 1 > remLen) + break; + LoRaWANMacCommand_t cmd = { + .cid = cid, + .payload = { 0 }, + .len = macLen, + .repeat = (cid == RADIOLIB_LORAWAN_MAC_LINK_ADR ? numADR : (uint8_t)0), + }; + memcpy(cmd.payload, foptsPtr + 1, macLen); + + // process the MAC command + bool sendUp = execMacCommand(&cmd); + if(sendUp) { + pushMacCommand(&cmd, &this->commandsUp); + } + + // processing succeeded, move in the buffer to the next command + remLen -= (macLen + 1); + foptsPtr += (macLen + 1); + lastCID = cid; + } + + #if !RADIOLIB_STATIC_ONLY + delete[] fopts; + #endif + + // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink + if(this->commandsUp.len > 15) { + size_t foptsBufSize = this->commandsUp.len; + #if RADIOLIB_STATIC_ONLY + uint8_t foptsBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* foptsBuff = new uint8_t[foptsBufSize]; + #endif + uint8_t* foptsPtr = foptsBuff; + // append all MAC replies into fopts buffer + int16_t i = 0; + for (; i < this->commandsUp.numCommands; i++) { + LoRaWANMacCommand_t cmd = this->commandsUp.commands[i]; + memcpy(foptsPtr, &cmd, 1 + cmd.len); + foptsPtr += cmd.len + 1; + } + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(foptsBuff, foptsBufSize); + + // pop the commands from back to front + for (; i >= 0; i--) { + if(this->commandsUp.commands[i].repeat > 0) { + this->commandsUp.commands[i].repeat--; + } else { + deleteMacCommand(this->commandsUp.commands[i].cid, &this->commandsUp); + } + } + + this->isMACPayload = true; + // temporarily lift dutyCycle restrictions to allow immediate MAC response + bool prevDC = this->dutyCycleEnabled; + this->dutyCycleEnabled = false; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Sending MAC-only uplink .. "); + state = this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(" .. state: %d", state); + this->dutyCycleEnabled = prevDC; + + #if !RADIOLIB_STATIC_ONLY + delete[] foptsBuff; + #endif + + #if RADIOLIB_STATIC_ONLY + uint8_t strDown[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* strDown = new uint8_t[this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; + #endif + size_t lenDown = 0; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Receiving after MAC-only uplink .. "); + state = this->downlink(strDown, &lenDown); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(" .. state: %d", state); + #if !RADIOLIB_STATIC_ONLY + delete[] strDown; + #endif + RADIOLIB_ASSERT(state); + } + + } + + // a downlink was received, so reset the ADR counter to the last uplink's fcnt + this->adrFcnt = this->fcntUp - 1; + + // pass the extra info if requested + if(event) { + event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; + event->confirmed = isConfirmedDown; + event->confirming = isConfirmingUp; + event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]; + event->freq = currentChannels[event->dir].freq; + event->power = this->txPowerMax - this->txPowerCur * 2; + event->fcnt = isAppDownlink ? this->aFcntDown : this->nFcntDown; + event->port = isAppDownlink ? downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)] : RADIOLIB_LORAWAN_FPORT_MAC_COMMAND; + } + + // process Application payload (if there is any) + if(payLen <= 0 || foptsLen > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { + // no payload + *len = 0; + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + + return(RADIOLIB_ERR_NONE); + } + + *len = payLen - 1; + + // TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fcnt16 + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(foptsLen)], payLen - 1, this->appSKey, data, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); + + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + + return(RADIOLIB_ERR_NONE); +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { + // send the uplink + int16_t state = this->uplink(strUp, port, isConfirmed, eventUp); + RADIOLIB_ASSERT(state); + + // wait for the downlink + state = this->downlink(strDown, eventDown); + return(state); +} +#endif + +int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { + // send the uplink + int16_t state = this->uplink(dataUp, lenUp, port, isConfirmed, eventUp); + RADIOLIB_ASSERT(state); + + // wait for the downlink + state = this->downlink(eventDown); + return(state); +} + +int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { + // send the uplink + int16_t state = this->uplink(strUp, port, isConfirmed, eventUp); + RADIOLIB_ASSERT(state); + + // wait for the downlink + state = this->downlink(dataDown, lenDown, eventDown); + return(state); +} + +int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { + // send the uplink + int16_t state = this->uplink(dataUp, lenUp, port, isConfirmed, eventUp); + RADIOLIB_ASSERT(state); + + // wait for the downlink + state = this->downlink(dataDown, lenDown, eventDown); + return(state); +} + +void LoRaWANNode::setDeviceStatus(uint8_t battLevel) { + this->battLevel = battLevel; +} + +// return Fcnt of last uplink; also return 0 if no uplink occured yet +uint32_t LoRaWANNode::getFcntUp() { + if(this->fcntUp == 0) { + return(0); + } + return(this->fcntUp - 1); +} + +uint32_t LoRaWANNode::getNFcntDown() { + return(this->nFcntDown); +} + +uint32_t LoRaWANNode::getAFcntDown() { + return(this->aFcntDown); +} + +void LoRaWANNode::resetFcntDown() { + this->nFcntDown = 0; + this->aFcntDown = 0; +} + +uint32_t LoRaWANNode::generateMIC(uint8_t* msg, size_t len, uint8_t* key) { + if((msg == NULL) || (len == 0)) { + return(0); + } + + RadioLibAES128Instance.init(key); + uint8_t cmac[RADIOLIB_AES128_BLOCK_SIZE]; + RadioLibAES128Instance.generateCMAC(msg, len, cmac); + return(((uint32_t)cmac[0]) | ((uint32_t)cmac[1] << 8) | ((uint32_t)cmac[2] << 16) | ((uint32_t)cmac[3]) << 24); +} + +bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { + if((msg == NULL) || (len < sizeof(uint32_t))) { + return(0); + } + + // extract MIC from the message + uint32_t micReceived = LoRaWANNode::ntoh(&msg[len - sizeof(uint32_t)]); + + // calculate the expected value and compare + uint32_t micCalculated = generateMIC(msg, len - sizeof(uint32_t), key); + if(micCalculated != micReceived) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("MIC mismatch, expected %08x, got %08x", micCalculated, micReceived); + return(false); + } + + return(true); +} + +int16_t LoRaWANNode::setPhyProperties() { + // set the physical layer configuration + int8_t pwr = this->txPowerMax - this->txPowerCur * 2; + int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; + while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + // go from the highest power and lower it until we hit one supported by the module + state = this->phyLayer->setOutputPower(pwr--); + } + RADIOLIB_ASSERT(state); + + uint8_t syncWord[3] = { 0 }; + uint8_t syncWordLen = 0; + size_t preLen = 0; + if(this->FSK) { + preLen = 8*RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN; + syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 16); + syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 8); + syncWord[2] = (uint8_t)RADIOLIB_LORAWAN_GFSK_SYNC_WORD; + syncWordLen = 3; + + } else { + preLen = RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN; + syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; + syncWordLen = 1; + + } + + state = this->phyLayer->setSyncWord(syncWord, syncWordLen); + RADIOLIB_ASSERT(state); + + state = this->phyLayer->setPreambleLength(preLen); + return(state); +} + +int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up dynamic channels"); + + size_t num = 0; + // copy the default defined channels into the first slots (where Tx = Rx) + for(; num < 3 && this->band->txFreqs[num].enabled; num++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; + } + + // if we're about to send a join-request, copy the join-request channels to the next slots + if(joinRequest) { + size_t numJR = 0; + for(; numJR < 3 && this->band->txJoinReq[num].enabled; numJR++, num++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; + } + } + + // clear all remaining channels + for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; + } + + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } + } + + return(RADIOLIB_ERR_NONE); +} + +// setup a subband and its corresponding join-request datarate +// WARNING: subBand starts at 1 (corresponds to all populair schemes) +int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up fixed channels (subband %d)", subBand); + + // clear all existing channels + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; + } + + // if no subband is selected by user, cycle through banks of 8 using devNonce value + if(subBand == 0) { + uint8_t numBanks8 = this->band->txSpans[0].numChannels / 8; + subBand = this->devNonce % numBanks8; + } + + uint8_t chMaskCntl = 0; + uint16_t chMask = 0; + + // if there are two channel spans, first set the channel from second span + if(this->band->numTxSpans == 2) { + chMaskCntl = 7; + chMask = (1 << (subBand - 1)); // set channel mask + this->applyChannelMaskFix(chMaskCntl, chMask); + } + + // chMask is set for 16 channels at once, so widen the Cntl value + chMaskCntl = (subBand - 1) / 2; // compensate the 1 offset + + // now select the correct bank of 8 channels + if(subBand % 2 == 0) { // even subbands + chMask = 0xFF00; + } else { + chMask = 0x00FF; // odd subbands + } + this->applyChannelMaskFix(chMaskCntl, chMask); + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::processCFList(uint8_t* cfList) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Processing CFList"); + + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + // retrieve number of existing (default) channels + size_t num = 0; + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(!this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + break; + } + num++; + } + + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, + .payload = { 0 }, + .len = 0, + .repeat = 0, + }; + // datarate range for all new channels is equal to the default channels + cmd.payload[4] = (this->band->txFreqs[0].drMax << 4) | this->band->txFreqs[0].drMin; + for(uint8_t i = 0; i < 5; i++, num++) { + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; + cmd.payload[0] = num; + memcpy(&cmd.payload[1], &cfList[i*3], 3); + (void)execMacCommand(&cmd); + } + } else { // RADIOLIB_LORAWAN_BAND_FIXED + // complete channel mask received, so clear all existing channels + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; + } + + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .payload = { 0 }, + .len = 0, + .repeat = 0, + }; + + // in case of mask-type bands, copy those frequencies that are masked true into the available TX channels + size_t numChMasks = 3 + this->band->numTxSpans; // 4 masks for bands with 2 spans, 5 spans for bands with 1 span + for(size_t chMaskCntl = 0; chMaskCntl < numChMasks; chMaskCntl++) { + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + cmd.payload[0] = 0xFF; // same datarate and payload + memcpy(&cmd.payload[1], &cfList[chMaskCntl*2], 2); // copy mask + cmd.payload[3] = chMaskCntl << 4; // set chMaskCntl, set NbTrans = 0 -> keep the same + cmd.repeat = (chMaskCntl + 1); + (void)execMacCommand(&cmd); + } + } + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::selectChannels() { + // figure out which channel IDs are enabled (chMask may have disabled some) and are valid for the current datarate + uint8_t numChannels = 0; + uint8_t channelsEnabled[RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; + for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] >= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin + && this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] <= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax) { + channelsEnabled[numChannels] = i; + numChannels++; + } + } + } + if(numChannels == 0) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("There are no channels defined - are you in ABP mode with no defined subband?"); + return(RADIOLIB_ERR_INVALID_CHANNEL); + } + // select a random ID & channel from the list of enabled and possible channels + uint8_t channelID = channelsEnabled[this->phyLayer->random(numChannels)]; + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][channelID]; + + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + // for dynamic bands, the downlink channel is the one matched to the uplink channel + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][channelID]; + + } else { // RADIOLIB_LORAWAN_BAND_FIXED + // for fixed bands, the downlink channel is the uplink channel ID `modulo` number of downlink channels + LoRaWANChannel_t channelDn; + channelDn.enabled = true; + channelDn.idx = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx % this->band->rx1Span.numChannels; + channelDn.freq = this->band->rx1Span.freqStart + channelDn.idx*this->band->rx1Span.freqStep; + channelDn.drMin = this->band->rx1Span.drMin; + channelDn.drMax = this->band->rx1Span.drMax; + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = channelDn; + + } + uint8_t drDown = getDownlinkDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], this->rx1DrOffset, this->band->rx1DataRateBase, + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax); + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::setDatarate(uint8_t drUp) { + // scan through all enabled channels and check if the requested datarate is available + bool isValidDR = false; + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + LoRaWANChannel_t *chnl = &(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]); + if(chnl->enabled) { + if(drUp >= chnl->drMin && drUp <= chnl->drMax) { + isValidDR = true; + break; + } + } + } + if(!isValidDR) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("No defined channel allows datarate %d", drUp); + return(RADIOLIB_ERR_INVALID_DATA_RATE); + } + + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .payload = { 0 }, + .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .repeat = 0, + }; + cmd.payload[0] = (drUp << 4); + cmd.payload[0] |= 0x0F; // keep Tx Power the same + cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored + cmd.payload[3] |= 0; // keep NbTrans the same + (void)execMacCommand(&cmd); + + // check if ACK is set for Tx Power + if((cmd.payload[0] >> 1) != 1) { + return(RADIOLIB_ERR_INVALID_DATA_RATE); + } + + return(RADIOLIB_ERR_NONE); +} + +void LoRaWANNode::setADR(bool enable) { + this->adrEnabled = enable; +} + +void LoRaWANNode::setDutyCycle(bool enable, uint32_t msPerHour) { + this->dutyCycleEnabled = enable; + if(msPerHour <= 0) { + this->dutyCycle = this->band->dutyCycle; + } else { + this->dutyCycle = msPerHour; + } +} + +// given an airtime in milliseconds, calculate the minimum uplink interval +// to adhere to a given dutyCycle +uint32_t LoRaWANNode::dutyCycleInterval(uint32_t msPerHour, uint32_t airtime) { + if(msPerHour == 0 || airtime == 0) { + return(0); + } + uint32_t oneHourInMs = (uint32_t)60 * (uint32_t)60 * (uint32_t)1000; + float numPackets = msPerHour / airtime; + uint32_t delayMs = oneHourInMs / numPackets + 1; // + 1 to prevent rounding problems + return(delayMs); +} + +uint32_t LoRaWANNode::timeUntilUplink() { + Module* mod = this->phyLayer->getMod(); + uint32_t nextUplink = this->rxDelayStart + dutyCycleInterval(this->dutyCycle, this->lastToA); + if(mod->hal->millis() > nextUplink){ + return(0); + } + return(nextUplink - mod->hal->millis() + 1); +} + +void LoRaWANNode::setDwellTime(bool enable, uint32_t msPerUplink) { + this->dwellTimeEnabledUp = enable; + if(msPerUplink <= 0) { + this->dwellTimeUp = this->band->dwellTimeUp; + } else { + this->dwellTimeUp = msPerUplink; + } +} + +uint8_t LoRaWANNode::maxPayloadDwellTime() { + // configure current datarate + DataRate_t dr; + findDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], &dr); + (void)this->phyLayer->setDataRate(dr); + uint8_t minPayLen = 0; + uint8_t maxPayLen = 255; + uint8_t payLen = (minPayLen + maxPayLen) / 2; + // do some binary search to find maximum allowed payload length + while(payLen != minPayLen && payLen != maxPayLen) { + if(this->phyLayer->getTimeOnAir(payLen) > this->dwellTimeUp) { + maxPayLen = payLen; + } else { + minPayLen = payLen; + } + payLen = (minPayLen + maxPayLen) / 2; + } + return(payLen - 13); // fixed 13-byte header +} + +int16_t LoRaWANNode::setTxPower(int8_t txPower) { + // only allow values within the band's (or MAC state) maximum + if(txPower > this->txPowerMax) { + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + // Tx Power is set in steps of two + // the selected value is rounded down to nearest multiple of two away from txPowerMax + // e.g. on EU868, max is 16; if 13 is selected then we set to 12 + uint8_t numSteps = (this->txPowerMax - txPower + 1) / (-RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM); + + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .payload = { 0 }, + .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .repeat = 0, + }; + cmd.payload[0] = 0xF0; // keep datarate the same + cmd.payload[0] |= numSteps; // set the Tx Power + cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored + cmd.payload[3] |= 0; // keep NbTrans the same + (void)execMacCommand(&cmd); + + // check if ACK is set for Tx Power + if((cmd.payload[0] >> 2) != 1) { + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { + uint8_t dataRateBand = this->band->dataRates[dr]; + + if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { + dataRate->fsk.bitRate = 50; + dataRate->fsk.freqDev = 25; + + } else { + uint8_t bw = dataRateBand & 0x0C; + switch(bw) { + case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): + dataRate->lora.bandwidth = 125.0; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): + dataRate->lora.bandwidth = 250.0; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): + dataRate->lora.bandwidth = 500.0; + break; + default: + dataRate->lora.bandwidth = 125.0; + } + + dataRate->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; + dataRate->lora.codingRate = (dataRateBand & 0x03) + 5; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: SF = %d, BW = %6.3f kHz, CR = 4/%d", + dataRate->lora.spreadingFactor, dataRate->lora.bandwidth, dataRate->lora.codingRate); + } + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::configureChannel(uint8_t dir) { + // set the frequency + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(""); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %6.3f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq); + int state = this->phyLayer->setFrequency(this->currentChannels[dir].freq); + RADIOLIB_ASSERT(state); + + // if this channel is an FSK channel, toggle the FSK switch + if(this->band->dataRates[this->dataRates[dir]] == RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { + this->FSK = true; + } else { + this->FSK = false; + } + + DataRate_t dr; + findDataRate(this->dataRates[dir], &dr); + state = this->phyLayer->setDataRate(dr); + RADIOLIB_ASSERT(state); + + if(this->FSK) { + state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); + RADIOLIB_ASSERT(state); + state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); + } + + return(state); +} + +bool LoRaWANNode::sendMacCommandReq(uint8_t cid) { + bool valid = false; + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) { + if(MacTable[i].cid == cid) { + valid = MacTable[i].user; + } + } + if(!valid) + return(false); + + LoRaWANMacCommand_t cmd = { + .cid = cid, + .payload = { 0 }, + .len = 0, + .repeat = 0, + }; + pushMacCommand(&cmd, &this->commandsUp); + return(true); +} + +int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue) { + if(queue->numCommands >= RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE) { + return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); + } + + memcpy(&queue->commands[queue->numCommands], cmd, sizeof(LoRaWANMacCommand_t)); + queue->numCommands++; + queue->len += 1 + cmd->len; // 1 byte for command ID, len bytes for payload + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t* payload) { + for(size_t index = 0; index < queue->numCommands; index++) { + if(queue->commands[index].cid == cid) { + // if a pointer to a payload is supplied, copy the command's payload over + if(payload) { + memcpy(payload, queue->commands[index].payload, queue->commands[index].len); + } + queue->len -= (1 + queue->commands[index].len); // 1 byte for command ID, len for payload + // move all subsequent commands one forward in the queue + if(index < RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1) { + memmove(&queue->commands[index], &queue->commands[index + 1], (RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - index - 1) * sizeof(LoRaWANMacCommand_t)); + } + // set the latest element to all 0 + memset(&queue->commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1], 0x00, sizeof(LoRaWANMacCommand_t)); + queue->numCommands--; + return(RADIOLIB_ERR_NONE); + } + } + + return(RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND); +} + +bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[MAC] 0x%02X", cmd->cid); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(cmd->payload, cmd->len); + + if(cmd->cid >= RADIOLIB_LORAWAN_MAC_PROPRIETARY) { + // TODO call user-provided callback for proprietary MAC commands? + return(false); + } + + switch(cmd->cid) { + case(RADIOLIB_LORAWAN_MAC_RESET): { + // get the server version + uint8_t srvVersion = cmd->payload[0]; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ResetConf: server version 1.%d", srvVersion); + if(srvVersion == this->rev) { + // valid server version, stop sending the ResetInd MAC command + deleteMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->commandsUp); + } + return(false); + } break; + + case(RADIOLIB_LORAWAN_MAC_LINK_CHECK): { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkCheckAns: [user]"); + // delete any existing response (does nothing if there is none) + deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_CHECK, &this->commandsDown); + + // insert response into MAC downlink queue + pushMacCommand(cmd, &this->commandsDown); + return(false); + } break; + + case(RADIOLIB_LORAWAN_MAC_LINK_ADR): { + int16_t state = RADIOLIB_ERR_UNKNOWN; + // get the ADR configuration + // per spec, all these configuration should only be set if all ACKs are set, otherwise retain previous state + // but we don't bother and try to set each individual command + uint8_t drUp = (cmd->payload[0] & 0xF0) >> 4; + uint8_t txPower = cmd->payload[0] & 0x0F; + bool isInternalTxDr = cmd->payload[3] >> 7; + + uint16_t chMask = LoRaWANNode::ntoh(&cmd->payload[1]); + uint8_t chMaskCntl = (cmd->payload[3] & 0x70) >> 4; + uint8_t nbTrans = cmd->payload[3] & 0x0F; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRReq: dataRate = %d, txPower = %d, chMask = 0x%04x, chMaskCntl = %d, nbTrans = %d", drUp, txPower, chMask, chMaskCntl, nbTrans); + + // apply the configuration + uint8_t drAck = 0; + if(drUp == 0x0F) { // keep the same + drAck = 1; + + // replace the 'placeholder' with the current actual value for saving + cmd->payload[0] = (cmd->payload[0] & 0x0F) | (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); + + } else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + // check if the module supports this data rate + DataRate_t dr; + findDataRate(drUp, &dr); + state = this->phyLayer->checkDataRate(dr); + if(state == RADIOLIB_ERR_NONE) { + uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax); + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp; + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; + drAck = 1; + } else { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure dataRate %d, code %d!", drUp, state); + } + + } + + // try to apply the power configuration + uint8_t pwrAck = 0; + if(txPower == 0x0F) { + pwrAck = 1; + + // replace the 'placeholder' with the current actual value for saving + cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerCur; + + } else { + int8_t pwr = this->txPowerMax - 2*txPower; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: TX = %d dBm", pwr); + state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; + while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + // go from the highest power and lower it until we hit one supported by the module + state = this->phyLayer->setOutputPower(pwr--); + } + // only acknowledge if the requested datarate was succesfully configured + if(state == RADIOLIB_ERR_NONE) { + pwrAck = 1; + this->txPowerCur = txPower; + } + } + + + uint8_t chMaskAck = 1; + // only apply channel mask when the RFU bit is not set + // (which is only set in internal MAC commands for changing Tx/Dr) + if(!isInternalTxDr) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + chMaskAck = (uint8_t)this->applyChannelMaskDyn(chMaskCntl, chMask); + + } else { // RADIOLIB_LORAWAN_BAND_FIXED + if(cmd->repeat == 1) { + // if this is the first ADR command in the queue, clear all saved channels + // so we can apply the new channel mask + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR mask: clearing channels"); + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; + } + // clear all previous channel masks + memset(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS], 0, 16*8); + } else { + // if this is not the first ADR command, clear the ADR response that was in the queue + (void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); + } + chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask); + + } + } + + if(nbTrans == 0) { // keep the same + cmd->payload[3] = (cmd->payload[3] & 0xF0) | this->nbTrans; // set current number of retransmissions for saving + } else { + this->nbTrans = nbTrans; + } + + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + // if RFU bit is set, this is just a change in Datarate or TxPower, so read ADR command and overwrite first byte + if(isInternalTxDr) { + memcpy(&(cmd->payload[1]), &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 1, 3); + } + + // if there was no channel mask (all zeroes), we should never apply that channel mask, so set RFU bit again + if(cmd->payload[1] == 0 && cmd->payload[2] == 0) { + cmd->payload[3] |= (1 << 7); + } + + // save to the single ADR MAC location + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], &(cmd->payload[0]), cmd->len); + + } else { // RADIOLIB_LORAWAN_BAND_FIXED + + // save Tx/Dr to the Link ADR position in the session buffer + uint8_t bufTxDr[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; + bufTxDr[0] = cmd->payload[0]; + bufTxDr[3] = 1 << 7; + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], bufTxDr, cmd->len); + + // if RFU bit is set, this is just a change in Datarate or TxPower, in which case we don't save the channel masks + // if the RFU bit is not set, we must save this channel mask + if(!isInternalTxDr) { + // save the channel mask to the uplink channels position in session buffer, with Tx and DR set to 'same' + cmd->payload[0] = 0xFF; + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->payload, cmd->len); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Saving mask to ULChannels[%d]:", (cmd->repeat - 1) * cmd->len); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->len); + } + + } + + // send the reply + cmd->len = 1; + cmd->payload[0] = (pwrAck << 2) | (drAck << 1) | (chMaskAck << 0); + cmd->repeat = 0; // discard any repeat value that may have been set + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRAns: status = 0x%02x", cmd->payload[0]); + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_DUTY_CYCLE): { + uint8_t maxDutyCycle = cmd->payload[0] & 0x0F; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DutyCycleReq: max duty cycle = 1/2^%d", maxDutyCycle); + if(maxDutyCycle == 0) { + this->dutyCycle = this->band->dutyCycle; + } else { + this->dutyCycle = (uint32_t)60 * (uint32_t)60 * (uint32_t)1000 / (uint32_t)(1UL << maxDutyCycle); + } + + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], cmd->payload, cmd->len); + + cmd->len = 0; + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP): { + // get the configuration + this->rx1DrOffset = (cmd->payload[0] & 0x70) >> 4; + uint8_t rx1OffsAck = 1; + this->rx2.drMax = cmd->payload[0] & 0x0F; + uint8_t rx2Ack = 1; + uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); + this->rx2.freq = (float)freqRaw/10000.0; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXParamSetupReq: rx1DrOffset = %d, rx2DataRate = %d, freq = %f", this->rx1DrOffset, this->rx2.drMax, this->rx2.freq); + + // apply the configuration + uint8_t chanAck = 0; + if(this->phyLayer->setFrequency(this->rx2.freq) == RADIOLIB_ERR_NONE) { + chanAck = 1; + this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); + } + + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], cmd->payload, cmd->len); + + // TODO this should be sent repeatedly until the next downlink + cmd->len = 1; + cmd->payload[0] = (rx1OffsAck << 2) | (rx2Ack << 1) | (chanAck << 0); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXParamSetupAns: status = 0x%02x", cmd->payload[0]); + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_DEV_STATUS): { + // set the uplink reply + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatusReq"); + cmd->len = 2; + cmd->payload[1] = this->battLevel; + int8_t snr = this->phyLayer->getSNR(); + cmd->payload[0] = snr & 0x3F; + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatusAns: status = 0x%02x%02x", cmd->payload[0], cmd->payload[1]); + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_NEW_CHANNEL): { + // get the configuration + uint8_t chIndex = cmd->payload[0]; + uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); + float freq = (float)freqRaw/10000.0; + uint8_t maxDr = (cmd->payload[4] & 0xF0) >> 4; + uint8_t minDr = cmd->payload[4] & 0x0F; + + uint8_t newChAck = 0; + uint8_t freqAck = 0; + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled = true; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx = chIndex; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq = freq; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMin = minDr; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMax = maxDr; + + // downlink channel is identical to uplink channel + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex]; + newChAck = 1; + + // check if the frequency is possible + if(this->phyLayer->setFrequency(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq) == RADIOLIB_ERR_NONE) { + freqAck = 1; + this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); + } + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("NewChannelReq:"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].drMax + ); + + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); + + // send the reply + cmd->len = 1; + cmd->payload[0] = (newChAck << 1) | (freqAck << 0); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("NewChannelAns: status = 0x%02x", cmd->payload[0]); + + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_DL_CHANNEL): { + // get the configuration + uint8_t chIndex = cmd->payload[0]; + uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); + float freq = (float)freqRaw/10000.0; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelReq: index = %d, freq = %f MHz", chIndex, freq); + uint8_t freqDlAck = 0; + uint8_t freqUlAck = 0; + + // check if the frequency is possible + if(this->phyLayer->setFrequency(freq) == RADIOLIB_ERR_NONE) { + freqDlAck = 1; + this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); + } + + // update the downlink frequency + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx == chIndex) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq = freq; + // check if the corresponding uplink frequency is actually set + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq > 0) { + freqUlAck = 1; + } + } + } + + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); + + // TODO send this repeatedly until a downlink is received + cmd->len = 1; + cmd->payload[0] = (freqUlAck << 1) | (freqDlAck << 0); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelAns: status = 0x%02x", cmd->payload[0]); + + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP): { + // get the configuration + uint8_t delay = cmd->payload[0] & 0x0F; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXTimingSetupReq: delay = %d sec", delay); + + // apply the configuration + if(delay == 0) { + delay = 1; + } + this->rxDelays[0] = delay * 1000; + this->rxDelays[1] = this->rxDelays[0] + 1000; + + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], cmd->payload, cmd->len); + + // send the reply + cmd->len = 0; + + // TODO send this repeatedly until a downlink is received + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP): { + uint8_t dlDwell = (cmd->payload[0] & 0x20) >> 5; + uint8_t ulDwell = (cmd->payload[0] & 0x10) >> 4; + uint8_t maxEirpRaw = cmd->payload[0] & 0x0F; + + // who the f came up with this ... + const uint8_t eirpEncoding[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 }; + this->txPowerMax = eirpEncoding[maxEirpRaw]; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("TxParamSetupReq: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, eirpEncoding[maxEirpRaw]); + + this->dwellTimeEnabledUp = ulDwell ? true : false; + this->dwellTimeUp = ulDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; + + this->dwellTimeEnabledDn = dlDwell ? true : false; + this->dwellTimeDn = dlDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; + + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], cmd->payload, cmd->len); + + cmd->len = 0; + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_REKEY): { + // get the server version + uint8_t srvVersion = cmd->payload[0]; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RekeyConf: server version = 1.%d", srvVersion); + if((srvVersion > 0) && (srvVersion <= this->rev)) { + // valid server version, stop sending the ReKey MAC command + deleteMacCommand(RADIOLIB_LORAWAN_MAC_REKEY, &this->commandsUp); + } + return(false); + } break; + + case(RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP): { + this->adrLimitExp = (cmd->payload[0] & 0xF0) >> 4; + this->adrDelayExp = cmd->payload[0] & 0x0F; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADRParamSetupReq: limitExp = %d, delayExp = %d", this->adrLimitExp, this->adrDelayExp); + + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP], cmd->payload, cmd->len); + + cmd->len = 0; + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_DEVICE_TIME): { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DeviceTimeAns: [user]"); + // delete any existing response (does nothing if there is none) + deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown); + + // insert response into MAC downlink queue + pushMacCommand(cmd, &this->commandsDown); + return(false); + } break; + + case(RADIOLIB_LORAWAN_MAC_FORCE_REJOIN): { + // TODO implement this + uint16_t rejoinReq = LoRaWANNode::ntoh(cmd->payload); + uint8_t period = (rejoinReq & 0x3800) >> 11; + uint8_t maxRetries = (rejoinReq & 0x0700) >> 8; + uint8_t rejoinType = (rejoinReq & 0x0070) >> 4; + uint8_t dr = rejoinReq & 0x000F; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ForceRejoinReq: period = %d, maxRetries = %d, rejoinType = %d, dr = %d", period, maxRetries, rejoinType, dr); + (void)period; + (void)maxRetries; + (void)rejoinType; + (void)dr; + return(false); + } break; + + case(RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP): { + // TODO implement this + uint8_t maxTime = (cmd->payload[0] & 0xF0) >> 4; + uint8_t maxCount = cmd->payload[0] & 0x0F; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RejoinParamSetupReq: maxTime = %d, maxCount = %d", maxTime, maxCount); + + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP], cmd->payload, cmd->len); + + cmd->len = 0; + cmd->payload[0] = (1 << 1) | 1; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RejoinParamSetupAns: status = 0x%02x", cmd->payload[0]); + + (void)maxTime; + (void)maxCount; + return(true); + } break; + } + + return(false); +} + +bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(chMaskCntl == 0) { + // apply the mask by looking at each channel bit + if(chMask & (1UL << i)) { + // if it should be enabled but is not currently defined, stop immediately + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + return(false); + } + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + } else { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = false; + } + + } else if(chMaskCntl == 6) { + // enable all defined channels + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + } + } + + } + + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } + } + + return(true); +} + +bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, chMask); + + // find out how many channels have already been configured + uint8_t idx = 0; + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq > 0) { + idx++; + } + } + + if((this->band->numTxSpans == 1 && chMaskCntl <= 5) || (this->band->numTxSpans == 2 && chMaskCntl <= 3)) { + // select channels from first span + LoRaWANChannel_t chnl; + for(uint8_t i = 0; i < 16; i++) { + uint16_t mask = 1 << i; + if(mask & chMask) { + uint8_t chNum = chMaskCntl * 16 + i; // 0 through 63 or 95 + this->subBand = chNum / 8 + 1; // save configured subband in case we must reset the channels (1-based) + chnl.enabled = true; + chnl.idx = chNum; + chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep; + chnl.drMin = this->band->txSpans[0].drMin; + chnl.drMax = this->band->txSpans[0].drMax; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + } + } + + } + if(this->band->numTxSpans == 1 && chMaskCntl == 6) { + // all channels on (but we revert to user-selected subband) + this->setupChannelsFix(this->subBand); + + } + if(this->band->numTxSpans == 2 && chMaskCntl == 4) { + // select channels from second span + LoRaWANChannel_t chnl; + for(uint8_t i = 0; i < 8; i++) { + uint16_t mask = 1 << i; + if(mask & chMask) { + uint8_t chNum = chMaskCntl * 16 + i; // 64 through 71 + chnl.enabled = true; + chnl.idx = chNum; + chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; + chnl.drMin = this->band->txSpans[1].drMin; + chnl.drMax = this->band->txSpans[1].drMax; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + } + } + + } + if(this->band->numTxSpans == 2 && chMaskCntl == 5) { + // a '1' enables a bank of 8 + 1 channels from 1st and 2nd span respectively + LoRaWANChannel_t chnl; + for(uint8_t i = 0; i < 8; i++) { + uint16_t mask = 1 << i; + if(mask & chMask) { + // enable bank of 8 channels from first span + for(uint8_t j = 0; j < 8; j++) { + uint8_t chNum = i * 8 + j; + chnl.enabled = true; + chnl.idx = chNum; + chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep; + chnl.drMin = this->band->txSpans[0].drMin; + chnl.drMax = this->band->txSpans[0].drMax; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + } + // enable single channel from second span + uint8_t chNum = 64 + i; + chnl.enabled = true; + chnl.idx = chNum; + chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; + chnl.drMin = this->band->txSpans[1].drMin; + chnl.drMax = this->band->txSpans[1].drMax; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + } + } + + } + if(this->band->numTxSpans == 2 && chMaskCntl == 6) { + // all channels on (but we revert to selected subband) + this->setupChannelsFix(this->subBand); + + // a '1' enables a single channel from second span + LoRaWANChannel_t chnl; + for(uint8_t i = 0; i < 8; i++) { + uint16_t mask = 1 << i; + if(mask & chMask) { + // enable single channel from second span + uint8_t chNum = 64 + i; + chnl.enabled = true; + chnl.idx = chNum; + chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; + chnl.drMin = this->band->txSpans[1].drMin; + chnl.drMax = this->band->txSpans[1].drMax; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + } + } + + } + if(this->band->numTxSpans == 2 && chMaskCntl == 7) { + // all channels off (clear all channels) + LoRaWANChannel_t chnl = RADIOLIB_LORAWAN_CHANNEL_NONE; + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = chnl; + // downlink channels are not defined so don't need to reset + } + idx = 0; + // a '1' enables a single channel from second span + for(uint8_t i = 0; i < 8; i++) { + uint16_t mask = 1 << i; + if(mask & chMask) { + // enable single channel from second span + uint8_t chNum = 64 + i; + chnl.enabled = true; + chnl.idx = chNum; + chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; + chnl.drMin = this->band->txSpans[1].drMin; + chnl.drMax = this->band->txSpans[1].drMax; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + } + } + + } + + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } + } + + return(true); +} + +uint8_t LoRaWANNode::getMacPayloadLength(uint8_t cid) { + for (LoRaWANMacSpec_t entry : MacTable) { + if (entry.cid == cid) { + return entry.lenDn; + } + } + // no idea about the length + return 0; +} + +int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { + uint8_t payload[5]; + int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_LINK_CHECK_REQ, &this->commandsDown, payload); + RADIOLIB_ASSERT(state); + + if(margin) { *margin = payload[0]; } + if(gwCnt) { *gwCnt = payload[1]; } + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix) { + uint8_t payload[5]; + int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown, payload); + RADIOLIB_ASSERT(state); + + if(gpsEpoch) { + *gpsEpoch = LoRaWANNode::ntoh(&payload[0]); + if(returnUnix) { + uint32_t unixOffset = 315964800 - 18; // 18 leap seconds since GPS epoch (Jan. 6th 1980) + *gpsEpoch += unixOffset; + } + } + if(fraction) { *fraction = payload[4]; } + + return(RADIOLIB_ERR_NONE); +} + +uint64_t LoRaWANNode::getDevAddr() { + return(this->devAddr); +} + +// The following function enables LMAC, a CSMA scheme for LoRa as specified +// in the LoRa Alliance Technical Recommendation #13. +// A user may enable CSMA to provide frames an additional layer of protection from interference. +// https://resources.lora-alliance.org/technical-recommendations/tr013-1-0-0-csma +void LoRaWANNode::performCSMA() { + + // Compute initial random back-off. + // When BO is reduced to zero, the function returns and the frame is transmitted. + uint32_t BO = this->phyLayer->random(1, this->backoffMax + 1); + while (BO > 0) { + // DIFS: Check channel for DIFS_slots + bool channelFreeDuringDIFS = true; + for (uint8_t i = 0; i < this->difsSlots; i++) { + if (performCAD()) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Occupied channel during DIFS"); + channelFreeDuringDIFS = false; + // Channel is occupied during DIFS, hop to another. + this->selectChannels(); + break; + } + } + // Start reducing BO counter if DIFS slot was free. + if (channelFreeDuringDIFS) { + // Continue decrementing BO with per each CAD reporting free channel. + while (BO > 0) { + if (performCAD()) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Occupied channel during BO"); + // Channel is busy during CAD, hop to another and return to DIFS state again. + this->selectChannels(); + break; // Exit loop. Go back to DIFS state. + } + BO--; // Decrement BO by one if channel is free + } + } + } +} +bool LoRaWANNode::performCAD() { + int16_t state = this->phyLayer->scanChannel(); + if ((state == RADIOLIB_PREAMBLE_DETECTED) || (state == RADIOLIB_LORA_DETECTED)) { + return true; // Channel is busy + } + return false; // Channel is free +} + +void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter) { + // figure out how many encryption blocks are there + size_t numBlocks = len/RADIOLIB_AES128_BLOCK_SIZE; + if(len % RADIOLIB_AES128_BLOCK_SIZE) { + numBlocks++; + } + + // generate the encryption blocks + uint8_t encBuffer[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + uint8_t encBlock[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + encBlock[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_ENC_BLOCK_MAGIC; + encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_ID_POS] = ctrId; + encBlock[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = dir; + LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt); + + // now encrypt the input + // on downlink frames, this has a decryption effect because server actually "decrypts" the plaintext + size_t remLen = len; + for(size_t i = 0; i < numBlocks; i++) { + + if(counter) { + encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS] = i + 1; + } + + // encrypt the buffer + RadioLibAES128Instance.init(key); + RadioLibAES128Instance.encryptECB(encBlock, RADIOLIB_AES128_BLOCK_SIZE, encBuffer); + + // now xor the buffer with the input + size_t xorLen = remLen; + if(xorLen > RADIOLIB_AES128_BLOCK_SIZE) { + xorLen = RADIOLIB_AES128_BLOCK_SIZE; + } + for(uint8_t j = 0; j < xorLen; j++) { + out[i*RADIOLIB_AES128_BLOCK_SIZE + j] = in[i*RADIOLIB_AES128_BLOCK_SIZE + j] ^ encBuffer[j]; + } + remLen -= xorLen; + } +} + +uint16_t LoRaWANNode::checkSum16(uint8_t *key, uint16_t keyLen) { + uint16_t checkSum = 0; + for(uint16_t i = 0; i < keyLen; i += 2) { + checkSum ^= ((uint16_t)key[i] << 8) | key[i + 1]; + } + if(keyLen % 2 == 1) { + uint16_t val = ((uint16_t)key[keyLen - 1] << 8); + checkSum ^= val; + } + return(checkSum); +} + +template +T LoRaWANNode::ntoh(uint8_t* buff, size_t size) { + uint8_t* buffPtr = buff; + size_t targetSize = sizeof(T); + if(size != 0) { + targetSize = size; + } + T res = 0; + for(size_t i = 0; i < targetSize; i++) { + res |= (uint32_t)(*(buffPtr++)) << 8*i; + } + return(res); +} + +template +void LoRaWANNode::hton(uint8_t* buff, T val, size_t size) { + uint8_t* buffPtr = buff; + size_t targetSize = sizeof(T); + if(size != 0) { + targetSize = size; + } + for(size_t i = 0; i < targetSize; i++) { + *(buffPtr++) = val >> 8*i; + } +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.h b/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.h new file mode 100644 index 000000000..0aab1fa7a --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWAN.h @@ -0,0 +1,997 @@ +#if !defined(_RADIOLIB_LORAWAN_H) && !RADIOLIB_EXCLUDE_LORAWAN +#define _RADIOLIB_LORAWAN_H + +#include "../../TypeDef.h" +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../../utils/Cryptography.h" + +// activation mode +#define RADIOLIB_LORAWAN_MODE_OTAA (0x07AA) +#define RADIOLIB_LORAWAN_MODE_ABP (0x0AB9) +#define RADIOLIB_LORAWAN_MODE_NONE (0x0000) + +// operation mode +#define RADIOLIB_LORAWAN_CLASS_A (0x0A) +#define RADIOLIB_LORAWAN_CLASS_B (0x0B) +#define RADIOLIB_LORAWAN_CLASS_C (0x0C) + +// preamble format +#define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34) +#define RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN (8) +#define RADIOLIB_LORAWAN_GFSK_SYNC_WORD (0xC194C1) +#define RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN (5) + +// MAC header field encoding MSB LSB DESCRIPTION +#define RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST (0x00 << 5) // 7 5 message type: join request +#define RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT (0x01 << 5) // 7 5 join accept +#define RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP (0x02 << 5) // 7 5 unconfirmed data up +#define RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_DOWN (0x03 << 5) // 7 5 unconfirmed data down +#define RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_UP (0x04 << 5) // 7 5 confirmed data up +#define RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_DOWN (0x05 << 5) // 7 5 confirmed data down +#define RADIOLIB_LORAWAN_MHDR_MTYPE_PROPRIETARY (0x07 << 5) // 7 5 proprietary +#define RADIOLIB_LORAWAN_MHDR_MTYPE_MASK (0x07 << 5) // 7 5 bitmask of all possible options +#define RADIOLIB_LORAWAN_MHDR_MAJOR_R1 (0x00 << 0) // 1 0 major version: LoRaWAN R1 + +// frame control field encoding +#define RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED (0x01 << 7) // 7 7 adaptive data rate: enabled +#define RADIOLIB_LORAWAN_FCTRL_ADR_DISABLED (0x00 << 7) // 7 7 disabled +#define RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ (0x01 << 6) // 6 6 adaptive data rate ACK request +#define RADIOLIB_LORAWAN_FCTRL_ACK (0x01 << 5) // 5 5 confirmed message acknowledge +#define RADIOLIB_LORAWAN_FCTRL_FRAME_PENDING (0x01 << 4) // 4 4 downlink frame is pending + +// port field +#define RADIOLIB_LORAWAN_FPORT_MAC_COMMAND (0x00 << 0) // 7 0 payload contains MAC commands only +#define RADIOLIB_LORAWAN_FPORT_RESERVED (0xE0 << 0) // 7 0 reserved port values + +// MAC commands - only those sent from end-device to gateway +#define RADIOLIB_LORAWAN_LINK_CHECK_REQ (0x02 << 0) // 7 0 MAC command: request to check connectivity to network +#define RADIOLIB_LORAWAN_LINK_ADR_ANS (0x03 << 0) // 7 0 answer to ADR change +#define RADIOLIB_LORAWAN_DUTY_CYCLE_ANS (0x04 << 0) // 7 0 answer to duty cycle change +#define RADIOLIB_LORAWAN_RX_PARAM_SETUP_ANS (0x05 << 0) // 7 0 answer to reception slot setup request +#define RADIOLIB_LORAWAN_DEV_STATUS_ANS (0x06 << 0) // 7 0 device status information +#define RADIOLIB_LORAWAN_NEW_CHANNEL_ANS (0x07 << 0) // 7 0 acknowledges change of a radio channel +#define RADIOLIB_LORAWAN_RX_TIMING_SETUP_ANS (0x08 << 0) // 7 0 acknowledges change of a reception slots timing + +#define RADIOLIB_LORAWAN_NOPTS_LEN (8) + +// data rate encoding +#define RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K (0x01 << 7) // 7 7 FSK @ 50 kbps +#define RADIOLIB_LORAWAN_DATA_RATE_SF_12 (0x06 << 4) // 6 4 LoRa spreading factor: SF12 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_11 (0x05 << 4) // 6 4 SF11 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_10 (0x04 << 4) // 6 4 SF10 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_9 (0x03 << 4) // 6 4 SF9 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_8 (0x02 << 4) // 6 4 SF8 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_7 (0x01 << 4) // 6 4 SF7 +#define RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ (0x00 << 2) // 3 2 LoRa bandwidth: 500 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ (0x01 << 2) // 3 2 250 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ (0x02 << 2) // 3 2 125 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_RESERVED (0x03 << 2) // 3 2 reserved value +#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_5 (0x00 << 0) // 1 0 LoRa coding rate: 4/5 +#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_6 (0x01 << 0) // 1 0 4/6 +#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_7 (0x02 << 0) // 1 0 4/7 +#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_8 (0x03 << 0) // 1 0 4/8 +#define RADIOLIB_LORAWAN_DATA_RATE_UNUSED (0xFF << 0) // 7 0 unused data rate + +#define RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK (0x00 << 0) +#define RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK (0x01 << 0) +#define RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH (0x02 << 0) +#define RADIOLIB_LORAWAN_CHANNEL_DIR_NONE (0x03 << 0) +#define RADIOLIB_LORAWAN_BAND_DYNAMIC (0) +#define RADIOLIB_LORAWAN_BAND_FIXED (1) +#define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (15) +#define RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE (0xFF >> 0) + +// recommended default settings +#define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000) +#define RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS ((RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS) + 1000) +#define RADIOLIB_LORAWAN_RX1_DR_OFFSET (0) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS (5000) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS (6000) +#define RADIOLIB_LORAWAN_MAX_FCNT_GAP (16384) +#define RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP (0x06) +#define RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP (0x05) +#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS (1000) +#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS (3000) +#define RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM (-2) +#define RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N (10) // send rejoin request 16384 uplinks +#define RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N (15) // once every year, not actually implemented + +// join request message layout +#define RADIOLIB_LORAWAN_JOIN_REQUEST_LEN (23) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS (1) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS (9) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS (17) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE (0xFF) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE_0 (0x00) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE_1 (0x01) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE_2 (0x02) + +// join accept message layout +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN (33) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS (1) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS (4) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS (7) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS (4) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS (11) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS (12) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS (12) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS (13) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN (16) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_TYPE_POS (RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS + RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN - 1) + +// join accept message variables +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_0 (0x00 << 7) // 7 7 LoRaWAN revision: 1.0 +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1 (0x01 << 7) // 7 7 1.1 +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY (0x01) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY (0x02) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_S_NWK_S_INT_KEY (0x03) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_NWK_S_ENC_KEY (0x04) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_ENC_KEY (0x05) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_INT_KEY (0x06) + +// frame header layout +#define RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS (16) +#define RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 1) +#define RADIOLIB_LORAWAN_FHDR_FCTRL_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 5) +#define RADIOLIB_LORAWAN_FHDR_FCNT_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 6) +#define RADIOLIB_LORAWAN_FHDR_FOPTS_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 8) +#define RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK (0x0F) +#define RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 16) +#define RADIOLIB_LORAWAN_FHDR_FPORT_POS(FOPTS) (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 8 + (FOPTS)) +#define RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(FOPTS) (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 9 + (FOPTS)) +#define RADIOLIB_LORAWAN_FRAME_LEN(PAYLOAD, FOPTS) (16 + 13 + (PAYLOAD) + (FOPTS)) + +// payload encryption/MIC blocks common layout +#define RADIOLIB_LORAWAN_BLOCK_MAGIC_POS (0) +#define RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS (1) +#define RADIOLIB_LORAWAN_BLOCK_DIR_POS (5) +#define RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS (6) +#define RADIOLIB_LORAWAN_BLOCK_FCNT_POS (10) + +// payload encryption block layout +#define RADIOLIB_LORAWAN_ENC_BLOCK_MAGIC (0x01) +#define RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_ID_POS (4) +#define RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS (15) + +// payload MIC blocks layout +#define RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC (0x49) +#define RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS (15) +#define RADIOLIB_LORAWAN_MIC_DATA_RATE_POS (3) +#define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4) + +// MAC commands +#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16) + +#define RADIOLIB_LORAWAN_MAC_RESET (0x01) +#define RADIOLIB_LORAWAN_MAC_LINK_CHECK (0x02) +#define RADIOLIB_LORAWAN_MAC_LINK_ADR (0x03) +#define RADIOLIB_LORAWAN_MAC_DUTY_CYCLE (0x04) +#define RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP (0x05) +#define RADIOLIB_LORAWAN_MAC_DEV_STATUS (0x06) +#define RADIOLIB_LORAWAN_MAC_NEW_CHANNEL (0x07) +#define RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP (0x08) +#define RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP (0x09) +#define RADIOLIB_LORAWAN_MAC_DL_CHANNEL (0x0A) +#define RADIOLIB_LORAWAN_MAC_REKEY (0x0B) +#define RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP (0x0C) +#define RADIOLIB_LORAWAN_MAC_DEVICE_TIME (0x0D) +#define RADIOLIB_LORAWAN_MAC_FORCE_REJOIN (0x0E) +#define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F) +#define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80) + +// maximum allowed dwell time on bands that implement dwell time limitations +#define RADIOLIB_LORAWAN_DWELL_TIME (400) + +// unused LoRaWAN version +#define RADIOLIB_LORAWAN_VERSION_NONE (0xFF) + +// unused frame counter value +#define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF) + +// the length of internal MAC command queue - hopefully this is enough for most use cases +#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (9) + +// the maximum number of simultaneously available channels +#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16) + +// maximum MAC command sizes +#define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN (5) +#define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_UP (2) +#define RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS (8) + +struct LoRaWANMacSpec_t { + const uint8_t cid; + const uint8_t lenDn; + const uint8_t lenUp; + const bool user; // whether this MAC command can be issued by a user or not +}; + +const LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = { + { 0x00, 0, 0, false }, // not an actual MAC command, exists for index offsetting + { RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false }, + { RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, true }, + { RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false }, + { RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, false }, + { RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false }, + { RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false }, + { RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, false }, + { RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false }, + { RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, true }, + { RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false }, + { RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false }, + { RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true } +}; + +#define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0001) + +enum LoRaWANSchemeBase_t { + RADIOLIB_LORAWAN_NONCES_VERSION = 0x00, // 2 bytes + RADIOLIB_LORAWAN_NONCES_MODE = 0x02, // 2 bytes + RADIOLIB_LORAWAN_NONCES_CLASS = 0x04, // 1 byte + RADIOLIB_LORAWAN_NONCES_PLAN = 0x05, // 1 byte + RADIOLIB_LORAWAN_NONCES_CHECKSUM = 0x06, // 2 bytes + RADIOLIB_LORAWAN_NONCES_DEV_NONCE = 0x08, // 2 bytes + RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = 0x0A, // 3 bytes + RADIOLIB_LORAWAN_NONCES_ACTIVE = 0x0D, // 1 byte + RADIOLIB_LORAWAN_NONCES_SIGNATURE = 0x0E, // 2 bytes + RADIOLIB_LORAWAN_NONCES_BUF_SIZE = 0x10 // = 16 bytes +}; + +enum LoRaWANSchemeSession_t { + RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = 0x00, // 16 bytes + RADIOLIB_LORAWAN_SESSION_APP_SKEY = 0x10, // 16 bytes + RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = 0x20, // 16 bytes + RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = 0x30, // 16 bytes + RADIOLIB_LORAWAN_SESSION_DEV_ADDR = 0x40, // 4 bytes + RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = 0x44, // 2 bytes + RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = 0x46, // 4 bytes + RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = 0x4A, // 4 bytes + RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN = 0x4E, // 4 bytes + RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 = 0x52, // 2 bytes + RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = 0x54, // 2 bytes + RADIOLIB_LORAWAN_SESSION_HOMENET_ID = 0x56, // 4 bytes + RADIOLIB_LORAWAN_SESSION_VERSION = 0x5A, // 1 byte + RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = 0x5B, // 1 byte + RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = 0x5C, // 4 bytes + RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = 0x60, // 1 byte + RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = 0x61, // 1 byte + RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = 0x62, // 1 byte + RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = 0x63, // 1 byte + RADIOLIB_LORAWAN_SESSION_BEACON_FREQ = 0x64, // 3 bytes + RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL = 0x67, // 4 bytes + RADIOLIB_LORAWAN_SESSION_PERIODICITY = 0x6B, // 1 byte + RADIOLIB_LORAWAN_SESSION_LAST_TIME = 0x6C, // 4 bytes + RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = 0x70, // 16*8 bytes + RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = 0xF0, // 16*4 bytes + RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL = 0x0130, // 9*8+2 bytes + RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = 0x017A, // 4 bytes + RADIOLIB_LORAWAN_SESSION_ADR_FCNT = 0x017E, // 4 bytes + RADIOLIB_LORAWAN_SESSION_LINK_ADR = 0x0182, // 4 bytes + RADIOLIB_LORAWAN_SESSION_FCNT_UP = 0x0186, // 4 bytes + RADIOLIB_LORAWAN_SESSION_SIGNATURE = 0x018A, // 2 bytes + RADIOLIB_LORAWAN_SESSION_BUF_SIZE = 0x018C // 396 bytes +}; + +/*! + \struct LoRaWANChannelSpan_t + \brief Structure to save information about LoRaWAN channels. + To save space, adjacent channels are saved in "spans". +*/ +struct LoRaWANChannel_t { + /*! \brief Whether this channel is enabled (can be used) or is disabled */ + bool enabled; + + /*! \brief The channel number, as specified by defaults or the network */ + uint8_t idx; + + /*! \brief The channel frequency */ + float freq; + + /*! \brief Minimum allowed datarate for this channel */ + uint8_t drMin; + + /*! \brief Maximum allowed datarate for this channel (inclusive) */ + uint8_t drMax; +}; + +// alias for unused channel +#define RADIOLIB_LORAWAN_CHANNEL_NONE { .enabled = false, .idx = RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE, .freq = 0, .drMin = 0, .drMax = 0 } + +/*! + \struct LoRaWANChannelSpan_t + \brief Structure to save information about LoRaWAN channels. + To save space, adjacent channels are saved in "spans". +*/ +struct LoRaWANChannelSpan_t { + /*! \brief Total number of channels in the span */ + uint8_t numChannels; + + /*! \brief Center frequency of the first channel in span */ + float freqStart; + + /*! \brief Frequency step between adjacent channels */ + float freqStep; + + /*! \brief Minimum allowed datarate for all channels in this span */ + uint8_t drMin; + + /*! \brief Maximum allowed datarate for all channels in this span (inclusive) */ + uint8_t drMax; + + /*! \brief Allowed data rates for a join request message */ + uint8_t joinRequestDataRate; +}; + +// alias for unused channel span +#define RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE { .numChannels = 0, .freqStart = 0, .freqStep = 0, .drMin = 0, .drMax = 0, .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED } + +/*! + \struct LoRaWANBand_t + \brief Structure to save information about LoRaWAN band +*/ +struct LoRaWANBand_t { + /*! \brief Identier for this band */ + uint8_t bandNum; + + /*! \brief Whether the channels are fixed per specification, or dynamically allocated through the network (plus defaults) */ + uint8_t bandType; + + /*! \brief Array of allowed maximum payload lengths for each data rate */ + uint8_t payloadLenMax[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; + + /*! \brief Maximum allowed output power in this band in dBm */ + int8_t powerMax; + + /*! \brief Number of power steps in this band */ + int8_t powerNumSteps; + + /*! \brief Number of milliseconds per hour of allowed Time-on-Air */ + uint32_t dutyCycle; + + /*! \brief Maximum dwell time per message in milliseconds */ + uint32_t dwellTimeUp; + uint32_t dwellTimeDn; + + /*! \brief A set of default uplink (TX) channels for frequency-type bands */ + LoRaWANChannel_t txFreqs[3]; + + /*! \brief A set of possible extra channels for the Join-Request message for frequency-type bands */ + LoRaWANChannel_t txJoinReq[3]; + + /*! \brief The number of TX channel spans for mask-type bands */ + uint8_t numTxSpans; + + /*! \brief Default uplink (TX) channel spans for mask-type bands, including Join-Request parameters */ + LoRaWANChannelSpan_t txSpans[2]; + + /*! \brief Default downlink (RX1) channel span for mask-type bands */ + LoRaWANChannelSpan_t rx1Span; + + /*! \brief The base downlink data rate. Used to calculate data rate changes for adaptive data rate */ + uint8_t rx1DataRateBase; + + /*! \brief Backup channel for downlink (RX2) window */ + LoRaWANChannel_t rx2; + + /*! \brief The corresponding datarates, bandwidths and coding rates for DR index */ + uint8_t dataRates[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; +}; + +// supported bands +extern const LoRaWANBand_t EU868; +extern const LoRaWANBand_t US915; +extern const LoRaWANBand_t CN780; +extern const LoRaWANBand_t EU433; +extern const LoRaWANBand_t AU915; +extern const LoRaWANBand_t CN500; +extern const LoRaWANBand_t AS923; +extern const LoRaWANBand_t KR920; +extern const LoRaWANBand_t IN865; + +/*! + \struct LoRaWANMacCommand_t + \brief Structure to save information about MAC command +*/ +struct LoRaWANMacCommand_t { + /*! \brief The command ID */ + uint8_t cid; + + /*! \brief Payload buffer (5 bytes is the longest possible) */ + uint8_t payload[5]; + + /*! \brief Length of the payload */ + uint8_t len; + + /*! \brief Repetition counter (the command will be uplinked repeat + 1 times) */ + uint8_t repeat; +}; + +struct LoRaWANMacCommandQueue_t { + uint8_t numCommands; + uint8_t len; + LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE]; +}; + +/*! + \struct LoRaWANEvent_t + \brief Structure to save extra information about uplink/downlink event. +*/ +struct LoRaWANEvent_t { + /*! \brief Event direction, one of RADIOLIB_LORAWAN_CHANNEL_DIR_* */ + uint8_t dir; + + /*! \brief Whether the event is confirmed or not (e.g., confirmed uplink sent by user application) */ + bool confirmed; + + /*! \brief Whether the event is confirming a previous request + (e.g., server downlink reply to confirmed uplink sent by user application)*/ + bool confirming; + + /*! \brief Datarate */ + uint8_t datarate; + + /*! \brief Frequency in MHz */ + float freq; + + /*! \brief Transmit power in dBm for uplink, or RSSI for downlink */ + int16_t power; + + /*! \brief The appropriate frame counter - for different events, different frame counters will be reported! */ + uint32_t fcnt; + + /*! \brief Port number */ + uint8_t port; +}; + +/*! + \class LoRaWANNode + \brief LoRaWAN-compatible node (class A device). +*/ +class LoRaWANNode { + public: + + // Offset between TX and RX1 (such that RX1 has equal or lower DR) + uint8_t rx1DrOffset = 0; + + // RX2 channel properties - may be changed by MAC command + LoRaWANChannel_t rx2; + + /*! + \brief Default constructor. + \param phy Pointer to the PhysicalLayer radio module. + \param band Pointer to the LoRaWAN band to use. + \param subBand The sub-band to be used (starting from 1!) + */ + LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t subBand = 0); + + /*! + \brief Wipe internal persistent parameters. + This will reset all counters and saved variables, so the device will have to rejoin the network. + */ + void wipe(); + + /*! + \brief Returns the pointer to the internal buffer that holds the LW base parameters + \returns Pointer to uint8_t array of size RADIOLIB_LORAWAN_NONCES_BUF_SIZE + */ + uint8_t* getBufferNonces(); + + /*! + \brief Fill the internal buffer that holds the LW base parameters with a supplied buffer + \param persistentBuffer Buffer that should match the internal format (previously extracted using getBufferNonces) + \returns \ref status_codes + */ + int16_t setBufferNonces(uint8_t* persistentBuffer); + + /*! + \brief Returns the pointer to the internal buffer that holds the LW session parameters + \returns Pointer to uint8_t array of size RADIOLIB_LORAWAN_SESSION_BUF_SIZE + */ + uint8_t* getBufferSession(); + + /*! + \brief Fill the internal buffer that holds the LW session parameters with a supplied buffer + \param persistentBuffer Buffer that should match the internal format (previously extracted using getBufferSession) + \returns \ref status_codes + */ + int16_t setBufferSession(uint8_t* persistentBuffer); + + /*! + \brief Restore session by loading information from persistent storage. + \returns \ref status_codes + */ + int16_t restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass, uint8_t freqPlan); + + /*! + \brief Join network by performing over-the-air activation. By this procedure, + the device will perform an exchange with the network server and set all necessary configuration. + \param joinEUI 8-byte application identifier. + \param devEUI 8-byte device identifier. + \param nwkKey Pointer to the network AES-128 key. + \param appKey Pointer to the application AES-128 key. + \param force Set to true to force joining even if previously joined. + \param joinDr The datarate at which to send the join-request and any subsequent uplinks (unless ADR is enabled) + \returns \ref status_codes + */ + int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force = false, uint8_t joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); + + /*! + \brief Join network by performing activation by personalization. + In this procedure, all necessary configuration must be provided by the user. + \param addr Device address. + \param nwkSKey Pointer to the network session AES-128 key (LoRaWAN 1.0) or MAC command network session key (LoRaWAN 1.1). + \param appSKey Pointer to the application session AES-128 key. + \param fNwkSIntKey Pointer to the Forwarding network session (LoRaWAN 1.1), unused for LoRaWAN 1.0. + \param sNwkSIntKey Pointer to the Serving network session (LoRaWAN 1.1), unused for LoRaWAN 1.0. + \param force Set to true to force a new session, even if one exists. + \param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled) + \returns \ref status_codes + */ + int16_t beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL, bool force = false, uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); + + /*! \brief Whether there is an ongoing session active */ + bool isJoined(); + + /*! + \brief Save the current state of the session to the session buffer. + \returns \ref status_codes + */ + int16_t saveSession(); + + /*! + \brief Add a MAC command to the uplink queue. + Only LinkCheck and DeviceTime are available to the user. + Other commands are ignored; duplicate MAC commands are discarded. + \param cid ID of the MAC command + \returns Whether or not the MAC command was added to the queue. + */ + bool sendMacCommandReq(uint8_t cid); + + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Send a message to the server. + \param str Address of Arduino String that will be transmitted. + \param port Port number to send the message to. + \param isConfirmed Whether to send a confirmed uplink or not. + \param event Pointer to a structure to store extra information about the event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t uplink(String& str, uint8_t port, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); + #endif + + /*! + \brief Send a message to the server. + \param str C-string that will be transmitted. + \param port Port number to send the message to. + \param isConfirmed Whether to send a confirmed uplink or not. + \param event Pointer to a structure to store extra information about the event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t uplink(const char* str, uint8_t port, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); + + /*! + \brief Send a message to the server. + \param data Data to send. + \param len Length of the data. + \param port Port number to send the message to. + \param isConfirmed Whether to send a confirmed uplink or not. + \param event Pointer to a structure to store extra information about the event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); + + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Wait for downlink from the server in either RX1 or RX2 window. + \param str Address of Arduino String to save the received data. + \param event Pointer to a structure to store extra information about the event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t downlink(String& str, LoRaWANEvent_t* event = NULL); + #endif + + /*! + \brief Wait for downlink from the server in either RX1 or RX2 window. + \param data Buffer to save received data into. + \param len Pointer to variable that will be used to save the number of received bytes. + \param event Pointer to a structure to store extra information about the event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event = NULL); + + /*! + \brief Wait for downlink, simplified to allow for simpler sendReceive + \param event Pointer to a structure to store extra information about the event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t downlink(LoRaWANEvent_t* event = NULL); + + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. + \param strUp Address of Arduino String that will be transmitted. + \param port Port number to send the message to. + \param strDown Address of Arduino String to save the received data. + \param isConfirmed Whether to send a confirmed uplink or not. + \param eventUp Pointer to a structure to store extra information about the uplink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \param eventDown Pointer to a structure to store extra information about the downlink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + #endif + + /*! + \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. + \param strUp C-string that will be transmitted. + \param port Port number to send the message to. + \param dataDown Buffer to save received data into. + \param lenDown Pointer to variable that will be used to save the number of received bytes. + \param isConfirmed Whether to send a confirmed uplink or not. + \param eventUp Pointer to a structure to store extra information about the uplink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \param eventDown Pointer to a structure to store extra information about the downlink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + + /*! + \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. + \param dataUp Data to send. + \param lenUp Length of the data. + \param port Port number to send the message to. + \param dataDown Buffer to save received data into. + \param lenDown Pointer to variable that will be used to save the number of received bytes. + \param isConfirmed Whether to send a confirmed uplink or not. + \param eventUp Pointer to a structure to store extra information about the uplink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \param eventDown Pointer to a structure to store extra information about the downlink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + + /*! + \brief Send a message to the server and wait for a downlink but don't bother the user with downlink contents + \param dataUp Data to send. + \param lenUp Length of the data. + \param port Port number to send the message to. + \param isConfirmed Whether to send a confirmed uplink or not. + \param eventUp Pointer to a structure to store extra information about the uplink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \param eventDown Pointer to a structure to store extra information about the downlink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port = 1, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + + /*! + \brief Set device status. + \param battLevel Battery level to set. 0 for external power source, 1 for lowest battery, + 254 for highest battery, 255 for unable to measure. + */ + void setDeviceStatus(uint8_t battLevel); + + /*! + \brief Returns the last uplink's frame counter; + also 0 if no uplink occured yet. + */ + uint32_t getFcntUp(); + + /*! + \brief Returns the last network downlink's frame counter; + also 0 if no network downlink occured yet. + */ + uint32_t getNFcntDown(); + + /*! + \brief Returns the last application downlink's frame counter; + also 0 if no application downlink occured yet. + */ + uint32_t getAFcntDown(); + + /*! + \brief Reset the downlink frame counters (application and network) + This is unsafe and can possibly allow replay attacks using downlinks. + It mainly exists as part of the TS009 Specification Verification protocol. + */ + void resetFcntDown(); + + /*! + \brief Set uplink datarate. This should not be used when ADR is enabled. + \param dr Datarate to use for uplinks. + \returns \ref status_codes + */ + int16_t setDatarate(uint8_t drUp); + + /*! + \brief Toggle ADR to on or off. + \param enable Whether to disable ADR or not. + */ + void setADR(bool enable = true); + + /*! + \brief Toggle adherence to dutyCycle limits to on or off. + \param enable Whether to adhere to dutyCycle limits or not (default true). + \param msPerHour The maximum allowed Time-on-Air per hour in milliseconds + (default 0 = maximum allowed for configured band). + */ + void setDutyCycle(bool enable = true, uint32_t msPerHour = 0); + + /*! + \brief Calculate the minimum interval to adhere to a certain dutyCycle. + This interval is based on the ToA of one uplink and does not actually keep track of total airtime. + \param msPerHour The maximum allowed duty cycle (in milliseconds per hour). + \param airtime The airtime of the uplink. + \returns Required interval (delay) in milliseconds between consecutive uplinks. + */ + uint32_t dutyCycleInterval(uint32_t msPerHour, uint32_t airtime); + + /*! \brief Returns time in milliseconds until next uplink is available under dutyCycle limits */ + uint32_t timeUntilUplink(); + + /*! + \brief Toggle adherence to dwellTime limits to on or off. + \param enable Whether to adhere to dwellTime limits or not (default true). + \param msPerHour The maximum allowed Time-on-Air per uplink in milliseconds + (default 0 = maximum allowed for configured band). + */ + void setDwellTime(bool enable, uint32_t msPerUplink = 0); + + /*! + \brief Returns the maximum payload given the currently present dwell time limits. + WARNING: the addition of MAC commands may cause uplink errors; + if you want to be sure that your payload fits within dwell time limits, subtract 16 from the result! + */ + uint8_t maxPayloadDwellTime(); + + /*! + \brief Configure TX power of the radio module. + \param txPower Output power during TX mode to be set in dBm. + \returns \ref status_codes + */ + int16_t setTxPower(int8_t txPower); + + /*! + \brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance. + \param backoffMax Num of BO slots to be decremented after DIFS phase. 0 to disable BO. + \param difsSlots Num of CADs to estimate a clear CH. + \param enableCSMA enable/disable CSMA for LoRaWAN. + */ + void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false); + + /*! + \brief Returns the quality of connectivity after requesting a LinkCheck MAC command. + Returns 'true' if a network response was successfully parsed. + Returns 'false' if there was no network response / parsing failed. + \param margin Link margin in dB of LinkCheckReq demodulation at gateway side. + \param gwCnt Number of gateways that received the LinkCheckReq. + \returns \ref status_codes + */ + int16_t getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt); + + /*! + \brief Returns the network time after requesting a DeviceTime MAC command. + Returns 'true' if a network response was successfully parsed. + Returns 'false' if there was no network response / parsing failed. + \param gpsEpoch Number of seconds since GPS epoch (Jan. 6th 1980) + \param fraction Fractional-second, in 1/256-second steps + \param returnUnix If true, returns Unix timestamp instead of GPS (default true) + \returns \ref status_codes + */ + int16_t getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix = true); + + /*! + \brief Returns the DevAddr of the device, regardless of OTAA or ABP mode + \returns 8-byte DevAddr + */ + uint64_t getDevAddr(); + +#if !RADIOLIB_GODMODE + private: +#endif + PhysicalLayer* phyLayer = NULL; + const LoRaWANBand_t* band = NULL; + + static int16_t checkBufferCommon(uint8_t *buffer, uint16_t size); + + void beginCommon(uint8_t initialDr); + + // a buffer that holds all LW base parameters that should persist at all times! + uint8_t bufferNonces[RADIOLIB_LORAWAN_NONCES_BUF_SIZE] = { 0 }; + + // a buffer that holds all LW session parameters that preferably persist, but can be afforded to get lost + uint8_t bufferSession[RADIOLIB_LORAWAN_SESSION_BUF_SIZE] = { 0 }; + + LoRaWANMacCommandQueue_t commandsUp = { + .numCommands = 0, + .len = 0, + .commands = { { .cid = 0, .payload = { 0 }, .len = 0, .repeat = 0, } }, + }; + LoRaWANMacCommandQueue_t commandsDown = { + .numCommands = 0, + .len = 0, + .commands = { { .cid = 0, .payload = { 0 }, .len = 0, .repeat = 0, } }, + }; + + // the following is either provided by the network server (OTAA) + // or directly entered by the user (ABP) + uint32_t devAddr = 0; + uint8_t appSKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + uint8_t fNwkSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + uint8_t sNwkSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + uint8_t nwkSEncKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + uint8_t jSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + + // device-specific parameters, persistent through sessions + uint16_t devNonce = 0; + uint32_t joinNonce = 0; + + // session-specific parameters + uint32_t homeNetId = 0; + uint8_t adrLimitExp = RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP; + uint8_t adrDelayExp = RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP; + uint8_t nbTrans = 1; // Number of allowed frame retransmissions + uint8_t txPowerCur = 0; + uint8_t txPowerMax = 0; + uint32_t fcntUp = 0; + uint32_t aFcntDown = 0; + uint32_t nFcntDown = 0; + uint32_t confFcntUp = RADIOLIB_LORAWAN_FCNT_NONE; + uint32_t confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + uint32_t adrFcnt = 0; + + // whether the current configured channel is in FSK mode + bool FSK = false; + + // flag that shows whether the device is joined and there is an ongoing session (none, ABP or OTAA) + uint16_t activeMode = RADIOLIB_LORAWAN_MODE_NONE; + + // ADR is enabled by default + bool adrEnabled = true; + + // duty cycle is set upon initialization and activated in regions that impose this + bool dutyCycleEnabled = false; + uint32_t dutyCycle = 0; + + // dwell time is set upon initialization and activated in regions that impose this + bool dwellTimeEnabledUp = false; + uint16_t dwellTimeUp = 0; + bool dwellTimeEnabledDn = false; + uint16_t dwellTimeDn = 0; + + // enable/disable CSMA for LoRaWAN + bool enableCSMA; + + // number of backoff slots to be decremented after DIFS phase. 0 to disable BO. + // A random BO avoids collisions in the case where two or more nodes start the CSMA + // process at the same time. + uint8_t backoffMax; + + // number of CADs to estimate a clear CH + uint8_t difsSlots; + + // available channel frequencies from list passed during OTA activation + LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; + + // currently configured channels for TX and RX1 + LoRaWANChannel_t currentChannels[2] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE }; + + // currently configured datarates for TX and RX1 + uint8_t dataRates[2] = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED }; + + // LoRaWAN revision (1.0 vs 1.1) + uint8_t rev = 0; + + // Time on Air of last uplink + uint32_t lastToA = 0; + + // timestamp to measure the RX1/2 delay (from uplink end) + uint32_t rxDelayStart = 0; + + // timestamp when the Rx1/2 windows were closed (timeout or uplink received) + uint32_t rxDelayEnd = 0; + + // delays between the uplink and RX1/2 windows + uint32_t rxDelays[2] = { RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS }; + + // device status - battery level + uint8_t battLevel = 0xFF; + + // indicates whether an uplink has MAC commands as payload + bool isMACPayload = false; + + // save the selected sub-band in case this must be restored in ADR control + uint8_t subBand = 0; + + // wait for, open and listen during Rx1 and Rx2 windows; only performs listening + int16_t downlinkCommon(); + + // method to generate message integrity code + uint32_t generateMIC(uint8_t* msg, size_t len, uint8_t* key); + + // method to verify message integrity code + // it assumes that the MIC is the last 4 bytes of the message + bool verifyMIC(uint8_t* msg, size_t len, uint8_t* key); + + // configure the common physical layer properties (preamble, sync word etc.) + // channels must be configured separately by setupChannelsDyn()! + int16_t setPhyProperties(); + + // setup uplink/downlink channel data rates and frequencies + // for dynamic channels, there is a small set of predefined channels + // in case of JoinRequest, add some optional extra frequencies + int16_t setupChannelsDyn(bool joinRequest = false); + + // setup uplink/downlink channel data rates and frequencies + // for fixed bands, we only allow one sub-band at a time to be selected + int16_t setupChannelsFix(uint8_t subBand); + + // a join-accept can piggy-back a set of channels or channel masks + int16_t processCFList(uint8_t* cfList); + + // select a set of random TX/RX channels for up- and downlink + int16_t selectChannels(); + + // find the first usable data rate for the given band + int16_t findDataRate(uint8_t dr, DataRate_t* dataRate); + + // configure channel based on cached data rate ID and frequency + int16_t configureChannel(uint8_t dir); + + // restore all available channels from persistent storage + int16_t restoreChannels(); + + // push MAC command to queue, done by copy + int16_t pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue); + + // delete a specific MAC command from queue, indicated by the command ID + // if a payload pointer is supplied, this returns the payload of the MAC command + int16_t deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t* payload = NULL); + + // execute mac command, return the number of processed bytes for sequential processing + bool execMacCommand(LoRaWANMacCommand_t* cmd); + + // apply a channel mask to a set of readily defined channels (dynamic bands only) + bool applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask); + + // define or delete channels from a fixed set of channels (fixed bands only) + bool applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask); + + // get the payload length for a specific MAC command + uint8_t getMacPayloadLength(uint8_t cid); + + // Performs CSMA as per LoRa Alliance Technical Recommendation 13 (TR-013). + void performCSMA(); + + // perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise. + bool performCAD(); + + // function to encrypt and decrypt payloads + void processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter); + + // 16-bit checksum method that takes a uint8_t array of even length and calculates the checksum + static uint16_t checkSum16(uint8_t *key, uint16_t keyLen); + + // network-to-host conversion method - takes data from network packet and converts it to the host endians + template + static T ntoh(uint8_t* buff, size_t size = 0); + + // host-to-network conversion method - takes data from host variable and and converts it to network packet endians + template + static void hton(uint8_t* buff, T val, size_t size = 0); +}; + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWANBands.cpp b/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWANBands.cpp new file mode 100644 index 000000000..ad0b1b9ee --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -0,0 +1,488 @@ +#include "LoRaWAN.h" + +#if !RADIOLIB_EXCLUDE_LORAWAN + +enum LoRaWANBandNum_t { + BandNone, + BandEU868, + BandUS915, + BandCN780, + BandEU433, + BandAU915, + BandCN500, + BandAS923, + BandKR920, + BandIN865 +}; + +const LoRaWANBand_t EU868 = { + .bandNum = BandEU868, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 16, + .powerNumSteps = 7, + .dutyCycle = 36000, + .dwellTimeUp = 0, + .dwellTimeDn = 0, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 868.100, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 868.300, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 2, .freq = 868.500, .drMin = 0, .drMax = 5}, + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 0, + .txSpans = { + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + }, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 869.525, .drMin = 0, .drMax = 0 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } +}; + +const LoRaWANBand_t US915 = { + .bandNum = BandUS915, + .bandType = RADIOLIB_LORAWAN_BAND_FIXED, + .payloadLenMax = { 19, 61, 133, 250, 250, 0, 0, 0, 41, 117, 230, 230, 230, 230, 0 }, + .powerMax = 30, + .powerNumSteps = 10, + .dutyCycle = 0, + .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, + .dwellTimeDn = 0, + .txFreqs = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 2, + .txSpans = { + { + .numChannels = 64, + .freqStart = 902.300, + .freqStep = 0.200, + .drMin = 0, + .drMax = 3, + .joinRequestDataRate = 0 + }, + { + .numChannels = 8, + .freqStart = 903.000, + .freqStep = 1.600, + .drMin = 4, + .drMax = 4, + .joinRequestDataRate = 4 + } + }, + .rx1Span = { + .numChannels = 8, + .freqStart = 923.300, + .freqStep = 0.600, + .drMin = 8, + .drMax = 13, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + }, + .rx1DataRateBase = 10, + .rx2 = { .enabled = true, .idx = 0, .freq = 923.300, .drMin = 8, .drMax = 8 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } +}; + +const LoRaWANBand_t CN780 = { + .bandNum = BandCN780, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 250, 230, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 12, + .powerNumSteps = 5, + .dutyCycle = 3600, + .dwellTimeUp = 0, + .dwellTimeDn = 0, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 779.500, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 779.700, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 2, .freq = 779.900, .drMin = 0, .drMax = 5}, + }, + .txJoinReq = { + { .enabled = true, .idx = 3, .freq = 780.500, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 4, .freq = 780.700, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 5, .freq = 780.900, .drMin = 0, .drMax = 5} + }, + .numTxSpans = 0, + .txSpans = { + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + }, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 786.000, .drMin = 0, .drMax = 0 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } +}; + +const LoRaWANBand_t EU433 = { + .bandNum = BandEU433, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 12, + .powerNumSteps = 5, + .dutyCycle = 36000, + .dwellTimeUp = 0, + .dwellTimeDn = 0, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 433.175, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 433.375, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 2, .freq = 433.575, .drMin = 0, .drMax = 5}, + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 0, + .txSpans = { + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + }, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 434.665, .drMin = 0, .drMax = 0 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } +}; + +const LoRaWANBand_t AU915 = { + .bandNum = BandAU915, + .bandType = RADIOLIB_LORAWAN_BAND_FIXED, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 0, 41, 117, 230, 230, 230, 230, 0 }, + .powerMax = 30, + .powerNumSteps = 10, + .dutyCycle = 0, + .dwellTimeUp = 0, + .dwellTimeDn = 0, + .txFreqs = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 2, + .txSpans = { + { + .numChannels = 64, + .freqStart = 915.200, + .freqStep = 0.200, + .drMin = 0, + .drMax = 5, + .joinRequestDataRate = 0 + }, + { + .numChannels = 8, + .freqStart = 915.900, + .freqStep = 1.600, + .drMin = 6, + .drMax = 6, + .joinRequestDataRate = 6 + } + }, + .rx1Span = { + .numChannels = 8, + .freqStart = 923.300, + .freqStep = 0.600, + .drMin = 8, + .drMax = 13, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + }, + .rx1DataRateBase = 8, + .rx2 = { .enabled = true, .idx = 0, .freq = 923.300, .drMin = 8, .drMax = 8 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } +}; + +const LoRaWANBand_t CN500 = { + .bandNum = BandCN500, + .bandType = RADIOLIB_LORAWAN_BAND_FIXED, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 19, + .powerNumSteps = 7, + .dutyCycle = 0, + .dwellTimeUp = 0, + .dwellTimeDn = 0, + .txFreqs = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 1, + .txSpans = { + { + .numChannels = 96, + .freqStart = 470.300, + .freqStep = 0.200, + .drMin = 0, + .drMax = 5, + .joinRequestDataRate = 0 + }, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + }, + .rx1Span = { + .numChannels = 48, + .freqStart = 500.300, + .freqStep = 0.200, + .drMin = 0, + .drMax = 5, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + }, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 505.300, .drMin = 0, .drMax = 0 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } +}; + +const LoRaWANBand_t AS923 = { + .bandNum = BandAS923, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 16, + .powerNumSteps = 7, + .dutyCycle = 36000, + .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, + .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5}, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 0, + .txSpans = { + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + }, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 923.200, .drMin = 2, .drMax = 2 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } +}; + +const LoRaWANBand_t KR920 = { + .bandNum = BandKR920, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 14, + .powerNumSteps = 7, + .dutyCycle = 0, + .dwellTimeUp = 0, + .dwellTimeDn = 0, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 922.100, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 922.300, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 2, .freq = 922.500, .drMin = 0, .drMax = 5} + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 0, + .txSpans = { + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + }, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 921.900, .drMin = 0, .drMax = 0 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } +}; + +const LoRaWANBand_t IN865 = { + .bandNum = BandIN865, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 30, + .powerNumSteps = 10, + .dutyCycle = 0, + .dwellTimeUp = 0, + .dwellTimeDn = 0, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 865.0625, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 865.4025, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 2, .freq = 865.9850, .drMin = 0, .drMax = 5} + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 0, + .txSpans = { + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + }, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 866.550, .drMin = 2, .drMax = 2 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } +}; + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/Morse/Morse.cpp b/lib/lib_rf/RadioLib/src/protocols/Morse/Morse.cpp new file mode 100644 index 000000000..90cc2a68b --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/Morse/Morse.cpp @@ -0,0 +1,187 @@ +#include "Morse.h" + +#include + +#if !RADIOLIB_EXCLUDE_MORSE + +MorseClient::MorseClient(PhysicalLayer* phy) { + phyLayer = phy; + lineFeed = "^"; + #if !RADIOLIB_EXCLUDE_AFSK + audioClient = nullptr; + #endif +} + +#if !RADIOLIB_EXCLUDE_AFSK +MorseClient::MorseClient(AFSKClient* audio) { + phyLayer = audio->phyLayer; + lineFeed = "^"; + audioClient = audio; +} +#endif + +int16_t MorseClient::begin(float base, uint8_t speed) { + // calculate 24-bit frequency + baseFreqHz = base; + baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); + + // calculate tone period for decoding + basePeriod = (1000000.0f/base)/2.0f; + + // calculate symbol lengths (assumes PARIS as typical word) + dotLength = 1200 / speed; + dashLength = 3*dotLength; + letterSpace = 3*dotLength; + wordSpace = 4*dotLength; + + // configure for direct mode + return(phyLayer->startDirect()); +} + +size_t MorseClient::startSignal() { + return(MorseClient::write('_')); +} + +char MorseClient::decode(uint8_t symbol, uint8_t len) { + // add the guard bit + symbol |= (RADIOLIB_MORSE_DASH << len); + + // iterate over the table + for(uint8_t i = 0; i < sizeof(MorseTable); i++) { + uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(&MorseTable[i]); + if(code == symbol) { + // match, return the index + ASCII offset + return((char)(i + RADIOLIB_MORSE_ASCII_OFFSET)); + } + } + + // nothing found + return(RADIOLIB_MORSE_UNSUPPORTED); +} + +#if !RADIOLIB_EXCLUDE_AFSK +int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { + Module* mod = phyLayer->getMod(); + + // measure pulse duration in us + uint32_t duration = mod->hal->pulseIn(audioClient->outPin, mod->hal->GpioLevelLow, 4*basePeriod); + + // decide if this is a signal, or pause + if((duration > low*basePeriod) && (duration < high*basePeriod)) { + // this is a signal + signalCounter++; + } else if(duration == 0) { + // this is a pause + pauseCounter++; + } + + // update everything + if((pauseCounter > 0) && (signalCounter == 1)) { + // start of dot or dash + pauseCounter = 0; + signalStart = mod->hal->millis(); + uint32_t pauseLen = mod->hal->millis() - pauseStart; + + if((pauseLen >= low*(float)letterSpace) && (pauseLen <= high*(float)letterSpace)) { + return(RADIOLIB_MORSE_CHAR_COMPLETE); + } else if(pauseLen > wordSpace) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("\n"); + return(RADIOLIB_MORSE_WORD_COMPLETE); + } + + } else if((signalCounter > 0) && (pauseCounter == 1)) { + // end of dot or dash + signalCounter = 0; + pauseStart = mod->hal->millis(); + uint32_t signalLen = mod->hal->millis() - signalStart; + + if((signalLen >= low*(float)dotLength) && (signalLen <= high*(float)dotLength)) { + RADIOLIB_DEBUG_PROTOCOL_PRINT("."); + (*symbol) |= (RADIOLIB_MORSE_DOT << (*len)); + (*len)++; + } else if((signalLen >= low*(float)dashLength) && (signalLen <= high*(float)dashLength)) { + RADIOLIB_DEBUG_PROTOCOL_PRINT("-"); + (*symbol) |= (RADIOLIB_MORSE_DASH << (*len)); + (*len)++; + } else { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("", signalLen); + } + } + + return(RADIOLIB_MORSE_INTER_SYMBOL); +} +#endif + +size_t MorseClient::write(uint8_t b) { + Module* mod = phyLayer->getMod(); + + // check unprintable ASCII characters and boundaries + if((b < ' ') || (b == 0x60) || (b > 'z')) { + return(0); + } + + // inter-word pause (space) + if(b == ' ') { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("space"); + standby(); + mod->waitForMicroseconds(mod->hal->micros(), wordSpace*1000); + return(1); + } + + // get morse code from lookup table + uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(&MorseTable[(uint8_t)(toupper(b) - RADIOLIB_MORSE_ASCII_OFFSET)]); + + // check unsupported characters + if(code == RADIOLIB_MORSE_UNSUPPORTED) { + return(0); + } + + // iterate through codeword until guard bit is reached + while(code > RADIOLIB_MORSE_GUARDBIT) { + + // send dot or dash + if (code & RADIOLIB_MORSE_DASH) { + RADIOLIB_DEBUG_PROTOCOL_PRINT("-"); + transmitDirect(baseFreq, baseFreqHz); + mod->waitForMicroseconds(mod->hal->micros(), dashLength*1000); + } else { + RADIOLIB_DEBUG_PROTOCOL_PRINT("."); + transmitDirect(baseFreq, baseFreqHz); + mod->waitForMicroseconds(mod->hal->micros(), dotLength*1000); + } + + // symbol space + standby(); + mod->waitForMicroseconds(mod->hal->micros(), dotLength*1000); + + // move onto the next bit + code >>= 1; + } + + // letter space + standby(); + mod->waitForMicroseconds(mod->hal->micros(), letterSpace*1000 - dotLength*1000); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(); + + return(1); +} + +int16_t MorseClient::transmitDirect(uint32_t freq, uint32_t freqHz) { + #if !RADIOLIB_EXCLUDE_AFSK + if(audioClient != nullptr) { + return(audioClient->tone(freqHz)); + } + #endif + return(phyLayer->transmitDirect(freq)); +} + +int16_t MorseClient::standby() { + #if !RADIOLIB_EXCLUDE_AFSK + if(audioClient != nullptr) { + return(audioClient->noTone(true)); + } + #endif + return(phyLayer->standby()); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/Morse/Morse.h b/lib/lib_rf/RadioLib/src/protocols/Morse/Morse.h new file mode 100644 index 000000000..3edb0beae --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/Morse/Morse.h @@ -0,0 +1,181 @@ +#if !defined(_RADIOLIB_MORSE_H) && !RADIOLIB_EXCLUDE_MORSE +#define _RADIOLIB_MORSE_H + +#include "../../TypeDef.h" +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" +#include "../Print/Print.h" + +#define RADIOLIB_MORSE_DOT 0b0 +#define RADIOLIB_MORSE_DASH 0b1 +#define RADIOLIB_MORSE_GUARDBIT 0b1 +#define RADIOLIB_MORSE_UNSUPPORTED 0xFF +#define RADIOLIB_MORSE_ASCII_OFFSET 32 +#define RADIOLIB_MORSE_INTER_SYMBOL 0x00 +#define RADIOLIB_MORSE_CHAR_COMPLETE 0x01 +#define RADIOLIB_MORSE_WORD_COMPLETE 0x02 + +// Morse character table: - using codes defined in ITU-R M.1677-1 +// - Morse code representation is saved LSb first, using additional bit as guard +// - position in array corresponds ASCII code minus RADIOLIB_MORSE_ASCII_OFFSET +// - ASCII characters marked RADIOLIB_MORSE_UNSUPPORTED do not have ITU-R M.1677-1 equivalent +static const uint8_t MorseTable[] RADIOLIB_NONVOLATILE = { + 0b00, // space + 0b110101, // ! (unsupported) + 0b1010010, // " + RADIOLIB_MORSE_UNSUPPORTED, // # (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // $ (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // % (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // & (unsupported) + 0b1011110, // ' + 0b101101, // ( + 0b1101101, // ) + RADIOLIB_MORSE_UNSUPPORTED, // * (unsupported) + 0b101010, // + + 0b1110011, // , + 0b1100001, // - + 0b1101010, // . + 0b101001, // / + 0b111111, // 0 + 0b111110, // 1 + 0b111100, // 2 + 0b111000, // 3 + 0b110000, // 4 + 0b100000, // 5 + 0b100001, // 6 + 0b100011, // 7 + 0b100111, // 8 + 0b101111, // 9 + 0b1000111, // : + RADIOLIB_MORSE_UNSUPPORTED, // ; (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // < (unsupported) + 0b110001, // = + RADIOLIB_MORSE_UNSUPPORTED, // > (unsupported) + 0b1001100, // ? + 0b1010110, // @ + 0b110, // A + 0b10001, // B + 0b10101, // C + 0b1001, // D + 0b10, // E + 0b10100, // F + 0b1011, // G + 0b10000, // H + 0b100, // I + 0b11110, // J + 0b1101, // K + 0b10010, // L + 0b111, // M + 0b101, // N + 0b1111, // O + 0b10110, // P + 0b11011, // Q + 0b1010, // R + 0b1000, // S + 0b11, // T + 0b1100, // U + 0b11000, // V + 0b1110, // W + 0b11001, // X + 0b11101, // Y + 0b10011, // Z + RADIOLIB_MORSE_UNSUPPORTED, // [ (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // \ (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // ] (unsupported) + 0b1101000, // ^ (unsupported, used as alias for end of work) + 0b110101 // _ (unsupported, used as alias for starting signal) +}; + +/*! + \class MorseClient + \brief Client for Morse Code communication. The public interface is the same as Arduino Serial. +*/ +class MorseClient: public RadioLibPrint { + public: + /*! + \brief Constructor for 2-FSK mode. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + */ + explicit MorseClient(PhysicalLayer* phy); + + #if !RADIOLIB_EXCLUDE_AFSK + /*! + \brief Constructor for AFSK mode. + \param audio Pointer to the AFSK instance providing audio. + */ + explicit MorseClient(AFSKClient* audio); + #endif + + // basic methods + + /*! + \brief Initialization method. + \param base Base RF frequency to be used in MHz (in 2-FSK mode), or the tone frequency in Hz (in AFSK mode) + \param speed Coding speed in words per minute. + \returns \ref status_codes + */ + int16_t begin(float base, uint8_t speed = 20); + + /*! + \brief Send start signal. + \returns Number of bytes sent (always 0). + */ + size_t startSignal(); + + /*! + \brief Decode Morse symbol to ASCII. + \param symbol Morse code symbol, represented as outlined in MorseTable. + \param len Symbol length (number of dots and dashes). + \returns ASCII character matching the symbol, or 0xFF if no match is found. + */ + static char decode(uint8_t symbol, uint8_t len); + + /*! + \brief Read Morse tone on input pin. + \param symbol Pointer to the symbol buffer. + \param len Pointer to the length counter. + \param low Low threshold for decision limit (dot length, pause length etc.), defaults to 0.75. + \param high High threshold for decision limit (dot length, pause length etc.), defaults to 1.25. + \returns 0 if not enough symbols were decoded, 1 if inter-character space was detected, + 2 if inter-word space was detected. + */ + #if !RADIOLIB_EXCLUDE_AFSK + int read(uint8_t* symbol, uint8_t* len, float low = 0.75f, float high = 1.25f); + #endif + + /*! + \brief Write one byte. Implementation of interface of the RadioLibPrint/Print class. + \param b Byte to write. + \returns 1 if the byte was written, 0 otherwise. + */ + size_t write(uint8_t b); + +#if !RADIOLIB_GODMODE + private: +#endif + PhysicalLayer* phyLayer; + #if !RADIOLIB_EXCLUDE_AFSK + AFSKClient* audioClient; + #endif + + uint32_t baseFreq = 0, baseFreqHz = 0; + float basePeriod = 0.0f; + uint32_t dotLength = 0; + uint32_t dashLength = 0; + uint32_t letterSpace = 0; + uint16_t wordSpace = 0; + + // variables to keep decoding state + uint32_t signalCounter = 0; + uint32_t signalStart = 0; + uint32_t pauseCounter = 0; + uint32_t pauseStart = 0; + + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); + + int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); + int16_t standby(); +}; + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.cpp b/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.cpp new file mode 100644 index 000000000..1db47da61 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.cpp @@ -0,0 +1,599 @@ +#include "Pager.h" +#include +#include +#if defined(ESP_PLATFORM) +#include "esp_attr.h" +#endif + +#if !RADIOLIB_EXCLUDE_PAGER + +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE +// this is a massive hack, but we need a global-scope ISR to manage the bit reading +// let's hope nobody ever tries running two POCSAG receivers at the same time +static PhysicalLayer* readBitInstance = NULL; +static uint32_t readBitPin = RADIOLIB_NC; + +#if defined(ESP8266) || defined(ESP32) + IRAM_ATTR +#endif +static void PagerClientReadBit(void) { + if(readBitInstance) { + readBitInstance->readBit(readBitPin); + } +} +#endif + +PagerClient::PagerClient(PhysicalLayer* phy) { + phyLayer = phy; + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE + readBitInstance = phyLayer; + #endif + filterNumAddresses = 0; + filterAddresses = NULL; + filterMasks = NULL; +} + +int16_t PagerClient::begin(float base, uint16_t speed, bool invert, uint16_t shift) { + // calculate duration of 1 bit in us + dataRate = (float)speed/1000.0f; + bitDuration = (uint32_t)1000000/speed; + + // calculate 24-bit frequency + baseFreq = base; + baseFreqRaw = (baseFreq * 1000000.0) / phyLayer->getFreqStep(); + + // calculate module carrier frequency resolution + uint16_t step = round(phyLayer->getFreqStep()); + + // calculate raw frequency shift + shiftFreqHz = shift; + shiftFreq = shiftFreqHz/step; + inv = invert; + + // initialize BCH encoder + RadioLibBCHInstance.begin(RADIOLIB_PAGER_BCH_N, RADIOLIB_PAGER_BCH_K, RADIOLIB_PAGER_BCH_PRIMITIVE_POLY); + + // configure for direct mode + return(phyLayer->startDirect()); +} + +int16_t PagerClient::sendTone(uint32_t addr) { + return(PagerClient::transmit(NULL, 0, addr)); +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t PagerClient::transmit(String& str, uint32_t addr, uint8_t encoding, uint8_t function) { + return(PagerClient::transmit(str.c_str(), addr, encoding, function)); +} +#endif + +int16_t PagerClient::transmit(const char* str, uint32_t addr, uint8_t encoding, uint8_t function) { + return(PagerClient::transmit((uint8_t*)str, strlen(str), addr, encoding, function)); +} + +int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding, uint8_t function) { + if(addr > RADIOLIB_PAGER_ADDRESS_MAX) { + return(RADIOLIB_ERR_INVALID_ADDRESS_WIDTH); + } + + if(((data == NULL) && (len > 0)) || ((data != NULL) && (len == 0))) { + return(RADIOLIB_ERR_INVALID_PAYLOAD); + } + + // get symbol bit length based on encoding + uint8_t symbolLength = 0; + if(encoding == RADIOLIB_PAGER_BCD) { + symbolLength = 4; + + } else if(encoding == RADIOLIB_PAGER_ASCII) { + symbolLength = 7; + + } else { + return(RADIOLIB_ERR_INVALID_ENCODING); + + } + + // Automatically set function bits based on given encoding + if (function == RADIOLIB_PAGER_FUNC_AUTO) { + if(encoding == RADIOLIB_PAGER_BCD) { + function = RADIOLIB_PAGER_FUNC_BITS_NUMERIC; + + } else if(encoding == RADIOLIB_PAGER_ASCII) { + function = RADIOLIB_PAGER_FUNC_BITS_ALPHA; + + } else { + return(RADIOLIB_ERR_INVALID_ENCODING); + + } + if(len == 0) { + function = RADIOLIB_PAGER_FUNC_BITS_TONE; + } + } + if (function > RADIOLIB_PAGER_FUNC_BITS_ALPHA) { + return(RADIOLIB_ERR_INVALID_FUNCTION); + } + + // get target position in batch (3 LSB from address determine frame position in batch) + uint8_t framePos = 2*(addr & 0x07); + + // get address that will be written into address frame + uint32_t frameAddr = ((addr >> 3) << RADIOLIB_PAGER_ADDRESS_POS) | (function << RADIOLIB_PAGER_FUNC_BITS_POS); + + // calculate the number of 20-bit data blocks + size_t numDataBlocks = (len * symbolLength) / RADIOLIB_PAGER_MESSAGE_BITS_LENGTH; + if((len * symbolLength) % RADIOLIB_PAGER_MESSAGE_BITS_LENGTH > 0) { + numDataBlocks += 1; + } + + // calculate number of batches + size_t numBatches = (1 + framePos + numDataBlocks) / RADIOLIB_PAGER_BATCH_LEN + 1; + if((1 + numDataBlocks) % RADIOLIB_PAGER_BATCH_LEN == 0) { + numBatches -= 1; + } + + // calculate message length in 32-bit code words + size_t msgLen = RADIOLIB_PAGER_PREAMBLE_LENGTH + (1 + RADIOLIB_PAGER_BATCH_LEN) * numBatches; + + #if RADIOLIB_STATIC_ONLY + uint32_t msg[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint32_t* msg = new uint32_t[msgLen]; + #endif + + // build the message + memset(msg, 0x00, msgLen*sizeof(uint32_t)); + + // set preamble + for(size_t i = 0; i < RADIOLIB_PAGER_PREAMBLE_LENGTH; i++) { + msg[i] = RADIOLIB_PAGER_PREAMBLE_CODE_WORD; + } + + // start by setting everything after preamble to idle + for(size_t i = RADIOLIB_PAGER_PREAMBLE_LENGTH; i < msgLen; i++) { + msg[i] = RADIOLIB_PAGER_IDLE_CODE_WORD; + } + + // set frame synchronization code words + for(size_t i = 0; i < numBatches; i++) { + msg[RADIOLIB_PAGER_PREAMBLE_LENGTH + i*(1 + RADIOLIB_PAGER_BATCH_LEN)] = RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD; + } + + // write address code word + msg[RADIOLIB_PAGER_PREAMBLE_LENGTH + 1 + framePos] = RadioLibBCHInstance.encode(frameAddr); + + // write the data as 20-bit code blocks + if(len > 0) { + int8_t remBits = 0; + uint8_t dataPos = 0; + for(size_t i = 0; i < numDataBlocks + numBatches - 1; i++) { + uint8_t blockPos = RADIOLIB_PAGER_PREAMBLE_LENGTH + 1 + framePos + 1 + i; + + // check if we need to skip a frame sync marker + if(((blockPos - (RADIOLIB_PAGER_PREAMBLE_LENGTH + 1)) % RADIOLIB_PAGER_BATCH_LEN) == 0) { + blockPos++; + i++; + } + + // mark this as a message code word + msg[blockPos] = RADIOLIB_PAGER_MESSAGE_CODE_WORD << (RADIOLIB_PAGER_CODE_WORD_LEN - 1); + + // first insert the remainder from previous code word (if any) + if(remBits > 0) { + // this doesn't apply to BCD messages, so no need to check that here + uint8_t prev = Module::reflect(data[dataPos - 1], 8); + prev >>= 1; + msg[blockPos] |= (uint32_t)prev << (RADIOLIB_PAGER_CODE_WORD_LEN - 1 - remBits); + } + + // set all message symbols until we overflow to the next code word or run out of message symbols + int8_t symbolPos = RADIOLIB_PAGER_CODE_WORD_LEN - 1 - symbolLength - remBits; + while(symbolPos > (RADIOLIB_PAGER_FUNC_BITS_POS - symbolLength)) { + + // for BCD, encode the symbol + uint8_t symbol = data[dataPos++]; + if(encoding == RADIOLIB_PAGER_BCD) { + symbol = encodeBCD(symbol); + } + symbol = Module::reflect(symbol, 8); + symbol >>= (8 - symbolLength); + + // insert the next message symbol + msg[blockPos] |= (uint32_t)symbol << symbolPos; + symbolPos -= symbolLength; + + // check if we ran out of message symbols + if(dataPos >= len) { + // in BCD mode, pad the rest of the code word with spaces (0xC) + if(encoding == RADIOLIB_PAGER_BCD) { + uint8_t numSteps = (symbolPos - RADIOLIB_PAGER_FUNC_BITS_POS + symbolLength)/symbolLength; + for(uint8_t i = 0; i < numSteps; i++) { + symbol = encodeBCD(' '); + symbol = Module::reflect(symbol, 8); + symbol >>= (8 - symbolLength); + msg[blockPos] |= (uint32_t)symbol << symbolPos; + symbolPos -= symbolLength; + } + } + break; + } + } + + // ensure the parity bits are not set due to overflow + msg[blockPos] &= ~(RADIOLIB_PAGER_BCH_BITS_MASK); + + // save the number of overflown bits + remBits = RADIOLIB_PAGER_FUNC_BITS_POS - symbolPos - symbolLength; + + // do the FEC + msg[blockPos] = RadioLibBCHInstance.encode(msg[blockPos]); + } + } + + // transmit the message + PagerClient::write(msg, msgLen); + + #if !RADIOLIB_STATIC_ONLY + delete[] msg; + #endif + + // turn transmitter off + phyLayer->standby(); + + return(RADIOLIB_ERR_NONE); +} + +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE +int16_t PagerClient::startReceive(uint32_t pin, uint32_t addr, uint32_t mask) { + // save the variables + readBitPin = pin; + filterAddr = addr; + filterMask = mask; + filterAddresses = NULL; + filterMasks = NULL; + filterNumAddresses = 0; + return(startReceiveCommon()); +} + +int16_t PagerClient::startReceive(uint32_t pin, uint32_t *addrs, uint32_t *masks, size_t numAddresses) { + // save the variables + readBitPin = pin; + filterAddr = 0; + filterMask = 0; + filterAddresses = addrs; + filterMasks = masks; + filterNumAddresses = numAddresses; + return(startReceiveCommon()); +} + +int16_t PagerClient::startReceiveCommon() { + // set the carrier frequency + int16_t state = phyLayer->setFrequency(baseFreq); + RADIOLIB_ASSERT(state); + + // set bitrate + state = phyLayer->setBitRate(dataRate); + RADIOLIB_ASSERT(state); + + // set frequency deviation to 4.5 khz + state = phyLayer->setFrequencyDeviation((float)shiftFreqHz / 1000.0f); + RADIOLIB_ASSERT(state); + + // now set up the direct mode reception + Module* mod = phyLayer->getMod(); + mod->hal->pinMode(readBitPin, mod->hal->GpioModeInput); + + // set direct sync word to the frame sync word + // the logic here is inverted, because modules like SX1278 + // assume high frequency to be logic 1, which is opposite to POCSAG + if(!inv) { + phyLayer->setDirectSyncWord(~RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD, 32); + } else { + phyLayer->setDirectSyncWord(RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD, 32); + } + + phyLayer->setDirectAction(PagerClientReadBit); + phyLayer->receiveDirect(); + + return(state); +} + +size_t PagerClient::available() { + return(phyLayer->available() + sizeof(uint32_t))/(sizeof(uint32_t) * (RADIOLIB_PAGER_BATCH_LEN + 1)); +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t PagerClient::readData(String& str, size_t len, uint32_t* addr) { + int16_t state = RADIOLIB_ERR_NONE; + + // determine the message length, based on user input or the amount of received data + size_t length = len; + if(length == 0) { + // one batch can contain at most 80 message symbols + length = available()*80; + } + + // build a temporary buffer + #if RADIOLIB_STATIC_ONLY + uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; + #else + uint8_t* data = new uint8_t[length + 1]; + if(!data) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + #endif + + // read the received data + state = readData(data, &length, addr); + + if(state == RADIOLIB_ERR_NONE) { + // check tone-only tramsissions + if(length == 0) { + length = 6; + strncpy((char*)data, "", length + 1); + } + + // add null terminator + data[length] = 0; + + // initialize Arduino String class + str = String((char*)data); + } + + // deallocate temporary buffer + #if !RADIOLIB_STATIC_ONLY + delete[] data; + #endif + + return(state); +} +#endif + +int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { + // find the correct address + bool match = false; + uint8_t framePos = 0; + uint8_t symbolLength = 0; + while(!match && phyLayer->available()) { + uint32_t cw = read(); + framePos++; + + // check if it's the idle code word + if(cw == RADIOLIB_PAGER_IDLE_CODE_WORD) { + continue; + } + + // check if it's the sync word + if(cw == RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD) { + framePos = 0; + continue; + } + + // not an idle code word, check if it's an address word + if(cw & (RADIOLIB_PAGER_MESSAGE_CODE_WORD << (RADIOLIB_PAGER_CODE_WORD_LEN - 1))) { + // this is pretty weird, it seems to be a message code word without address + continue; + } + + // should be an address code word, extract the address + uint32_t addr_found = ((cw & RADIOLIB_PAGER_ADDRESS_BITS_MASK) >> (RADIOLIB_PAGER_ADDRESS_POS - 3)) | (framePos/2); + if (addressMatched(addr_found)) { + match = true; + if(addr) { + *addr = addr_found; + } + + // determine the encoding from the function bits + if((cw & RADIOLIB_PAGER_FUNCTION_BITS_MASK) >> RADIOLIB_PAGER_FUNC_BITS_POS == RADIOLIB_PAGER_FUNC_BITS_NUMERIC) { + symbolLength = 4; + } else { + symbolLength = 7; + } + } + } + + if(!match) { + // address not found + return(RADIOLIB_ERR_ADDRESS_NOT_FOUND); + } + + // we have the address, start pulling out the message + bool complete = false; + size_t decodedBytes = 0; + uint32_t prevCw = 0; + bool overflow = false; + int8_t ovfBits = 0; + while(!complete && phyLayer->available()) { + uint32_t cw = read(); + + // check if it's the idle code word + if(cw == RADIOLIB_PAGER_IDLE_CODE_WORD) { + complete = true; + break; + } + + // skip the sync words + if(cw == RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD) { + continue; + } + + // check overflow from previous code word + uint8_t bitPos = RADIOLIB_PAGER_CODE_WORD_LEN - 1 - symbolLength; + if(overflow) { + overflow = false; + + // this is a bit convoluted - first, build masks for both previous and current code word + uint8_t currPos = RADIOLIB_PAGER_CODE_WORD_LEN - 1 - symbolLength + ovfBits; + uint8_t prevPos = RADIOLIB_PAGER_MESSAGE_END_POS; + uint32_t prevMask = (0x7FUL << prevPos) & ~((uint32_t)0x7FUL << (RADIOLIB_PAGER_MESSAGE_END_POS + ovfBits)); + uint32_t currMask = (0x7FUL << currPos) & ~((uint32_t)1 << (RADIOLIB_PAGER_CODE_WORD_LEN - 1)); + + // next, get the two parts of the message symbol and stick them together + uint8_t prevSymbol = (prevCw & prevMask) >> prevPos; + uint8_t currSymbol = (cw & currMask) >> currPos; + uint32_t symbol = prevSymbol << (symbolLength - ovfBits) | currSymbol; + + // finally, we can flip the bits + symbol = Module::reflect((uint8_t)symbol, 8); + symbol >>= (8 - symbolLength); + + // decode BCD and we're done + if(symbolLength == 4) { + symbol = decodeBCD(symbol); + } + data[decodedBytes++] = symbol; + + // adjust the bit position of the next message symbol + bitPos += ovfBits; + bitPos -= symbolLength; + } + + // get the message symbols based on the encoding type + while(bitPos >= RADIOLIB_PAGER_MESSAGE_END_POS) { + // get the message symbol from the code word and reverse bits + uint32_t symbol = (cw & (0x7FUL << bitPos)) >> bitPos; + symbol = Module::reflect((uint8_t)symbol, 8); + symbol >>= (8 - symbolLength); + + // decode BCD if needed + if(symbolLength == 4) { + symbol = decodeBCD(symbol); + } + data[decodedBytes++] = symbol; + + // now calculate if the next symbol is overflowing to the following code word + int8_t remBits = bitPos - RADIOLIB_PAGER_MESSAGE_END_POS; + if(remBits < symbolLength) { + // overflow! + prevCw = cw; + overflow = true; + ovfBits = remBits; + } + bitPos -= symbolLength; + } + + } + + // save the number of decoded bytes + *len = decodedBytes; + return(RADIOLIB_ERR_NONE); +} +#endif + +bool PagerClient::addressMatched(uint32_t addr) { + // check whether to match single or multiple addresses/masks + if(filterNumAddresses == 0) { + return((addr & filterMask) == (filterAddr & filterMask)); + } + + // multiple addresses, check there are some to match + if((filterAddresses == NULL) || (filterMasks == NULL)) { + return(false); + } + + for(size_t i = 0; i < filterNumAddresses; i++) { + if((filterAddresses[i] & filterMasks[i]) == (addr & filterMasks[i])) { + return(true); + } + } + + return(false); +} + +void PagerClient::write(uint32_t* data, size_t len) { + // write code words from buffer + for(size_t i = 0; i < len; i++) { + PagerClient::write(data[i]); + } +} + +void PagerClient::write(uint32_t codeWord) { + // write single code word + Module* mod = phyLayer->getMod(); + for(int8_t i = 31; i >= 0; i--) { + uint32_t mask = (uint32_t)0x01 << i; + uint32_t start = mod->hal->micros(); + + // figure out the shift direction - start by assuming the bit is 0 + int16_t change = shiftFreq; + + // now check if it's actually 1 + if(codeWord & mask) { + change = -shiftFreq; + } + + // finally, check if inversion is enabled + if(inv) { + change = -change; + } + + // now transmit the shifted frequency + phyLayer->transmitDirect(baseFreqRaw + change); + + // this is pretty silly, while(mod->hal->micros() ... ) would be enough + // but for some reason, MegaCore throws a linker error on it + // "relocation truncated to fit: R_AVR_7_PCREL against `no symbol'" + uint32_t now = mod->hal->micros(); + while(now - start < bitDuration) { + now = mod->hal->micros(); + } + } +} + +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE +uint32_t PagerClient::read() { + uint32_t codeWord = 0; + codeWord |= (uint32_t)phyLayer->read() << 24; + codeWord |= (uint32_t)phyLayer->read() << 16; + codeWord |= (uint32_t)phyLayer->read() << 8; + codeWord |= (uint32_t)phyLayer->read(); + + // check if we need to invert bits + // the logic here is inverted, because modules like SX1278 + // assume high frequency to be logic 1, which is opposite to POCSAG + if(!inv) { + codeWord = ~codeWord; + } + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("R\t%lX", codeWord); + // TODO BCH error correction here + return(codeWord); +} +#endif + +uint8_t PagerClient::encodeBCD(char c) { + switch(c) { + case '*': + return(0x0A); + case 'U': + return(0x0B); + case ' ': + return(0x0C); + case '-': + return(0x0D); + case ')': + return(0x0E); + case '(': + return(0x0F); + } + return(c - '0'); +} + +char PagerClient::decodeBCD(uint8_t b) { + switch(b) { + case 0x0A: + return('*'); + case 0x0B: + return('U'); + case 0x0C: + return(' '); + case 0x0D: + return('-'); + case 0x0E: + return(')'); + case 0x0F: + return('('); + } + return(b + '0'); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.h b/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.h new file mode 100644 index 000000000..f5cdb8190 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/Pager/Pager.h @@ -0,0 +1,206 @@ +#if !defined(_RADIOLIB_PAGER_H) && !RADIOLIB_EXCLUDE_PAGER +#define _RADIOLIB_PAGER_H + +#include "../../TypeDef.h" +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../../utils/FEC.h" + +// frequency shift in Hz +#define RADIOLIB_PAGER_FREQ_SHIFT_HZ (4500) + +// supported encoding schemes +#define RADIOLIB_PAGER_ASCII (0) +#define RADIOLIB_PAGER_BCD (1) + +// preamble length in 32-bit code words +#define RADIOLIB_PAGER_PREAMBLE_LENGTH (18) + +// protocol-specified code words +#define RADIOLIB_PAGER_PREAMBLE_CODE_WORD (0xAAAAAAAA) +#define RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD (0x7CD215D8) +#define RADIOLIB_PAGER_IDLE_CODE_WORD (0x7A89C197) + +// code word type identification flags +#define RADIOLIB_PAGER_ADDRESS_CODE_WORD (0UL) +#define RADIOLIB_PAGER_MESSAGE_CODE_WORD (1UL) + +// length of code word in bits +#define RADIOLIB_PAGER_CODE_WORD_LEN (32) + +// number of message bits in a single code block +#define RADIOLIB_PAGER_ADDRESS_POS (13) +#define RADIOLIB_PAGER_FUNC_BITS_POS (11) +#define RADIOLIB_PAGER_MESSAGE_BITS_LENGTH (20) +#define RADIOLIB_PAGER_MESSAGE_END_POS (11) + +// number of code words in a batch +#define RADIOLIB_PAGER_BATCH_LEN (16) + +// mask for address bits in a single code word +#define RADIOLIB_PAGER_ADDRESS_BITS_MASK (0x7FFFE000UL) + +// mask for function bits in a single code word +#define RADIOLIB_PAGER_FUNCTION_BITS_MASK (0x00001800UL) + +// mask for BCH bits in a single code word +#define RADIOLIB_PAGER_BCH_BITS_MASK (0x000007FFUL) + +// message type functional bits +#define RADIOLIB_PAGER_FUNC_BITS_NUMERIC (0b00) +#define RADIOLIB_PAGER_FUNC_BITS_TONE (0b01) +#define RADIOLIB_PAGER_FUNC_BITS_ACTIVATION (0b10) +#define RADIOLIB_PAGER_FUNC_BITS_ALPHA (0b11) +#define RADIOLIB_PAGER_FUNC_AUTO 0xFF + +// the maximum allowed address (2^22 - 1) +#define RADIOLIB_PAGER_ADDRESS_MAX (2097151) + +/*! + \class PagerClient + \brief Client for Pager communication. +*/ +class PagerClient { + public: + /*! + \brief Default constructor. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + */ + explicit PagerClient(PhysicalLayer* phy); + + // basic methods + + /*! + \brief Initialization method. + \param base Base (center) frequency to be used in MHz. + \param speed Bit rate to use in bps. Common POCSAG decoders can receive 512, 1200 and 2400 bps. + \param invert Enable frequency inversion. Disabled by default (high frequency is digital 0). + \param shift Set custom frequency shift, defaults to 4500 Hz. + \returns \ref status_codes + */ + int16_t begin(float base, uint16_t speed, bool invert = false, uint16_t shift = RADIOLIB_PAGER_FREQ_SHIFT_HZ); + + /*! + \brief Method to send a tone-only alert to a destination pager. + \param addr Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. + \returns \ref status_codes + */ + int16_t sendTone(uint32_t addr); + + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Arduino String transmit method. + \param str Address of Arduino string that will be transmitted. + \param addr Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. + \param encoding Encoding to be used (BCD or ASCII). Defaults to RADIOLIB_PAGER_BCD. + \param function bits (NUMERIC, TONE, ACTIVATION, ALPHANUMERIC). Allowed values 0 to 3. Defaults to auto select by specified encoding + \returns \ref status_codes + */ + int16_t transmit(String& str, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD, uint8_t function = RADIOLIB_PAGER_FUNC_AUTO); + #endif + + /*! + \brief C-string transmit method. + \param str C-string that will be transmitted. + \param addr Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. + \param encoding Encoding to be used (BCD or ASCII). Defaults to RADIOLIB_PAGER_BCD. + \param function bits (NUMERIC, TONE, ACTIVATION, ALPHANUMERIC). Allowed values 0 to 3. Defaults to auto select by specified encoding + \returns \ref status_codes + */ + int16_t transmit(const char* str, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD, uint8_t function = RADIOLIB_PAGER_FUNC_AUTO); + + /*! + \brief Binary transmit method. Will transmit arbitrary binary data. + \param data Binary data that will be transmitted. + \param len Length of binary data to transmit (in bytes). + \param addr Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. + \param encoding Encoding to be used (BCD or ASCII). Defaults to RADIOLIB_PAGER_BCD. + \param function bits (NUMERIC, TONE, ACTIVATION, ALPHANUMERIC). Allowed values 0 to 3. Defaults to auto select by specified encoding + \returns \ref status_codes + */ + int16_t transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD, uint8_t function = RADIOLIB_PAGER_FUNC_AUTO); + + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE + /*! + \brief Start reception of POCSAG packets. + \param pin Pin to receive digital data on (e.g., DIO2 for SX127x). + \param addr Address of this "pager". Allowed values are 0 to 2097151 - values above 2000000 are reserved. + \param mask Address filter mask - set individual bits to enable or disable match on that bit of the address. + Set to 0xFFFFF (all bits checked) by default. + \returns \ref status_codes + */ + int16_t startReceive(uint32_t pin, uint32_t addr, uint32_t mask = 0xFFFFF); + + /*! + \brief Start reception of POCSAG packets for multiple addresses and masks. + \param pin Pin to receive digital data on (e.g., DIO2 for SX127x). + \param addrs Array of addresses to receive. + \param masks Array of address masks to use for filtering. Masks will be applied to corresponding addresses in addr array. + \param numAddress Number of addresses/masks to match. + \returns \ref status_codes + */ + int16_t startReceive(uint32_t pin, uint32_t *addrs, uint32_t *masks, size_t numAddress); + + /*! + \brief Get the number of POCSAG batches available in buffer. Limited by the size of direct mode buffer! + \returns Number of available batches. + */ + size_t available(); + + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Reads data that was received after calling startReceive method. + \param str Address of Arduino String to save the received data. + \param len Expected number of characters in the message. When set to 0, the message length will be retrieved + automatically. When more bytes than received are requested, only the number of bytes requested will be returned. + \param addr Pointer to variable holding the address of the received pager message. + Set to NULL to not retrieve address. + \returns \ref status_codes + */ + int16_t readData(String& str, size_t len = 0, uint32_t* addr = NULL); + #endif + + /*! + \brief Reads data that was received after calling startReceive method. + \param data Pointer to array to save the received message. + \param len Pointer to variable holding the number of bytes that will be read. When set to 0, the packet length + will be retrieved automatically. When more bytes than received are requested, only the number of bytes + requested will be returned. Upon completion, the number of bytes received will be written to this variable. + \param addr Pointer to variable holding the address of the received pager message. + Set to NULL to not retrieve address. + \returns \ref status_codes + */ + int16_t readData(uint8_t* data, size_t* len, uint32_t* addr = NULL); +#endif + +#if !RADIOLIB_GODMODE + private: +#endif + PhysicalLayer* phyLayer; + + float baseFreq; + float dataRate; + uint32_t baseFreqRaw; + uint16_t shiftFreq; + uint16_t shiftFreqHz; + uint16_t bitDuration; + uint32_t filterAddr; + uint32_t filterMask; + uint32_t *filterAddresses; + uint32_t *filterMasks; + size_t filterNumAddresses; + bool inv = false; + + void write(uint32_t* data, size_t len); + void write(uint32_t codeWord); + int16_t startReceiveCommon(); + bool addressMatched(uint32_t addr); + +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE + uint32_t read(); +#endif + + uint8_t encodeBCD(char c); + char decodeBCD(uint8_t b); +}; + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/lib/lib_rf/RadioLib/src/protocols/PhysicalLayer/PhysicalLayer.cpp new file mode 100644 index 000000000..a1b51730e --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -0,0 +1,495 @@ +#include "PhysicalLayer.h" +#include + +PhysicalLayer::PhysicalLayer(float step, size_t maxLen) { + this->freqStep = step; + this->maxPacketLength = maxLen; + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE + this->bufferBitPos = 0; + this->bufferWritePos = 0; + #endif +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) { + // read flash string length + size_t len = 0; + PGM_P p = reinterpret_cast(fstr); + while(true) { + char c = RADIOLIB_NONVOLATILE_READ_BYTE(p++); + len++; + if(c == '\0') { + break; + } + } + + // dynamically allocate memory + #if RADIOLIB_STATIC_ONLY + char str[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + char* str = new char[len]; + #endif + + // copy string from flash + p = reinterpret_cast(fstr); + for(size_t i = 0; i < len; i++) { + str[i] = RADIOLIB_NONVOLATILE_READ_BYTE(p + i); + } + + // transmit string + int16_t state = transmit(str, addr); + #if !RADIOLIB_STATIC_ONLY + delete[] str; + #endif + return(state); +} + +int16_t PhysicalLayer::transmit(String& str, uint8_t addr) { + return(transmit(str.c_str(), addr)); +} +#endif + +int16_t PhysicalLayer::transmit(const char* str, uint8_t addr) { + return(transmit((uint8_t*)str, strlen(str), addr)); +} + +int16_t PhysicalLayer::transmit(uint8_t* data, size_t len, uint8_t addr) { + (void)data; + (void)len; + (void)addr; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t PhysicalLayer::receive(String& str, size_t len) { + int16_t state = RADIOLIB_ERR_NONE; + + // user can override the length of data to read + size_t length = len; + + // build a temporary buffer + #if RADIOLIB_STATIC_ONLY + uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; + #else + uint8_t* data = NULL; + if(length == 0) { + data = new uint8_t[this->maxPacketLength + 1]; + } else { + data = new uint8_t[length + 1]; + } + if(!data) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + #endif + + // attempt packet reception + state = receive(data, length); + + // any of the following leads to at least some data being available + // let's leave the decision of whether to keep it or not up to the user + if((state == RADIOLIB_ERR_NONE) || (state == RADIOLIB_ERR_CRC_MISMATCH) || (state == RADIOLIB_ERR_LORA_HEADER_DAMAGED)) { + // read the number of actually received bytes (for unknown packets) + if(len == 0) { + length = getPacketLength(false); + } + + // add null terminator + data[length] = 0; + + // initialize Arduino String class + str = String((char*)data); + } + + // deallocate temporary buffer + #if !RADIOLIB_STATIC_ONLY + delete[] data; + #endif + + return(state); +} +#endif + +int16_t PhysicalLayer::receive(uint8_t* data, size_t len) { + (void)data; + (void)len; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::sleep() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::standby() { + return(standby(RADIOLIB_STANDBY_DEFAULT)); +} + +int16_t PhysicalLayer::standby(uint8_t mode) { + (void)mode; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::startReceive() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)timeout; + (void)irqFlags; + (void)irqMask; + (void)len; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t PhysicalLayer::startTransmit(String& str, uint8_t addr) { + return(startTransmit(str.c_str(), addr)); +} +#endif + +int16_t PhysicalLayer::startTransmit(const char* str, uint8_t addr) { + return(startTransmit((uint8_t*)str, strlen(str), addr)); +} + +int16_t PhysicalLayer::startTransmit(uint8_t* data, size_t len, uint8_t addr) { + (void)data; + (void)len; + (void)addr; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::finishTransmit() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t PhysicalLayer::readData(String& str, size_t len) { + int16_t state = RADIOLIB_ERR_NONE; + + // read the number of actually received bytes + size_t length = getPacketLength(); + + if((len < length) && (len != 0)) { + // user requested less bytes than were received, this is allowed (but frowned upon) + // requests for more data than were received will only return the number of actually received bytes (unlike PhysicalLayer::receive()) + length = len; + } + + // build a temporary buffer + #if RADIOLIB_STATIC_ONLY + uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; + #else + uint8_t* data = new uint8_t[length + 1]; + if(!data) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + #endif + + // read the received data + state = readData(data, length); + + // any of the following leads to at least some data being available + // let's leave the decision of whether to keep it or not up to the user + if((state == RADIOLIB_ERR_NONE) || (state == RADIOLIB_ERR_CRC_MISMATCH) || (state == RADIOLIB_ERR_LORA_HEADER_DAMAGED)) { + // add null terminator + data[length] = 0; + + // initialize Arduino String class + str = String((char*)data); + } + + // deallocate temporary buffer + #if !RADIOLIB_STATIC_ONLY + delete[] data; + #endif + + return(state); +} +#endif + +int16_t PhysicalLayer::readData(uint8_t* data, size_t len) { + (void)data; + (void)len; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::transmitDirect(uint32_t frf) { + (void)frf; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::receiveDirect() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setFrequency(float freq) { + (void)freq; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setBitRate(float br) { + (void)br; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setFrequencyDeviation(float freqDev) { + (void)freqDev; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setDataShaping(uint8_t sh) { + (void)sh; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setEncoding(uint8_t encoding) { + (void)encoding; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::invertIQ(bool enable) { + (void)enable; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setOutputPower(int8_t power) { + (void)power; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setSyncWord(uint8_t* sync, size_t len) { + (void)sync; + (void)len; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setPreambleLength(size_t len) { + (void)len; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setDataRate(DataRate_t dr) { + (void)dr; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::checkDataRate(DataRate_t dr) { + (void)dr; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +float PhysicalLayer::getFreqStep() const { + return(this->freqStep); +} + +size_t PhysicalLayer::getPacketLength(bool update) { + (void)update; + return(0); +} + +float PhysicalLayer::getRSSI() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +float PhysicalLayer::getSNR() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +uint32_t PhysicalLayer::getTimeOnAir(size_t len) { + (void)len; + return(0); +} + +uint32_t PhysicalLayer::calculateRxTimeout(uint32_t timeoutUs) { + (void)timeoutUs; + return(0); +} + +int16_t PhysicalLayer::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) { + (void)irqFlags; + (void)irqMask; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +bool PhysicalLayer::isRxTimeout() { + return(false); +} + +int16_t PhysicalLayer::startChannelScan() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::getChannelScanResult() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::scanChannel() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int32_t PhysicalLayer::random(int32_t max) { + if(max == 0) { + return(0); + } + + // get random bytes from the radio + uint8_t randBuff[4]; + for(uint8_t i = 0; i < 4; i++) { + randBuff[i] = randomByte(); + } + + // create 32-bit TRNG number + int32_t randNum = ((int32_t)randBuff[0] << 24) | ((int32_t)randBuff[1] << 16) | ((int32_t)randBuff[2] << 8) | ((int32_t)randBuff[3]); + if(randNum < 0) { + randNum *= -1; + } + return(randNum % max); +} + +int32_t PhysicalLayer::random(int32_t min, int32_t max) { + if(min >= max) { + return(min); + } + + return(PhysicalLayer::random(max - min) + min); +} + +uint8_t PhysicalLayer::randomByte() { + return(0); +} + +int16_t PhysicalLayer::startDirect() { + // disable encodings + int16_t state = setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + + // disable shaping + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + + // set frequency deviation to the lowest possible value + state = setFrequencyDeviation(-1); + return(state); +} + +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE +int16_t PhysicalLayer::available() { + return(this->bufferWritePos); +} + +void PhysicalLayer::dropSync() { + if(this->directSyncWordLen > 0) { + this->gotSync = false; + this->syncBuffer = 0; + } +} + +uint8_t PhysicalLayer::read(bool drop) { + if(drop) { + dropSync(); + } + this->bufferWritePos--; + return(this->buffer[this->bufferReadPos++]); +} + +int16_t PhysicalLayer::setDirectSyncWord(uint32_t syncWord, uint8_t len) { + if(len > 32) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + this->directSyncWordMask = 0xFFFFFFFF >> (32 - len); + this->directSyncWordLen = len; + this->directSyncWord = syncWord; + + // override sync word matching when length is set to 0 + if(this->directSyncWordLen == 0) { + this->gotSync = true; + } + + return(RADIOLIB_ERR_NONE); +} + +void PhysicalLayer::updateDirectBuffer(uint8_t bit) { + // check sync word + if(!this->gotSync) { + this->syncBuffer <<= 1; + this->syncBuffer |= bit; + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("S\t%lu", this->syncBuffer); + + if((this->syncBuffer & this->directSyncWordMask) == this->directSyncWord) { + this->gotSync = true; + this->bufferWritePos = 0; + this->bufferReadPos = 0; + this->bufferBitPos = 0; + } + + } else { + // save the bit + if(bit) { + this->buffer[this->bufferWritePos] |= 0x01 << this->bufferBitPos; + } else { + this->buffer[this->bufferWritePos] &= ~(0x01 << this->bufferBitPos); + } + this->bufferBitPos++; + + // check complete byte + if(this->bufferBitPos == 8) { + this->buffer[this->bufferWritePos] = Module::reflect(this->buffer[this->bufferWritePos], 8); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("R\t%X", this->buffer[this->bufferWritePos]); + + this->bufferWritePos++; + this->bufferBitPos = 0; + } + } +} + +void PhysicalLayer::setDirectAction(void (*func)(void)) { + (void)func; +} + +void PhysicalLayer::readBit(uint32_t pin) { + (void)pin; +} + +#endif + +int16_t PhysicalLayer::setDIOMapping(uint32_t pin, uint32_t value) { + (void)pin; + (void)value; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +void PhysicalLayer::setPacketReceivedAction(void (*func)(void)) { + (void)func; +} + +void PhysicalLayer::clearPacketReceivedAction() { + +} + +void PhysicalLayer::setPacketSentAction(void (*func)(void)) { + (void)func; +} + +void PhysicalLayer::clearPacketSentAction() { + +} + +void PhysicalLayer::setChannelScanAction(void (*func)(void)) { + (void)func; +} + +void PhysicalLayer::clearChannelScanAction() { + +} + +#if RADIOLIB_INTERRUPT_TIMING +void PhysicalLayer::setInterruptSetup(void (*func)(uint32_t)) { + Module* mod = getMod(); + mod->TimerSetupCb = func; +} + +void PhysicalLayer::setTimerFlag() { + Module* mod = getMod(); + mod->TimerFlag = true; +} +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/PhysicalLayer/PhysicalLayer.h b/lib/lib_rf/RadioLib/src/protocols/PhysicalLayer/PhysicalLayer.h new file mode 100644 index 000000000..173c2939a --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -0,0 +1,531 @@ +#if !defined(_RADIOLIB_PHYSICAL_LAYER_H) +#define _RADIOLIB_PHYSICAL_LAYER_H + +#include "../../TypeDef.h" +#include "../../Module.h" + +// data rate structure interpretation in case LoRa is used +struct LoRaRate_t { + uint8_t spreadingFactor; + float bandwidth; + uint8_t codingRate; +}; + +// data rate structure interpretation in case FSK is used +struct FSKRate_t { + float bitRate; + float freqDev; +}; + +// common data rate +union DataRate_t { + LoRaRate_t lora; + FSKRate_t fsk; +}; + +/*! + \class PhysicalLayer + + \brief Provides common interface for protocols that run on %LoRa/FSK modules, such as RTTY or LoRaWAN. + Also extracts some common module-independent methods. Using this interface class allows to use the protocols + on various modules without much code duplicity. Because this class is used mainly as interface, + all of its virtual members must be implemented in the module class. +*/ +class PhysicalLayer { + public: + + // constructor + + /*! + \brief Default constructor. + \param step Frequency step of the synthesizer in Hz. + \param maxLen Maximum length of packet that can be received by the module. + */ + PhysicalLayer(float step, size_t maxLen); + + // basic methods + + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Arduino Flash String transmit method. + \param str Pointer to Arduino Flash String that will be transmitted. + \param addr Node address to transmit the packet to. Only used in FSK mode. + \returns \ref status_codes + */ + int16_t transmit(__FlashStringHelper* fstr, uint8_t addr = 0); + + /*! + \brief Arduino String transmit method. + \param str Address of Arduino string that will be transmitted. + \param addr Node address to transmit the packet to. Only used in FSK mode. + \returns \ref status_codes + */ + int16_t transmit(String& str, uint8_t addr = 0); + #endif + + /*! + \brief C-string transmit method. + \param str C-string that will be transmitted. + \param addr Node address to transmit the packet to. Only used in FSK mode. + \returns \ref status_codes + */ + int16_t transmit(const char* str, uint8_t addr = 0); + + /*! + \brief Binary transmit method. Must be implemented in module class. + \param data Binary data that will be transmitted. + \param len Length of binary data to transmit (in bytes). + \param addr Node address to transmit the packet to. Only used in FSK mode. + \returns \ref status_codes + */ + virtual int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); + + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Arduino String receive method. + \param str Address of Arduino String to save the received data. + \param len Expected number of characters in the message. Leave as 0 if expecting a unknown size packet + \returns \ref status_codes + */ + int16_t receive(String& str, size_t len = 0); + #endif + + /*! + \brief Sets module to sleep. + \returns \ref status_codes + */ + virtual int16_t sleep(); + + /*! + \brief Sets module to standby. + \returns \ref status_codes + */ + virtual int16_t standby(); + + /*! + \brief Sets module to a specific standby mode. + \returns \ref status_codes + */ + virtual int16_t standby(uint8_t mode); + + /*! + \brief Sets module to received mode using its default configuration. + \returns \ref status_codes + */ + virtual int16_t startReceive(); + + /*! + \brief Interrupt-driven receive method. A DIO pin will be activated when full packet is received. + Must be implemented in module class. + \param timeout Raw timeout value. Some modules use this argument to specify operation mode + (single vs. continuous receive). + \param irqFlags Sets the IRQ flags. + \param irqMask Sets the mask of IRQ flags that will trigger the DIO pin. + \param len Packet length, needed for some modules under special circumstances (e.g. LoRa implicit header mode). + \returns \ref status_codes + */ + virtual int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + + /*! + \brief Binary receive method. Must be implemented in module class. + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \returns \ref status_codes + */ + virtual int16_t receive(uint8_t* data, size_t len); + + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Interrupt-driven Arduino String transmit method. Unlike the standard transmit method, this one is non-blocking. + Interrupt pin will be activated when transmission finishes. + \param str Address of Arduino String that will be transmitted. + \param addr Node address to transmit the packet to. Only used in FSK mode. + \returns \ref status_codes + */ + int16_t startTransmit(String& str, uint8_t addr = 0); + #endif + + /*! + \brief Interrupt-driven Arduino String transmit method. Unlike the standard transmit method, this one is non-blocking. + Interrupt pin will be activated when transmission finishes. + \param str C-string that will be transmitted. + \param addr Node address to transmit the packet to. Only used in FSK mode. + \returns \ref status_codes + */ + int16_t startTransmit(const char* str, uint8_t addr = 0); + + /*! + \brief Interrupt-driven binary transmit method. + \param data Binary data that will be transmitted. + \param len Length of binary data to transmit (in bytes). + \param addr Node address to transmit the packet to. Only used in FSK mode. + \returns \ref status_codes + */ + virtual int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0); + + /*! + \brief Clean up after transmission is done. + \returns \ref status_codes + */ + virtual int16_t finishTransmit(); + + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Reads data that was received after calling startReceive method. + \param str Address of Arduino String to save the received data. + \param len Expected number of characters in the message. When set to 0, the packet length will be retrieved + automatically. When more bytes than received are requested, only the number of bytes requested will be returned. + \returns \ref status_codes + */ + int16_t readData(String& str, size_t len = 0); + #endif + + /*! + \brief Reads data that was received after calling startReceive method. + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. + \returns \ref status_codes + */ + virtual int16_t readData(uint8_t* data, size_t len); + + /*! + \brief Enables direct transmission mode on pins DIO1 (clock) and DIO2 (data). Must be implemented in module class. + While in direct mode, the module will not be able to transmit or receive packets. Can only be activated in FSK mode. + \param frf 24-bit raw frequency value to start transmitting at. Required for quick frequency shifts in RTTY. + \returns \ref status_codes + */ + virtual int16_t transmitDirect(uint32_t frf = 0); + + /*! + \brief Enables direct reception mode on pins DIO1 (clock) and DIO2 (data). Must be implemented in module class. + While in direct mode, the module will not be able to transmit or receive packets. Can only be activated in FSK mode. + \returns \ref status_codes + */ + virtual int16_t receiveDirect(); + + // configuration methods + + /*! + \brief Sets carrier frequency. Must be implemented in module class. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + virtual int16_t setFrequency(float freq); + + /*! + \brief Sets FSK bit rate. Only available in FSK mode. Must be implemented in module class. + \param br Bit rate to be set (in kbps). + \returns \ref status_codes + */ + virtual int16_t setBitRate(float br); + + /*! + \brief Sets FSK frequency deviation from carrier frequency. Only available in FSK mode. + Must be implemented in module class. + \param freqDev Frequency deviation to be set (in kHz). + \returns \ref status_codes + */ + virtual int16_t setFrequencyDeviation(float freqDev); + + /*! + \brief Sets GFSK data shaping. Only available in FSK mode. Must be implemented in module class. + \param sh Shaping to be set. See \ref config_shaping for possible values. + \returns \ref status_codes + */ + virtual int16_t setDataShaping(uint8_t sh); + + /*! + \brief Sets FSK data encoding. Only available in FSK mode. Must be implemented in module class. + \param enc Encoding to be used. See \ref config_encoding for possible values. + \returns \ref status_codes + */ + virtual int16_t setEncoding(uint8_t encoding); + + /*! + \brief Set IQ inversion. Must be implemented in module class if the module supports it. + \param enable True to use inverted IQ, false for non-inverted. + \returns \ref status_codes + */ + virtual int16_t invertIQ(bool enable); + + /*! + \brief Set output power. Must be implemented in module class if the module supports it. + \param power Output power in dBm. The allowed range depends on the module used. + \returns \ref status_codes + */ + virtual int16_t setOutputPower(int8_t power); + + /*! + \brief Set sync word. Must be implemented in module class if the module supports it. + \param sync Pointer to the sync word. + \param len Sync word length in bytes. Maximum length depends on the module used. + \returns \ref status_codes + */ + virtual int16_t setSyncWord(uint8_t* sync, size_t len); + + /*! + \brief Set preamble length. Must be implemented in module class if the module supports it. + \param len Preamble length in bytes. Maximum length depends on the module used. + \returns \ref status_codes + */ + virtual int16_t setPreambleLength(size_t len); + + /*! + \brief Set data. Must be implemented in module class if the module supports it. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + virtual int16_t setDataRate(DataRate_t dr); + + /*! + \brief Check the data rate can be configured by this module. Must be implemented in module class if the module supports it. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + virtual int16_t checkDataRate(DataRate_t dr); + + /*! + \brief Gets the module frequency step size that was set in constructor. + \returns Synthesizer frequency step size in Hz. + */ + float getFreqStep() const; + + /*! + \brief Query modem for the packet length of received payload. Must be implemented in module class. + \param update Update received packet length. Will return cached value when set to false. + \returns Length of last received packet in bytes. + */ + virtual size_t getPacketLength(bool update = true); + + /*! + \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. + \returns RSSI of the last received packet in dBm. + */ + virtual float getRSSI(); + + /*! + \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem. + \returns SNR of the last received packet in dB. + */ + virtual float getSNR(); + + /*! + \brief Get expected time-on-air for a given size of payload + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + virtual uint32_t getTimeOnAir(size_t len); + + /*! + \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) + \param timeoutUs Timeout in microseconds to listen for + \returns Timeout value in a unit that is specific for the used module + */ + virtual uint32_t calculateRxTimeout(uint32_t timeoutUs); + + /*! + \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks + \param irqFlags The flags for which IRQs must be triggered + \param irqMask Mask indicating which IRQ triggers a DIO + \returns \ref status_codes + */ + virtual int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask); + + /*! + \brief Check whether the IRQ bit for RxTimeout is set + \returns \ref RxTimeout IRQ is set + */ + virtual bool isRxTimeout(); + + /*! + \brief Interrupt-driven channel activity detection method. interrupt will be activated + when packet is detected. Must be implemented in module class. + \returns \ref status_codes + */ + virtual int16_t startChannelScan(); + + /*! + \brief Read the channel scan result + \returns \ref status_codes + */ + virtual int16_t getChannelScanResult(); + + /*! + \brief Check whether the current communication channel is free or occupied. Performs CAD for LoRa modules, + or RSSI measurement for FSK modules. + \returns RADIOLIB_CHANNEL_FREE when channel is free, + RADIOLIB_PREAMBLE_DETECTEDwhen occupied or other \ref status_codes. + */ + virtual int16_t scanChannel(); + + /*! + \brief Get truly random number in range 0 - max. + \param max The maximum value of the random number (non-inclusive). + \returns Random number. + */ + int32_t random(int32_t max); + + /*! + \brief Get truly random number in range min - max. + \param min The minimum value of the random number (inclusive). + \param max The maximum value of the random number (non-inclusive). + \returns Random number. + */ + int32_t random(int32_t min, int32_t max); + + /*! + \brief Get one truly random byte from RSSI noise. Must be implemented in module class. + \returns TRNG byte. + */ + virtual uint8_t randomByte(); + + /*! + \brief Configure module parameters for direct modes. Must be called prior to "ham" modes like RTTY or AX.25. + Only available in FSK mode. + \returns \ref status_codes + */ + int16_t startDirect(); + + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE + /*! + \brief Set sync word to be used to determine start of packet in direct reception mode. + \param syncWord Sync word bits. + \param len Sync word length in bits. Set to zero to disable sync word matching. + \returns \ref status_codes + */ + int16_t setDirectSyncWord(uint32_t syncWord, uint8_t len); + + /*! + \brief Set interrupt service routine function to call when data bit is received in direct mode. + Must be implemented in module class. + \param func Pointer to interrupt service routine. + */ + virtual void setDirectAction(void (*func)(void)); + + /*! + \brief Function to read and process data bit in direct reception mode. Must be implemented in module class. + \param pin Pin on which to read. + */ + virtual void readBit(uint32_t pin); + + /*! + \brief Get the number of direct mode bytes currently available in buffer. + \returns Number of available bytes. + */ + int16_t available(); + + /*! + \brief Forcefully drop synchronization. + */ + void dropSync(); + + /*! + \brief Get data from direct mode buffer. + \param drop Drop synchronization on read - next reading will require waiting for the sync word again. + Defaults to true. + \returns Byte from direct mode buffer. + */ + uint8_t read(bool drop = true); + #endif + + /*! + \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). + \param pin Pin number onto which a signal is to be placed. + \param value The value that indicates which function to place on that pin. See chip datasheet for details. + \returns \ref status_codes + */ + virtual int16_t setDIOMapping(uint32_t pin, uint32_t value); + + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + virtual void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + virtual void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + virtual void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + virtual void clearPacketSentAction(); + + /*! + \brief Sets interrupt service routine to call when a channel scan is finished. + \param func ISR to call. + */ + virtual void setChannelScanAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a channel scan is finished. + */ + virtual void clearChannelScanAction(); + + #if RADIOLIB_INTERRUPT_TIMING + + /*! + \brief Set function to be called to set up the timing interrupt. + For details, see https://github.com/jgromes/RadioLib/wiki/Interrupt-Based-Timing + \param func Setup function to be called, with one argument (pulse length in microseconds). + */ + void setInterruptSetup(void (*func)(uint32_t)); + + /*! + \brief Set timing interrupt flag. + For details, see https://github.com/jgromes/RadioLib/wiki/Interrupt-Based-Timing + */ + void setTimerFlag(); + + #endif + +#if !RADIOLIB_GODMODE + protected: +#endif +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE + void updateDirectBuffer(uint8_t bit); +#endif + +#if !RADIOLIB_GODMODE + private: +#endif + float freqStep; + size_t maxPacketLength; + + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE + uint8_t bufferBitPos; + uint8_t bufferWritePos; + uint8_t bufferReadPos; + uint8_t buffer[RADIOLIB_STATIC_ARRAY_SIZE]; + uint32_t syncBuffer; + uint32_t directSyncWord; + uint8_t directSyncWordLen; + uint32_t directSyncWordMask; + bool gotSync; + #endif + + virtual Module* getMod() = 0; + + // allow specific classes access the private getMod method + friend class AFSKClient; + friend class RTTYClient; + friend class MorseClient; + friend class HellClient; + friend class SSTVClient; + friend class AX25Client; + friend class FSK4Client; + friend class PagerClient; + friend class BellClient; + friend class FT8Client; + friend class LoRaWANNode; +}; + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/Print/ITA2String.cpp b/lib/lib_rf/RadioLib/src/protocols/Print/ITA2String.cpp new file mode 100644 index 000000000..4f2d99a7c --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/Print/ITA2String.cpp @@ -0,0 +1,113 @@ +#include "ITA2String.h" + +#include + +ITA2String::ITA2String(char c) { + asciiLen = 1; + #if !RADIOLIB_STATIC_ONLY + strAscii = new char[1]; + #endif + strAscii[0] = c; + ita2Len = 0; +} + +ITA2String::ITA2String(const char* str) { + asciiLen = strlen(str); + #if !RADIOLIB_STATIC_ONLY + strAscii = new char[asciiLen + 1]; + #endif + strcpy(strAscii, str); + ita2Len = 0; +} + +ITA2String::~ITA2String() { + #if !RADIOLIB_STATIC_ONLY + delete[] strAscii; + #endif +} + +size_t ITA2String::length() { + // length returned by this method is different than the length of ASCII-encoded strAscii + // ITA2-encoded string length varies based on how many number and characters the string contains + + if(ita2Len == 0) { + // ITA2 length wasn't calculated yet, call byteArr() to calculate it + byteArr(); + } + + return(ita2Len); +} + +uint8_t* ITA2String::byteArr() { + // create temporary array 2x the string length (figures may be 3 bytes) + #if RADIOLIB_STATIC_ONLY + uint8_t temp[RADIOLIB_STATIC_ARRAY_SIZE*2 + 1]; + #else + uint8_t* temp = new uint8_t[asciiLen*2 + 1]; + #endif + + size_t arrayLen = 0; + bool flagFigure = false; + for(size_t i = 0; i < asciiLen; i++) { + uint16_t code = getBits(strAscii[i]); + uint8_t shift = (code >> 5) & 0b11111; + uint8_t character = code & 0b11111; + // check if the code is letter or figure + if(shift == RADIOLIB_ITA2_FIGS) { + // check if this is the first figure in sequence + if(!flagFigure) { + flagFigure = true; + temp[arrayLen++] = RADIOLIB_ITA2_FIGS; + } + + // add the character code + temp[arrayLen++] = character & 0b11111; + + // check the following character (skip for message end) + if(i < (asciiLen - 1)) { + uint16_t nextCode = getBits(strAscii[i+1]); + uint8_t nextShift = (nextCode >> 5) & 0b11111; + if(nextShift == RADIOLIB_ITA2_LTRS) { + // next character is a letter, terminate figure shift + temp[arrayLen++] = RADIOLIB_ITA2_LTRS; + flagFigure = false; + } + } else { + // reached the end of the message, terminate figure shift + temp[arrayLen++] = RADIOLIB_ITA2_LTRS; + flagFigure = false; + } + } else { + temp[arrayLen++] = character & 0b11111; + } + } + + // save ITA2 string length + ita2Len = arrayLen; + + uint8_t* arr = new uint8_t[arrayLen]; + memcpy(arr, temp, arrayLen); + #if !RADIOLIB_STATIC_ONLY + delete[] temp; + #endif + + return(arr); +} + +uint16_t ITA2String::getBits(char c) { + // search ITA2 table + uint16_t code = 0x0000; + for(uint8_t i = 0; i < RADIOLIB_ITA2_LENGTH; i++) { + if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][0]) == c) { + // character is in letter shift + code = (RADIOLIB_ITA2_LTRS << 5) | i; + break; + } else if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][1]) == c) { + // character is in figures shift + code = (RADIOLIB_ITA2_FIGS << 5) | i; + break; + } + } + + return(code); +} diff --git a/lib/lib_rf/RadioLib/src/protocols/Print/ITA2String.h b/lib/lib_rf/RadioLib/src/protocols/Print/ITA2String.h new file mode 100644 index 000000000..579bb1c48 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/Print/ITA2String.h @@ -0,0 +1,70 @@ +#if !defined(_RADIOLIB_ITA2_STRING_H) +#define _RADIOLIB_ITA2_STRING_H + +#include "../../TypeDef.h" + +#define RADIOLIB_ITA2_FIGS 0x1B +#define RADIOLIB_ITA2_LTRS 0x1F +#define RADIOLIB_ITA2_LENGTH 32 + +// ITA2 character table: - position in array corresponds to 5-bit ITA2 code +// - characters to the left are in letters shift, characters to the right in figures shift +// - characters marked 0x7F do not have ASCII equivalent +static const char ITA2Table[RADIOLIB_ITA2_LENGTH][2] RADIOLIB_NONVOLATILE = { + {'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'}, + {'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('}, + {'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'}, + {'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F} +}; + +/*! + \class ITA2String + \brief ITA2-encoded string. +*/ +class ITA2String { + public: + /*! + \brief Default single-character constructor. + \param c ASCII-encoded character to encode as ITA2. + */ + ITA2String(char c); + + /*! + \brief Default string constructor. + \param str ASCII-encoded string to encode as ITA2. + */ + ITA2String(const char* str); + + /*! + \brief Default destructor. + */ + ~ITA2String(); + + /*! + \brief Gets the length of the ITA2 string. This number is not the same as the length of ASCII-encoded string! + \returns Length of ITA2-encoded string. + */ + size_t length(); + + /*! + \brief Gets the ITA2 representation of the ASCII string set in constructor. + \returns Pointer to dynamically allocated array, which contains ITA2-encoded bytes. + It is the caller's responsibility to deallocate this memory! + */ + uint8_t* byteArr(); + +#if !RADIOLIB_GODMODE + private: +#endif + #if RADIOLIB_STATIC_ONLY + char strAscii[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + char* strAscii; + #endif + size_t asciiLen; + size_t ita2Len; + + static uint16_t getBits(char c); +}; + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/Print/Print.cpp b/lib/lib_rf/RadioLib/src/protocols/Print/Print.cpp new file mode 100644 index 000000000..94b7b3345 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/Print/Print.cpp @@ -0,0 +1,312 @@ +#include "Print.h" + +#include +#include + +size_t RadioLibPrint::print(ITA2String& ita2) { + uint8_t enc = this->encoding; + this->encoding = RADIOLIB_ITA2; + uint8_t* arr = ita2.byteArr(); + size_t n = write(arr, ita2.length()); + delete[] arr; + this->encoding = enc; + return(n); +} + +size_t RadioLibPrint::println(ITA2String& ita2) { + size_t n = RadioLibPrint::print(ita2); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::write(const uint8_t *buffer, size_t size) { + size_t n = 0; + while (size--) { + if (write(*buffer++)) n++; + else break; + } + return n; +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +size_t RadioLibPrint::print(const __FlashStringHelper* fstr) { + // read flash string length + size_t len = 0; + RADIOLIB_NONVOLATILE_PTR p = reinterpret_cast(fstr); + while(true) { + char c = RADIOLIB_NONVOLATILE_READ_BYTE(p++); + len++; + if(c == '\0') { + break; + } + } + + // dynamically allocate memory + #if RADIOLIB_STATIC_ONLY + char str[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + char* str = new char[len]; + #endif + + // copy string from flash + p = reinterpret_cast(fstr); + for(size_t i = 0; i < len; i++) { + str[i] = RADIOLIB_NONVOLATILE_READ_BYTE(p + i); + } + + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(str); + n = RadioLibPrint::print(ita2); + } else { + n = write((uint8_t*)str, len); + } + #if !RADIOLIB_STATIC_ONLY + delete[] str; + #endif + return(n); +} + +size_t RadioLibPrint::print(const String& str) { + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(str.c_str()); + n = RadioLibPrint::print(ita2); + } else { + n = write((uint8_t*)str.c_str(), str.length()); + } + return(n); +} + +size_t RadioLibPrint::println(const __FlashStringHelper* fstr) { + size_t n = RadioLibPrint::print(fstr); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(const String& str) { + size_t n = RadioLibPrint::print(str); + n += RadioLibPrint::println(); + return(n); +} +#endif + +size_t RadioLibPrint::print(const char str[]) { + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(str); + n = RadioLibPrint::print(ita2); + } else { + n = write((uint8_t*)str, strlen(str)); + } + return(n); +} + +size_t RadioLibPrint::print(char c) { + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(c); + n = RadioLibPrint::print(ita2); + } else { + n = write(c); + } + return(n); +} + +size_t RadioLibPrint::print(unsigned char b, int base) { + return(RadioLibPrint::print((unsigned long)b, base)); +} + +size_t RadioLibPrint::print(int n, int base) { + return(RadioLibPrint::print((long)n, base)); +} + +size_t RadioLibPrint::print(unsigned int n, int base) { + return(RadioLibPrint::print((unsigned long)n, base)); +} + +size_t RadioLibPrint::print(long n, int base) { + if(base == 0) { + return(write(n)); + } else if(base == DEC) { + if (n < 0) { + int t = RadioLibPrint::print('-'); + n = -n; + return(RadioLibPrint::printNumber(n, DEC) + t); + } + return(RadioLibPrint::printNumber(n, DEC)); + } else { + return(RadioLibPrint::printNumber(n, base)); + } +} + +size_t RadioLibPrint::print(unsigned long n, int base) { + if(base == 0) { + return(write(n)); + } else { + return(RadioLibPrint::printNumber(n, base)); + } +} + +size_t RadioLibPrint::print(double n, int digits) { + return(RadioLibPrint::printFloat(n, digits)); +} + +size_t RadioLibPrint::println(const char* str) { + size_t n = RadioLibPrint::print(str); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(char c) { + size_t n = RadioLibPrint::print(c); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(unsigned char b, int base) { + size_t n = RadioLibPrint::print(b, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(int num, int base) { + size_t n = RadioLibPrint::print(num, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(unsigned int num, int base) { + size_t n = RadioLibPrint::print(num, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(long num, int base) { + size_t n = RadioLibPrint::print(num, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(unsigned long num, int base) { + size_t n = RadioLibPrint::print(num, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(double d, int digits) { + size_t n = RadioLibPrint::print(d, digits); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(void) { + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String lf = ITA2String("\r\n"); + n = RadioLibPrint::print(lf); + } else { + n = write("\r\n"); + } + return(n); +} + +size_t RadioLibPrint::printNumber(unsigned long n, uint8_t base) { + char buf[8 * sizeof(long) + 1]; + char *str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + if(base < 2) { + base = 10; + } + + do { + char c = n % base; + n /= base; + + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); + + size_t l = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(str); + uint8_t* arr = ita2.byteArr(); + l = write(arr, ita2.length()); + delete[] arr; + } else { + l = write(str); + } + + return(l); +} + +/// \todo improve ITA2 float print speed (characters are sent one at a time) +size_t RadioLibPrint::printFloat(double number, uint8_t digits) { + size_t n = 0; + + char code[] = {0x00, 0x00, 0x00, 0x00}; + if (isnan(number)) strcpy(code, "nan"); + if (isinf(number)) strcpy(code, "inf"); + if (number > 4294967040.0) strcpy(code, "ovf"); // constant determined empirically + if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically + + if(code[0] != 0x00) { + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(code); + uint8_t* arr = ita2.byteArr(); + n = write(arr, ita2.length()); + delete[] arr; + return(n); + } else { + return(write(code)); + } + } + + // Handle negative numbers + if (number < 0.0) { + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String("-"); + uint8_t* arr = ita2.byteArr(); + n += write(arr, ita2.length()); + delete[] arr; + } else { + n += RadioLibPrint::print('-'); + } + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for(uint8_t i = 0; i < digits; ++i) { + rounding /= 10.0; + } + number += rounding; + + // Extract the integer part of the number and print it + unsigned long int_part = (unsigned long)number; + double remainder = number - (double)int_part; + n += RadioLibPrint::print(int_part); + + // Print the decimal point, but only if there are digits beyond + if(digits > 0) { + if(encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String("."); + uint8_t* arr = ita2.byteArr(); + n += write(arr, ita2.length()); + delete[] arr; + } else { + n += RadioLibPrint::print('.'); + } + } + + // Extract digits from the remainder one at a time + while(digits-- > 0) { + remainder *= 10.0; + unsigned int toPrint = (unsigned int)(remainder); + n += RadioLibPrint::print(toPrint); + remainder -= toPrint; + } + + return n; +} diff --git a/lib/lib_rf/RadioLib/src/protocols/Print/Print.h b/lib/lib_rf/RadioLib/src/protocols/Print/Print.h new file mode 100644 index 000000000..48bd7e702 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/Print/Print.h @@ -0,0 +1,67 @@ +#if !defined(_RADIOLIB_PRINT_H) +#define _RADIOLIB_PRINT_H + +#include + +#include "ITA2String.h" + +// supported encoding schemes +#define RADIOLIB_ASCII 0 +#define RADIOLIB_ASCII_EXTENDED 1 +#define RADIOLIB_ITA2 2 + +// based on Arduino Print class +class RadioLibPrint { + public: + virtual size_t write(uint8_t) = 0; + size_t write(const char *str) { + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); + } + virtual size_t write(const uint8_t *buffer, size_t size); + size_t write(const char *buffer, size_t size) { + return write((const uint8_t *)buffer, size); + } + + size_t print(ITA2String& ita2); + size_t println(ITA2String& ita2); + + #if defined(RADIOLIB_BUILD_ARDUINO) + size_t print(const __FlashStringHelper *); + size_t print(const String &); + + size_t println(const __FlashStringHelper *); + size_t println(const String &); + #endif + + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); + + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + size_t println(void); + +#if !RADIOLIB_GODMODE + protected: +#endif + uint8_t encoding = RADIOLIB_ASCII_EXTENDED; + const char* lineFeed; + + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); + +}; + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/RTTY/RTTY.cpp b/lib/lib_rf/RadioLib/src/protocols/RTTY/RTTY.cpp new file mode 100644 index 000000000..c823fb280 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/RTTY/RTTY.cpp @@ -0,0 +1,127 @@ +#include "RTTY.h" + +#include + +#if !RADIOLIB_EXCLUDE_RTTY + +RTTYClient::RTTYClient(PhysicalLayer* phy) { + phyLayer = phy; + lineFeed = "\r\n"; + #if !RADIOLIB_EXCLUDE_AFSK + audioClient = nullptr; + #endif +} + +#if !RADIOLIB_EXCLUDE_AFSK +RTTYClient::RTTYClient(AFSKClient* audio) { + phyLayer = audio->phyLayer; + lineFeed = "\r\n"; + audioClient = audio; +} +#endif + +int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc, uint8_t stopBits) { + // save configuration + RadioLibPrint::encoding = enc; + stopBitsNum = stopBits; + baseFreqHz = base; + shiftFreqHz = shift; + + // calculate duration of 1 bit + bitDuration = (uint32_t)1000000/rate; + + // calculate module carrier frequency resolution + uint32_t step = round(phyLayer->getFreqStep()); + + // check minimum shift value + if(shift < step / 2) { + return(RADIOLIB_ERR_INVALID_RTTY_SHIFT); + } + + // round shift to multiples of frequency step size + if(shift % step < (step / 2)) { + shiftFreq = shift / step; + } else { + shiftFreq = (shift / step) + 1; + } + + // calculate 24-bit frequency + baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); + + // configure for direct mode + return(phyLayer->startDirect()); +} + +void RTTYClient::idle() { + mark(); +} + +size_t RTTYClient::write(uint8_t b) { + uint8_t dataBitsNum = 0; + switch(RadioLibPrint::encoding) { + case RADIOLIB_ASCII: + dataBitsNum = 7; + break; + case RADIOLIB_ASCII_EXTENDED: + dataBitsNum = 8; + break; + case RADIOLIB_ITA2: + dataBitsNum = 5; + break; + default: + return(0); + } + space(); + + uint16_t maxDataMask = 0x01 << (dataBitsNum - 1); + for(uint16_t mask = 0x01; mask <= maxDataMask; mask <<= 1) { + if(b & mask) { + mark(); + } else { + space(); + } + } + + for(uint8_t i = 0; i < stopBitsNum; i++) { + mark(); + } + + return(1); +} + +void RTTYClient::mark() { + Module* mod = phyLayer->getMod(); + uint32_t start = mod->hal->micros(); + transmitDirect(baseFreq + shiftFreq, baseFreqHz + shiftFreqHz); + mod->waitForMicroseconds(start, bitDuration); +} + +void RTTYClient::space() { + Module* mod = phyLayer->getMod(); + uint32_t start = mod->hal->micros(); + transmitDirect(baseFreq, baseFreqHz); + mod->waitForMicroseconds(start, bitDuration); +} + +int16_t RTTYClient::transmitDirect(uint32_t freq, uint32_t freqHz) { + #if !RADIOLIB_EXCLUDE_AFSK + if(audioClient != nullptr) { + return(audioClient->tone(freqHz)); + } + #endif + return(phyLayer->transmitDirect(freq)); +} + +int16_t RTTYClient::standby() { + // ensure everything is stopped in interrupt timing mode + Module* mod = phyLayer->getMod(); + mod->waitForMicroseconds(0, 0); + #if !RADIOLIB_EXCLUDE_AFSK + if(audioClient != nullptr) { + return(audioClient->noTone()); + } + #endif + return(phyLayer->standby()); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/RTTY/RTTY.h b/lib/lib_rf/RadioLib/src/protocols/RTTY/RTTY.h new file mode 100644 index 000000000..4da4ca631 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/RTTY/RTTY.h @@ -0,0 +1,85 @@ +#if !defined(_RADIOLIB_RTTY_H) +#define _RADIOLIB_RTTY_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_RTTY + +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" +#include "../Print/Print.h" +#include "../Print/ITA2String.h" + +/*! + \class RTTYClient + \brief Client for RTTY communication. The public interface is the same as Arduino Serial. +*/ +class RTTYClient: public RadioLibPrint { + public: + /*! + \brief Constructor for 2-FSK mode. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + */ + explicit RTTYClient(PhysicalLayer* phy); + + #if !RADIOLIB_EXCLUDE_AFSK + /*! + \brief Constructor for AFSK mode. + \param audio Pointer to the AFSK instance providing audio. + */ + explicit RTTYClient(AFSKClient* audio); + #endif + + // basic methods + + /*! + \brief Initialization method. + \param base Base (space) frequency to be used in MHz (in 2-FSK mode), or the space tone frequency in Hz (in AFSK mode) + \param shift Frequency shift between mark and space in Hz. + \param rate Baud rate to be used during transmission. + \param enc Encoding to be used. Defaults to ASCII. + \param stopBits Number of stop bits to be used. + \returns \ref status_codes + */ + int16_t begin(float base, uint32_t shift, uint16_t rate, uint8_t enc = RADIOLIB_ASCII, uint8_t stopBits = 1); + + /*! + \brief Send out idle condition (RF tone at mark frequency). + */ + void idle(); + + /*! + \brief Stops transmitting. + \returns \ref status_codes + */ + int16_t standby(); + + /*! + \brief Write one byte. Implementation of interface of the RadioLibPrint/Print class. + \param b Byte to write. + \returns 1 if the byte was written, 0 otherwise. + */ + size_t write(uint8_t b); + +#if !RADIOLIB_GODMODE + private: +#endif + PhysicalLayer* phyLayer; + #if !RADIOLIB_EXCLUDE_AFSK + AFSKClient* audioClient; + #endif + + uint32_t baseFreq = 0, baseFreqHz = 0; + uint32_t shiftFreq = 0, shiftFreqHz = 0; + uint32_t bitDuration = 0; + uint8_t stopBitsNum = 0; + + void mark(); + void space(); + + int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/SSTV/SSTV.cpp b/lib/lib_rf/RadioLib/src/protocols/SSTV/SSTV.cpp new file mode 100644 index 000000000..b06df2975 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/SSTV/SSTV.cpp @@ -0,0 +1,307 @@ +#include "SSTV.h" +#if !RADIOLIB_EXCLUDE_SSTV + +const SSTVMode_t Scottie1 { + .visCode = RADIOLIB_SSTV_SCOTTIE_1, + .width = 320, + .height = 256, + .scanPixelLen = 432, + .numTones = 7, + .tones = { + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 } + } +}; + +const SSTVMode_t Scottie2 { + .visCode = RADIOLIB_SSTV_SCOTTIE_2, + .width = 320, + .height = 256, + .scanPixelLen = 275, + .numTones = 7, + .tones = { + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 } + } +}; + +const SSTVMode_t ScottieDX { + .visCode = RADIOLIB_SSTV_SCOTTIE_DX, + .width = 320, + .height = 256, + .scanPixelLen = 1080, + .numTones = 7, + .tones = { + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 } + } +}; + +const SSTVMode_t Martin1 { + .visCode = RADIOLIB_SSTV_MARTIN_1, + .width = 320, + .height = 256, + .scanPixelLen = 458, + .numTones = 8, + .tones = { + { .type = tone_t::GENERIC, .len = 4862, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 } + } +}; + +const SSTVMode_t Martin2 { + .visCode = RADIOLIB_SSTV_MARTIN_2, + .width = 320, + .height = 256, + .scanPixelLen = 229, + .numTones = 8, + .tones = { + { .type = tone_t::GENERIC, .len = 4862, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 } + } +}; + +const SSTVMode_t Wrasse { + .visCode = RADIOLIB_SSTV_WRASSE_SC2_180, + .width = 320, + .height = 256, + .scanPixelLen = 734, + .numTones = 5, + .tones = { + { .type = tone_t::GENERIC, .len = 5523, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 500, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 } + } +}; + +const SSTVMode_t PasokonP3 { + .visCode = RADIOLIB_SSTV_PASOKON_P3, + .width = 640, + .height = 496, + .scanPixelLen = 208, + .numTones = 7, + .tones = { + { .type = tone_t::GENERIC, .len = 5208, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1042, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1042, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1042, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 } + } +}; + +const SSTVMode_t PasokonP5 { + .visCode = RADIOLIB_SSTV_PASOKON_P5, + .width = 640, + .height = 496, + .scanPixelLen = 312, + .numTones = 7, + .tones = { + { .type = tone_t::GENERIC, .len = 7813, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1563, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1563, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1563, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 } + } +}; + +const SSTVMode_t PasokonP7 { + .visCode = RADIOLIB_SSTV_PASOKON_P7, + .width = 640, + .height = 496, + .scanPixelLen = 417, + .numTones = 7, + .tones = { + { .type = tone_t::GENERIC, .len = 10417, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 2083, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 2083, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 2083, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 } + } +}; + +SSTVClient::SSTVClient(PhysicalLayer* phy) { + phyLayer = phy; + #if !RADIOLIB_EXCLUDE_AFSK + audioClient = nullptr; + #endif +} + +#if !RADIOLIB_EXCLUDE_AFSK +SSTVClient::SSTVClient(AFSKClient* audio) { + phyLayer = audio->phyLayer; + audioClient = audio; +} +#endif + +#if !RADIOLIB_EXCLUDE_AFSK +int16_t SSTVClient::begin(const SSTVMode_t& mode) { + if(audioClient == nullptr) { + // this initialization method can only be used in AFSK mode + return(RADIOLIB_ERR_WRONG_MODEM); + } + + return(begin(0, mode)); +} +#endif + +int16_t SSTVClient::begin(float base, const SSTVMode_t& mode) { + // save mode + txMode = mode; + + // calculate 24-bit frequency + baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); + + // configure for direct mode + return(phyLayer->startDirect()); +} + +int16_t SSTVClient::setCorrection(float correction) { + // check if mode is initialized + if(txMode.visCode == 0) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // apply correction factor to all timings + txMode.scanPixelLen *= correction; + for(uint8_t i = 0; i < txMode.numTones; i++) { + txMode.tones[i].len *= correction; + } + return(RADIOLIB_ERR_NONE); +} + +void SSTVClient::idle() { + phyLayer->transmitDirect(); + this->tone(RADIOLIB_SSTV_TONE_LEADER); +} + +void SSTVClient::sendHeader() { + // save first header flag for Scottie modes + firstLine = true; + phyLayer->transmitDirect(); + + // send the first part of header (leader-break-leader) + this->tone(RADIOLIB_SSTV_TONE_LEADER, RADIOLIB_SSTV_HEADER_LEADER_LENGTH); + this->tone(RADIOLIB_SSTV_TONE_BREAK, RADIOLIB_SSTV_HEADER_BREAK_LENGTH); + this->tone(RADIOLIB_SSTV_TONE_LEADER, RADIOLIB_SSTV_HEADER_LEADER_LENGTH); + + // VIS start bit + this->tone(RADIOLIB_SSTV_TONE_BREAK, RADIOLIB_SSTV_HEADER_BIT_LENGTH); + + // VIS code + uint8_t parityCount = 0; + for(uint8_t mask = 0x01; mask < 0x80; mask <<= 1) { + if(txMode.visCode & mask) { + this->tone(RADIOLIB_SSTV_TONE_VIS_1, RADIOLIB_SSTV_HEADER_BIT_LENGTH); + parityCount++; + } else { + this->tone(RADIOLIB_SSTV_TONE_VIS_0, RADIOLIB_SSTV_HEADER_BIT_LENGTH); + } + } + + // VIS parity + if(parityCount % 2 == 0) { + // even parity + this->tone(RADIOLIB_SSTV_TONE_VIS_0, RADIOLIB_SSTV_HEADER_BIT_LENGTH); + } else { + // odd parity + this->tone(RADIOLIB_SSTV_TONE_VIS_1, RADIOLIB_SSTV_HEADER_BIT_LENGTH); + } + + // VIS stop bit + this->tone(RADIOLIB_SSTV_TONE_BREAK, RADIOLIB_SSTV_HEADER_BIT_LENGTH); +} + +void SSTVClient::sendLine(uint32_t* imgLine) { + // check first line flag in Scottie modes + if(firstLine && ((txMode.visCode == RADIOLIB_SSTV_SCOTTIE_1) || (txMode.visCode == RADIOLIB_SSTV_SCOTTIE_2) || (txMode.visCode == RADIOLIB_SSTV_SCOTTIE_DX))) { + firstLine = false; + + // send start sync tone + this->tone(RADIOLIB_SSTV_TONE_BREAK, 9000); + } + + // send all tones in sequence + for(uint8_t i = 0; i < txMode.numTones; i++) { + if((txMode.tones[i].type == tone_t::GENERIC) && (txMode.tones[i].len > 0)) { + // sync/porch tones + this->tone(txMode.tones[i].freq, txMode.tones[i].len); + } else { + // scan lines + for(uint16_t j = 0; j < txMode.width; j++) { + uint32_t color = imgLine[j]; + switch(txMode.tones[i].type) { + case(tone_t::SCAN_RED): + color &= 0x00FF0000; + color >>= 16; + break; + case(tone_t::SCAN_GREEN): + color &= 0x0000FF00; + color >>= 8; + break; + case(tone_t::SCAN_BLUE): + color &= 0x000000FF; + break; + case(tone_t::GENERIC): + break; + } + this->tone(RADIOLIB_SSTV_TONE_BRIGHTNESS_MIN + ((float)color * 3.1372549), txMode.scanPixelLen); + } + } + } +} + +uint16_t SSTVClient::getPictureHeight() const { + return(txMode.height); +} + +void SSTVClient::tone(float freq, uint32_t len) { + Module* mod = phyLayer->getMod(); + uint32_t start = mod->hal->micros(); + #if !RADIOLIB_EXCLUDE_AFSK + if(audioClient != nullptr) { + audioClient->tone(freq, false); + } else { + phyLayer->transmitDirect(baseFreq + (freq / phyLayer->getFreqStep())); + } + #else + phyLayer->transmitDirect(baseFreq + (freq / phyLayer->getFreqStep())); + #endif + mod->waitForMicroseconds(start, len); +} + +#endif diff --git a/lib/lib_rf/RadioLib/src/protocols/SSTV/SSTV.h b/lib/lib_rf/RadioLib/src/protocols/SSTV/SSTV.h new file mode 100644 index 000000000..986dd0cbb --- /dev/null +++ b/lib/lib_rf/RadioLib/src/protocols/SSTV/SSTV.h @@ -0,0 +1,202 @@ +#if !defined(_RADIOLIB_SSTV_H) +#define _RADIOLIB_SSTV_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SSTV + +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" + +// the following implementation is based on information from +// http://www.barberdsp.com/downloads/Dayton%20Paper.pdf + +// VIS codes +#define RADIOLIB_SSTV_SCOTTIE_1 60 +#define RADIOLIB_SSTV_SCOTTIE_2 56 +#define RADIOLIB_SSTV_SCOTTIE_DX 76 +#define RADIOLIB_SSTV_MARTIN_1 44 +#define RADIOLIB_SSTV_MARTIN_2 40 +#define RADIOLIB_SSTV_WRASSE_SC2_180 55 +#define RADIOLIB_SSTV_PASOKON_P3 113 +#define RADIOLIB_SSTV_PASOKON_P5 114 +#define RADIOLIB_SSTV_PASOKON_P7 115 + +// SSTV tones in Hz +#define RADIOLIB_SSTV_TONE_LEADER 1900 +#define RADIOLIB_SSTV_TONE_BREAK 1200 +#define RADIOLIB_SSTV_TONE_VIS_1 1100 +#define RADIOLIB_SSTV_TONE_VIS_0 1300 +#define RADIOLIB_SSTV_TONE_BRIGHTNESS_MIN 1500 +#define RADIOLIB_SSTV_TONE_BRIGHTNESS_MAX 2300 + +// calibration header timing in us +#define RADIOLIB_SSTV_HEADER_LEADER_LENGTH 300000 +#define RADIOLIB_SSTV_HEADER_BREAK_LENGTH 10000 +#define RADIOLIB_SSTV_HEADER_BIT_LENGTH 30000 + +/*! + \struct tone_t + \brief Structure to save data about tone. +*/ +struct tone_t { + + /*! + \brief Tone type: GENERIC for sync and porch tones, SCAN_GREEN, SCAN_BLUE and SCAN_RED for scan lines. + */ + enum { + GENERIC = 0, + SCAN_GREEN, + SCAN_BLUE, + SCAN_RED + } type; + + /*! + \brief Length of tone in us, set to 0 for picture scan tones. + */ + uint32_t len; + + /*! + \brief Frequency of tone in Hz, set to 0 for picture scan tones. + */ + uint16_t freq; +}; + +/*! + \struct SSTVMode_t + \brief Structure to save data about supported SSTV modes. +*/ +struct SSTVMode_t { + + /*! + \brief Unique VIS code of the SSTV mode. + */ + uint8_t visCode; + + /*! + \brief Picture width in pixels. + */ + uint16_t width; + + /*! + \brief Picture height in pixels. + */ + uint16_t height; + + /*! + \brief Pixel scan length in us. + */ + uint16_t scanPixelLen; + + /*! + \brief Number of tones in each transmission line. Picture scan data is considered single tone. + */ + uint8_t numTones; + + /*! + \brief Sequence of tones in each transmission line. This is used to create the correct encoding sequence. + */ + tone_t tones[8]; +}; + +// all currently supported SSTV modes +extern const SSTVMode_t Scottie1; +extern const SSTVMode_t Scottie2; +extern const SSTVMode_t ScottieDX; +extern const SSTVMode_t Martin1; +extern const SSTVMode_t Martin2; +extern const SSTVMode_t Wrasse; +extern const SSTVMode_t PasokonP3; +extern const SSTVMode_t PasokonP5; +extern const SSTVMode_t PasokonP7; + +/*! + \class SSTVClient + \brief Client for SSTV transmissions. +*/ +class SSTVClient { + public: + /*! + \brief Constructor for 2-FSK mode. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + */ + explicit SSTVClient(PhysicalLayer* phy); + + #if !RADIOLIB_EXCLUDE_AFSK + /*! + \brief Constructor for AFSK mode. + \param audio Pointer to the AFSK instance providing audio. + */ + explicit SSTVClient(AFSKClient* audio); + #endif + + // basic methods + + /*! + \brief Initialization method for 2-FSK. + \param base Base "0 Hz tone" RF frequency to be used in MHz. + \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, + ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7. + \returns \ref status_codes + */ + int16_t begin(float base, const SSTVMode_t& mode); + + #if !RADIOLIB_EXCLUDE_AFSK + /*! + \brief Initialization method for AFSK. + \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, + ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7. + \returns \ref status_codes + */ + int16_t begin(const SSTVMode_t& mode); + #endif + + /*! + \brief Set correction coefficient for tone length. + \param correction Timing correction factor, used to adjust the length of timing pulses. + Less than 1.0 leads to shorter timing pulses, defaults to 1.0 (no correction). + \returns \ref status_codes + */ + int16_t setCorrection(float correction); + + /*! + \brief Sends out tone at 1900 Hz. + */ + void idle(); + + /*! + \brief Sends synchronization header for the SSTV mode set in begin method. + */ + void sendHeader(); + + /*! + \brief Sends single picture line in the currently configured SSTV mode. + \param imgLine Image line to send, in 24-bit RGB. It is up to the user to ensure that + imgLine has enough pixels to send it in the current SSTV mode. + */ + void sendLine(uint32_t* imgLine); + + /*! + \brief Get picture height of the currently configured SSTV mode. + \returns Picture height of the currently configured SSTV mode in pixels. + */ + uint16_t getPictureHeight() const; + +#if !RADIOLIB_GODMODE + private: +#endif + PhysicalLayer* phyLayer; + #if !RADIOLIB_EXCLUDE_AFSK + AFSKClient* audioClient; + #endif + + uint32_t baseFreq = 0; + SSTVMode_t txMode = Scottie1; + bool firstLine = true; + + void tone(float freq, uint32_t len = 0); +}; + +#endif + +#endif diff --git a/lib/lib_rf/RadioLib/src/utils/CRC.cpp b/lib/lib_rf/RadioLib/src/utils/CRC.cpp new file mode 100644 index 000000000..4422942b0 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/utils/CRC.cpp @@ -0,0 +1,35 @@ +#include "CRC.h" + +RadioLibCRC::RadioLibCRC() { + +} + +uint32_t RadioLibCRC::checksum(uint8_t* buff, size_t len) { + uint32_t crc = this->init; + size_t pos = 0; + for(size_t i = 0; i < 8*len; i++) { + if(i % 8 == 0) { + uint32_t in = buff[pos++]; + if(this->refIn) { + in = Module::reflect(in, 8); + } + crc ^= (in << (this->size - 8)); + } + + if(crc & ((uint32_t)1 << (this->size - 1))) { + crc <<= (uint32_t)1; + crc ^= this->poly; + } else { + crc <<= (uint32_t)1; + } + } + + crc ^= this->out; + if(this->refOut) { + crc = Module::reflect(crc, this->size); + } + crc &= (uint32_t)0xFFFFFFFF >> (32 - this->size); + return(crc); +} + +RadioLibCRC RadioLibCRCInstance; diff --git a/lib/lib_rf/RadioLib/src/utils/CRC.h b/lib/lib_rf/RadioLib/src/utils/CRC.h new file mode 100644 index 000000000..124fa49d9 --- /dev/null +++ b/lib/lib_rf/RadioLib/src/utils/CRC.h @@ -0,0 +1,68 @@ +#if !defined(_RADIOLIB_CRC_H) +#define _RADIOLIB_CRC_H + +#include "../TypeDef.h" +#include "../Module.h" +#if defined(RADIOLIB_BUILD_ARDUINO) +#include "../ArduinoHal.h" +#endif + +// CCITT CRC properties (used by AX.25) +#define RADIOLIB_CRC_CCITT_POLY (0x1021) +#define RADIOLIB_CRC_CCITT_INIT (0xFFFF) +#define RADIOLIB_CRC_CCITT_OUT (0xFFFF) + +/*! + \class RadioLibCRC + \brief Class to calculate CRCs of varying formats. +*/ +class RadioLibCRC { + public: + /*! + \brief CRC size in bits. + */ + uint8_t size; + + /*! + \brief CRC polynomial. + */ + uint32_t poly; + + /*! + \brief Initial value. + */ + uint32_t init; + + /*! + \brief Final XOR value. + */ + uint32_t out; + + /*! + \brief Whether to reflect input bytes. + */ + bool refIn; + + /*! + \brief Whether to reflect the result. + */ + bool refOut; + + /*! + \brief Default constructor. + */ + RadioLibCRC(); + + /*! + \brief Calculate checksum of a buffer. + \param buff Buffer to calculate the checksum over. + \param len Size of the buffer in bytes. + \returns The resulting checksum. + */ + uint32_t checksum(uint8_t* buff, size_t len); +}; + +// the global singleton +extern RadioLibCRC RadioLibCRCInstance; + +#endif diff --git a/lib/lib_rf/RadioLib/src/utils/Cryptography.cpp b/lib/lib_rf/RadioLib/src/utils/Cryptography.cpp new file mode 100644 index 000000000..16d1c46da --- /dev/null +++ b/lib/lib_rf/RadioLib/src/utils/Cryptography.cpp @@ -0,0 +1,294 @@ +#include "Cryptography.h" + +#include + +RadioLibAES128::RadioLibAES128() { + +} + +void RadioLibAES128::init(uint8_t* key) { + this->keyPtr = key; + this->keyExpansion(this->roundKey, key); +} + +size_t RadioLibAES128::encryptECB(uint8_t* in, size_t len, uint8_t* out) { + size_t num_blocks = len / RADIOLIB_AES128_BLOCK_SIZE; + if(len % RADIOLIB_AES128_BLOCK_SIZE) { + num_blocks++; + } + + memset(out, 0x00, RADIOLIB_AES128_BLOCK_SIZE * num_blocks); + memcpy(out, in, len); + + for(size_t i = 0; i < num_blocks; i++) { + this->cipher((state_t*)(out + (RADIOLIB_AES128_BLOCK_SIZE * i)), this->roundKey); + } + + return(num_blocks*RADIOLIB_AES128_BLOCK_SIZE); +} + +size_t RadioLibAES128::decryptECB(uint8_t* in, size_t len, uint8_t* out) { + size_t num_blocks = len / RADIOLIB_AES128_BLOCK_SIZE; + if(len % RADIOLIB_AES128_BLOCK_SIZE) { + num_blocks++; + } + + memset(out, 0x00, RADIOLIB_AES128_BLOCK_SIZE * num_blocks); + memcpy(out, in, len); + + for(size_t i = 0; i < num_blocks; i++) { + this->decipher((state_t*)(out + (RADIOLIB_AES128_BLOCK_SIZE * i)), this->roundKey); + } + + return(num_blocks*RADIOLIB_AES128_BLOCK_SIZE); +} + +void RadioLibAES128::generateCMAC(uint8_t* in, size_t len, uint8_t* cmac) { + uint8_t key1[RADIOLIB_AES128_BLOCK_SIZE]; + uint8_t key2[RADIOLIB_AES128_BLOCK_SIZE]; + this->generateSubkeys(key1, key2); + + size_t num_blocks = len / RADIOLIB_AES128_BLOCK_SIZE; + bool flag = true; + if(len % RADIOLIB_AES128_BLOCK_SIZE) { + num_blocks++; + flag = false; + } + + uint8_t* buff = new uint8_t[num_blocks * RADIOLIB_AES128_BLOCK_SIZE]; + memset(buff, 0, num_blocks * RADIOLIB_AES128_BLOCK_SIZE); + memcpy(buff, in, len); + if (flag) { + this->blockXor(&buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], &buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], key1); + } else { + buff[len] = 0x80; + this->blockXor(&buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], &buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], key2); + } + + uint8_t X[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + uint8_t Y[RADIOLIB_AES128_BLOCK_SIZE]; + + for(size_t i = 0; i < num_blocks - 1; i++) { + this->blockXor(Y, &buff[i*RADIOLIB_AES128_BLOCK_SIZE], X); + this->encryptECB(Y, RADIOLIB_AES128_BLOCK_SIZE, X); + } + this->blockXor(Y, &buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], X); + this->encryptECB(Y, RADIOLIB_AES128_BLOCK_SIZE, cmac); + delete[] buff; +} + +bool RadioLibAES128::verifyCMAC(uint8_t* in, size_t len, uint8_t* cmac) { + uint8_t cmacReal[RADIOLIB_AES128_BLOCK_SIZE]; + this->generateCMAC(in, len, cmacReal); + for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { + if((cmacReal[i] != cmac[i])) { + return(false); + } + } + return(true); +} + +void RadioLibAES128::keyExpansion(uint8_t* roundKey, uint8_t* key) { + uint8_t tmp[4]; + + // the first round key is the key itself + for(uint8_t i = 0; i < RADIOLIB_AES128_N_K; i++) { + for(uint8_t j = 0; j < 4; j++) { + roundKey[(i * 4) + j] = key[(i * 4) + j]; + } + } + + // All other round keys are found from the previous round keys. + for(uint8_t i = RADIOLIB_AES128_N_K; i < RADIOLIB_AES128_N_B * (RADIOLIB_AES128_N_R + 1); ++i) { + uint8_t j = (i - 1) * 4; + for(uint8_t k = 0; k < 4; k++) { + tmp[k] = roundKey[j + k]; + } + + if(i % RADIOLIB_AES128_N_K == 0) { + this->rotWord(tmp); + this->subWord(tmp); + tmp[0] = tmp[0] ^ aesRcon[i/RADIOLIB_AES128_N_K]; + } + + j = i * 4; + uint8_t k = (i - RADIOLIB_AES128_N_K) * 4; + for(uint8_t l = 0; l < 4; l++) { + roundKey[j + l] = roundKey[k + l] ^ tmp[l]; + } + } +} + +void RadioLibAES128::cipher(state_t* state, uint8_t* roundKey) { + this->addRoundKey(0, state, roundKey); + for(uint8_t round = 1; round < RADIOLIB_AES128_N_R; round++) { + this->subBytes(state, aesSbox); + this->shiftRows(state, false); + this->mixColumns(state, false); + this->addRoundKey(round, state, roundKey); + } + + this->subBytes(state, aesSbox); + this->shiftRows(state, false); + this->addRoundKey(RADIOLIB_AES128_N_R, state, roundKey); +} + + +void RadioLibAES128::decipher(state_t* state, uint8_t* roundKey) { + this->addRoundKey(RADIOLIB_AES128_N_R, state, roundKey); + for(uint8_t round = RADIOLIB_AES128_N_R - 1; round > 0; --round) { + this->shiftRows(state, true); + this->subBytes(state, aesSboxInv); + this->addRoundKey(round, state, roundKey); + this->mixColumns(state, true); + } + + this->shiftRows(state, true); + this->subBytes(state, aesSboxInv); + this->addRoundKey(0, state, roundKey); +} + +void RadioLibAES128::subWord(uint8_t* word) { + for(size_t i = 0; i < 4; i++) { + word[i] = RADIOLIB_NONVOLATILE_READ_BYTE(&aesSbox[word[i]]); + } +} + +void RadioLibAES128::rotWord(uint8_t* word) { + uint8_t tmp[4]; + memcpy(tmp, word, 4); + for(size_t i = 0; i < 4; i++) { + word[i] = tmp[(i + 1) % 4]; + } +} + +void RadioLibAES128::addRoundKey(uint8_t round, state_t* state, uint8_t* roundKey) { + for(size_t row = 0; row < 4; row++) { + for(size_t col = 0; col < 4; col++) { + (*state)[row][col] ^= roundKey[(round * RADIOLIB_AES128_N_B * 4) + (row * RADIOLIB_AES128_N_B) + col]; + } + } +} + +void RadioLibAES128::blockXor(uint8_t* dst, uint8_t* a, uint8_t* b) { + for(uint8_t j = 0; j < RADIOLIB_AES128_BLOCK_SIZE; j++) { + dst[j] = a[j] ^ b[j]; + } +} + +void RadioLibAES128::blockLeftshift(uint8_t* dst, uint8_t* src) { + uint8_t ovf = 0x00; + for(int8_t i = RADIOLIB_AES128_BLOCK_SIZE - 1; i >= 0; i--) { + dst[i] = src[i] << 1; + dst[i] |= ovf; + ovf = (src[i] & 0x80) ? 1 : 0; + } +} + +void RadioLibAES128::generateSubkeys(uint8_t* key1, uint8_t* key2) { + uint8_t const_Zero[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + uint8_t const_Rb[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x87 + }; + + uint8_t L[RADIOLIB_AES128_BLOCK_SIZE]; + this->encryptECB(const_Zero, RADIOLIB_AES128_BLOCK_SIZE, L); + this->blockLeftshift(key1, L); + if(L[0] & 0x80) { + this->blockXor(key1, key1, const_Rb); + } + + this->blockLeftshift(key2, key1); + if(key1[0] & 0x80) { + this->blockXor(key2, key2, const_Rb); + } +} + +void RadioLibAES128::subBytes(state_t* state, const uint8_t* box) { + for(size_t row = 0; row < 4; row++) { + for(size_t col = 0; col < 4; col++) { + (*state)[col][row] = RADIOLIB_NONVOLATILE_READ_BYTE(&box[(*state)[col][row]]); + } + } +} + +void RadioLibAES128::shiftRows(state_t* state, bool inv) { + uint8_t tmp[4]; + for(size_t row = 1; row < 4; row++) { + for(size_t col = 0; col < 4; col++) { + if(!inv) { + tmp[col] = (*state)[(row + col) % 4][row]; + } else { + tmp[(row + col) % 4] = (*state)[col][row]; + } + } + for(size_t col = 0; col < 4; col++) { + (*state)[col][row] = tmp[col]; + } + } +} + +void RadioLibAES128::mixColumns(state_t* state, bool inv) { + uint8_t tmp[4]; + uint8_t matmul[][4] = { + 0x02, 0x03, 0x01, 0x01, + 0x01, 0x02, 0x03, 0x01, + 0x01, 0x01, 0x02, 0x03, + 0x03, 0x01, 0x01, 0x02 + }; + if(inv) { + uint8_t matmul_inv[][4] = { + 0x0e, 0x0b, 0x0d, 0x09, + 0x09, 0x0e, 0x0b, 0x0d, + 0x0d, 0x09, 0x0e, 0x0b, + 0x0b, 0x0d, 0x09, 0x0e + }; + memcpy(matmul, matmul_inv, sizeof(matmul_inv)); + } + + for(size_t col = 0; col < 4; col++) { + for(size_t row = 0; row < 4; row++) { + tmp[row] = (*state)[col][row]; + } + for(size_t i = 0; i < 4; i++) { + (*state)[col][i] = 0x00; + for(size_t j = 0; j < 4; j++) { + (*state)[col][i] ^= mul(matmul[i][j], tmp[j]); + } + } + } +} + +uint8_t RadioLibAES128::mul(uint8_t a, uint8_t b) { + uint8_t sb[4]; + uint8_t out = 0; + sb[0] = b; + for(size_t i = 1; i < 4; i++) { + sb[i] = sb[i - 1] << 1; + if (sb[i - 1] & 0x80) { + sb[i] ^= 0x1b; + } + } + for(size_t i = 0; i < 4; i++) { + if(a >> i & 0x01) { + out ^= sb[i]; + } + } + return(out); +} + +RadioLibAES128 RadioLibAES128Instance; diff --git a/lib/lib_rf/RadioLib/src/utils/Cryptography.h b/lib/lib_rf/RadioLib/src/utils/Cryptography.h new file mode 100644 index 000000000..661996c5f --- /dev/null +++ b/lib/lib_rf/RadioLib/src/utils/Cryptography.h @@ -0,0 +1,174 @@ +#if !defined(_RADIOLIB_CRYPTOGRAPHY_H) +#define _RADIOLIB_CRYPTOGRAPHY_H + +#include "../TypeDef.h" +#include "../Module.h" + +// AES-128 constants +#define RADIOLIB_AES128_BLOCK_SIZE (16) +#define RADIOLIB_AES128_KEY_SIZE (RADIOLIB_AES128_BLOCK_SIZE) +#define RADIOLIB_AES128_N_K ((RADIOLIB_AES128_BLOCK_SIZE) / sizeof(uint32_t)) +#define RADIOLIB_AES128_N_B (4) +#define RADIOLIB_AES128_N_R (10) +#define RADIOLIB_AES128_KEY_EXP_SIZE (176) + +// helper type +typedef uint8_t state_t[4][4]; + +// AES lookup tables +static const uint8_t aesSbox[] RADIOLIB_NONVOLATILE = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +static const uint8_t aesSboxInv[] RADIOLIB_NONVOLATILE = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, + 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, + 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, + 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, + 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, + 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, + 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, + 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, + 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, + 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, + 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, + 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +}; + +static const uint8_t aesRcon[] = { 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + +/*! + \class RadioLibAES128 + Most of the implementation here is adapted from https://github.com/kokke/tiny-AES-c + Additional code and CMAC calculation is from https://github.com/megrxu/AES-CMAC + \brief Class to perform AES encryption, decryption and CMAC. +*/ +class RadioLibAES128 { + public: + /*! + \brief Default constructor. + */ + RadioLibAES128(); + + /*! + \brief Initialize the AES. + \param key AES key to use. + */ + void init(uint8_t* key); + + /*! + \brief Perform ECB-type AES encryption. + \param in Input plaintext data (unpadded). + \param len Length of the input data. + \param out Buffer to save the output ciphertext into. It is up to the caller + to ensure the buffer is sufficiently large to save the data! + \returns The number of bytes saved into the output buffer. + */ + size_t encryptECB(uint8_t* in, size_t len, uint8_t* out); + + /*! + \brief Perform ECB-type AES decryption. + \param in Input ciphertext data. + \param len Length of the input data. + \param out Buffer to save the output plaintext into. It is up to the caller + to ensure the buffer is sufficiently large to save the data! + \returns The number of bytes saved into the output buffer. + */ + size_t decryptECB(uint8_t* in, size_t len, uint8_t* out); + + /*! + \brief Calculate message authentication code according to RFC4493. + \param in Input data (unpadded). + \param len Length of the input data. + \param cmac Buffer to save the output MAC into. The buffer must be at least 16 bytes long! + */ + void generateCMAC(uint8_t* in, size_t len, uint8_t* cmac); + + /*! + \brief Verify the received CMAC. This just calculates the CMAC again and compares the results. + \param in Input data (unpadded). + \param len Length of the input data. + \param cmac CMAC to verify. + \returns True if valid, false otherwise. + */ + bool verifyCMAC(uint8_t* in, size_t len, uint8_t* cmac); + + private: + uint8_t* keyPtr; + uint8_t roundKey[RADIOLIB_AES128_KEY_EXP_SIZE]; + + void keyExpansion(uint8_t* roundKey, uint8_t* key); + void cipher(state_t* state, uint8_t* roundKey); + void decipher(state_t* state, uint8_t* roundKey); + + void subWord(uint8_t* word); + void rotWord(uint8_t* word); + + void addRoundKey(uint8_t round, state_t* state, uint8_t* roundKey); + + void blockXor(uint8_t* dst, uint8_t* a, uint8_t* b); + void blockLeftshift(uint8_t* dst, uint8_t* src); + void generateSubkeys(uint8_t* key1, uint8_t* key2); + + void subBytes(state_t* state, const uint8_t* box); + void shiftRows(state_t* state, bool inv); + void mixColumns(state_t* state, bool inv); + + uint8_t mul(uint8_t a, uint8_t b); +}; + +// the global singleton +extern RadioLibAES128 RadioLibAES128Instance; + +#endif diff --git a/lib/lib_rf/RadioLib/src/utils/FEC.cpp b/lib/lib_rf/RadioLib/src/utils/FEC.cpp new file mode 100644 index 000000000..39d7f5d5f --- /dev/null +++ b/lib/lib_rf/RadioLib/src/utils/FEC.cpp @@ -0,0 +1,293 @@ +#include "FEC.h" +#include + +RadioLibBCH::RadioLibBCH() { + +} + +/* + BCH Encoder based on https://www.codeproject.com/articles/13189/pocsag-encoder + + Significantly cleaned up and slightly fixed. +*/ +void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { + this->n = n; + this->k = k; + this->poly = poly; + #if !RADIOLIB_STATIC_ONLY + this->alphaTo = new int32_t[n + 1]; + this->indexOf = new int32_t[n + 1]; + this->generator = new int32_t[n - k + 1]; + #endif + + // find the maximum power of the polynomial + for(this->m = 0; this->m < 31; this->m++) { + if((poly >> this->m) == 1) { + break; + } + } + + /* + * generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] + * lookup tables: index->polynomial form this->alphaTo[] contains j=alpha**i; + * polynomial form -> index form this->indexOf[j=alpha**i] = i alpha=2 is the + * primitive element of GF(2**m) + */ + + int32_t mask = 1; + this->alphaTo[this->m] = 0; + + for(uint8_t i = 0; i < this->m; i++) { + this->alphaTo[i] = mask; + + this->indexOf[this->alphaTo[i]] = i; + + if(this->poly & ((uint32_t)0x01 << i)) { + this->alphaTo[this->m] ^= mask; + } + + mask <<= 1; + } + + this->indexOf[this->alphaTo[this->m]] = this->m; + mask >>= 1; + + for(uint8_t i = this->m + 1; i < this->n; i++) { + if(this->alphaTo[i - 1] >= mask) { + this->alphaTo[i] = this->alphaTo[this->m] ^ ((this->alphaTo[i - 1] ^ mask) << 1); + } else { + this->alphaTo[i] = this->alphaTo[i - 1] << 1; + } + + this->indexOf[this->alphaTo[i]] = i; + } + + this->indexOf[0] = -1; + + /* + * Compute generator polynomial of BCH code of length = 31, redundancy = 10 + * (OK, this is not very efficient, but we only do it once, right? :) + */ + + int32_t ii = 0; + int32_t jj = 1; + int32_t ll = 0; + int32_t kaux = 0; + bool test = false; + int32_t aux = 0; + int32_t cycle[15][6] = { { 0 } }; + int32_t size[15] = { 0 }; + + // Generate cycle sets modulo 31 + cycle[0][0] = 0; size[0] = 1; + cycle[1][0] = 1; size[1] = 1; + + do { + // Generate the jj-th cycle set + ii = 0; + do { + ii++; + cycle[jj][ii] = (cycle[jj][ii - 1] * 2) % this->n; + size[jj]++; + aux = (cycle[jj][ii] * 2) % this->n; + } while(aux != cycle[jj][0]); + + // Next cycle set representative + ll = 0; + do { + ll++; + test = false; + for(ii = 1; ((ii <= jj) && !test); ii++) { + // Examine previous cycle sets + for(kaux = 0; ((kaux < size[ii]) && !test); kaux++) { + test = (ll == cycle[ii][kaux]); + } + } + } while(test && (ll < (this->n - 1))); + + if(!test) { + jj++; // next cycle set index + cycle[jj][0] = ll; + size[jj] = 1; + } + + } while(ll < (this->n - 1)); + + // Search for roots 1, 2, ..., m-1 in cycle sets + int32_t rdncy = 0; + #if RADIOLIB_STATIC_ONLY + int32_t min[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; + #else + int32_t* min = new int32_t[this->n - this->k + 1]; + #endif + kaux = 0; + + for(ii = 1; ii <= jj; ii++) { + min[kaux] = 0; + for(jj = 0; jj < size[ii]; jj++) { + for(uint8_t root = 1; root < this->m; root++) { + if(root == cycle[ii][jj]) { + min[kaux] = ii; + } + } + } + + if(min[kaux]) { + rdncy += size[min[kaux]]; + kaux++; + } + } + + int32_t noterms = kaux; + #if RADIOLIB_STATIC_ONLY + int32_t zeros[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; + #else + int32_t* zeros = new int32_t[this->n - this->k + 1]; + #endif + kaux = 1; + + for(ii = 0; ii < noterms; ii++) { + for(jj = 0; jj < size[min[ii]]; jj++) { + zeros[kaux] = cycle[min[ii]][jj]; + kaux++; + } + } + + #if !RADIOLIB_STATIC_ONLY + delete[] min; + #endif + + // Compute generator polynomial + this->generator[0] = this->alphaTo[zeros[1]]; + this->generator[1] = 1; // g(x) = (X + zeros[1]) initially + + for(ii = 2; ii <= rdncy; ii++) { + this->generator[ii] = 1; + for(jj = ii - 1; jj > 0; jj--) { + if(this->generator[jj] != 0) { + this->generator[jj] = this->generator[jj - 1] ^ this->alphaTo[(this->indexOf[this->generator[jj]] + zeros[ii]) % this->n]; + } else { + this->generator[jj] = this->generator[jj - 1]; + } + } + this->generator[0] = this->alphaTo[(this->indexOf[this->generator[0]] + zeros[ii]) % this->n]; + } + + #if !RADIOLIB_STATIC_ONLY + delete[] zeros; + #endif +} + +/* + BCH Encoder based on https://www.codeproject.com/articles/13189/pocsag-encoder + + Significantly cleaned up and slightly fixed. +*/ +uint32_t RadioLibBCH::encode(uint32_t dataword) { + // we only use the "k" most significant bits + #if RADIOLIB_STATIC_ONLY + int32_t data[RADIOLIB_BCH_MAX_K]; + #else + int32_t* data = new int32_t[this->k]; + #endif + int32_t j1 = 0; + for(int32_t i = this->n; i > (this->n - this->k); i--) { + if(dataword & ((uint32_t)1<n]; + #endif + memset(Mr, 0x00, this->n*sizeof(int32_t)); + + // copy the contents of data into Mr and add the zeros + memcpy(Mr, data, this->k*sizeof(int32_t)); + + int32_t j = 0; + int32_t start = 0; + int32_t end = this->n - this->k; + while(end < this->n) { + for(int32_t i = end; i > start-2; --i) { + if(Mr[start]) { + Mr[i] ^= this->generator[j]; + ++j; + } else { + ++start; + j = 0; + end = start + this->n - this->k; + break; + } + } + } + + #if RADIOLIB_STATIC_ONLY + int32_t bb[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; + #else + int32_t* bb = new int32_t[this->n - this->k + 1]; + #endif + j = 0; + for(int32_t i = start; i < end; ++i) { + bb[j] = Mr[i]; + ++j; + } + + #if !RADIOLIB_STATIC_ONLY + delete[] Mr; + #endif + + int32_t iEvenParity = 0; + #if RADIOLIB_STATIC_ONLY + int32_t recd[RADIOLIB_BCH_MAX_N + 1]; + #else + int32_t* recd = new int32_t[this->n + 1]; + #endif + for(uint8_t i = 0; i < this->k; i++) { + recd[this->n - i] = data[i]; + if(data[i] == 1) { + iEvenParity++; + } + } + + #if !RADIOLIB_STATIC_ONLY + delete[] data; + #endif + + for(uint8_t i = 0; i < this->n - this->k + 1; i++) { + recd[this->n - this->k - i] = bb[i]; + if(bb[i] == 1) { + iEvenParity++; + } + } + + #if !RADIOLIB_STATIC_ONLY + delete[] bb; + #endif + + if((iEvenParity % 2) == 0) { + recd[0] = 0; + } else { + recd[0] = 1; + } + + int32_t res = 0; + for(int32_t i = 0; i < this->n + 1; i++) { + if(recd[i]) { + res |= ((uint32_t)1<=' and '>>=' as part of a template in code like +# 'void f(list>=val);'. If true, 'assert(x<0 && y>=3)' will be broken. +# Improvements to template detection may make this option obsolete. +tok_split_gte = false # true/false + +# Disable formatting of NL_CONT ('\\n') ended lines (e.g. multi-line macros). +disable_processing_nl_cont = false # true/false + +# Specify the marker used in comments to disable processing of part of the +# file. +# +# Default: *INDENT-OFF* +disable_processing_cmt = " *INDENT-OFF*" # string + +# Specify the marker used in comments to (re)enable processing in a file. +# +# Default: *INDENT-ON* +enable_processing_cmt = " *INDENT-ON*" # string + +# Enable parsing of digraphs. +enable_digraphs = false # true/false + +# Option to allow both disable_processing_cmt and enable_processing_cmt +# strings, if specified, to be interpreted as ECMAScript regular expressions. +# If true, a regex search will be performed within comments according to the +# specified patterns in order to disable/enable processing. +processing_cmt_as_regex = false # true/false + +# Add or remove the UTF-8 BOM (recommend 'remove'). +utf8_bom = remove # ignore/add/remove/force/not_defined + +# If the file contains bytes with values between 128 and 255, but is not +# UTF-8, then output as UTF-8. +utf8_byte = false # true/false + +# Force the output encoding to UTF-8. +utf8_force = false # true/false + +# +# Spacing options +# + +# Add or remove space around non-assignment symbolic operators ('+', '/', '%', +# '<<', and so forth). +sp_arith = force # ignore/add/remove/force/not_defined + +# Add or remove space around arithmetic operators '+' and '-'. +# +# Overrides sp_arith. +sp_arith_additive = force # ignore/add/remove/force/not_defined + +# Add or remove space around assignment operator '=', '+=', etc. +sp_assign = force # ignore/add/remove/force/not_defined + +# Add or remove space around '=' in C++11 lambda capture specifications. +# +# Overrides sp_assign. +sp_cpp_lambda_assign = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the capture specification of a C++11 lambda when +# an argument list is present, as in '[] (int x){ ... }'. +sp_cpp_lambda_square_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the capture specification of a C++11 lambda with +# no argument list is present, as in '[] { ... }'. +sp_cpp_lambda_square_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the opening parenthesis and before the closing +# parenthesis of a argument list of a C++11 lambda, as in +# '[]( int x ){ ... }'. +sp_cpp_lambda_argument_list = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the argument list of a C++11 lambda, as in +# '[](int x) { ... }'. +sp_cpp_lambda_paren_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a lambda body and its call operator of an +# immediately invoked lambda, as in '[]( ... ){ ... } ( ... )'. +sp_cpp_lambda_fparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space around assignment operator '=' in a prototype. +# +# If set to ignore, use sp_assign. +sp_assign_default = force # ignore/add/remove/force/not_defined + +# Add or remove space before assignment operator '=', '+=', etc. +# +# Overrides sp_assign. +sp_before_assign = force # ignore/add/remove/force/not_defined + +# Add or remove space after assignment operator '=', '+=', etc. +# +# Overrides sp_assign. +sp_after_assign = force # ignore/add/remove/force/not_defined + +# Add or remove space in 'enum {'. +# +# Default: add +sp_enum_brace = force # ignore/add/remove/force/not_defined + +# Add or remove space in 'NS_ENUM ('. +sp_enum_paren = force # ignore/add/remove/force/not_defined + +# Add or remove space around assignment '=' in enum. +sp_enum_assign = force # ignore/add/remove/force/not_defined + +# Add or remove space before assignment '=' in enum. +# +# Overrides sp_enum_assign. +sp_enum_before_assign = force # ignore/add/remove/force/not_defined + +# Add or remove space after assignment '=' in enum. +# +# Overrides sp_enum_assign. +sp_enum_after_assign = force # ignore/add/remove/force/not_defined + +# Add or remove space around assignment ':' in enum. +sp_enum_colon = force # ignore/add/remove/force/not_defined + +# Add or remove space around preprocessor '##' concatenation operator. +# +# Default: add +sp_pp_concat = remove # ignore/add/remove/force/not_defined + +# Add or remove space after preprocessor '#' stringify operator. +# Also affects the '#@' charizing operator. +sp_pp_stringify = remove # ignore/add/remove/force/not_defined + +# Add or remove space before preprocessor '#' stringify operator +# as in '#define x(y) L#y'. +sp_before_pp_stringify = remove # ignore/add/remove/force/not_defined + +# Add or remove space around boolean operators '&&' and '||'. +sp_bool = force # ignore/add/remove/force/not_defined + +# Add or remove space around compare operator '<', '>', '==', etc. +sp_compare = force # ignore/add/remove/force/not_defined + +# Add or remove space inside '(' and ')'. +sp_inside_paren = remove # ignore/add/remove/force/not_defined + +# Add or remove space between nested parentheses, i.e. '((' vs. ') )'. +sp_paren_paren = remove # ignore/add/remove/force/not_defined + +# Add or remove space between back-to-back parentheses, i.e. ')(' vs. ') ('. +sp_cparen_oparen = remove # ignore/add/remove/force/not_defined + +# Whether to balance spaces inside nested parentheses. +sp_balance_nested_parens = false # true/false + +# Add or remove space between ')' and '{'. +sp_paren_brace = force # ignore/add/remove/force/not_defined + +# Add or remove space between nested braces, i.e. '{{' vs. '{ {'. +sp_brace_brace = force # ignore/add/remove/force/not_defined + +# Add or remove space before pointer star '*'. +sp_before_ptr_star = remove # ignore/add/remove/force/not_defined + +# Add or remove space before pointer star '*' that isn't followed by a +# variable name. If set to ignore, sp_before_ptr_star is used instead. +sp_before_unnamed_ptr_star = force # ignore/add/remove/force/not_defined + +# Add or remove space between pointer stars '*', as in 'int ***a;'. +sp_between_ptr_star = remove # ignore/add/remove/force/not_defined + +# Add or remove space after pointer star '*', if followed by a word. +# +# Overrides sp_type_func. +sp_after_ptr_star = force # ignore/add/remove/force/not_defined + +# Add or remove space after pointer caret '^', if followed by a word. +sp_after_ptr_block_caret = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after pointer star '*', if followed by a qualifier. +sp_after_ptr_star_qualifier = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after a pointer star '*', if followed by a function +# prototype or function definition. +# +# Overrides sp_after_ptr_star and sp_type_func. +sp_after_ptr_star_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after a pointer star '*' in the trailing return of a +# function prototype or function definition. +sp_after_ptr_star_trailing = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the pointer star '*' and the name of the variable +# in a function pointer definition. +sp_ptr_star_func_var = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the pointer star '*' and the name of the type +# in a function pointer type definition. +sp_ptr_star_func_type = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after a pointer star '*', if followed by an open +# parenthesis, as in 'void* (*)()'. +sp_ptr_star_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a pointer star '*', if followed by a function +# prototype or function definition. +sp_before_ptr_star_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a pointer star '*' in the trailing return of a +# function prototype or function definition. +sp_before_ptr_star_trailing = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a reference sign '&'. +sp_before_byref = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a reference sign '&' that isn't followed by a +# variable name. If set to ignore, sp_before_byref is used instead. +sp_before_unnamed_byref = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after reference sign '&', if followed by a word. +# +# Overrides sp_type_func. +sp_after_byref = force # ignore/add/remove/force/not_defined + +# Add or remove space after a reference sign '&', if followed by a function +# prototype or function definition. +# +# Overrides sp_after_byref and sp_type_func. +sp_after_byref_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a reference sign '&', if followed by a function +# prototype or function definition. +sp_before_byref_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after a reference sign '&', if followed by an open +# parenthesis, as in 'char& (*)()'. +sp_byref_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between type and word. In cases where total removal of +# whitespace would be a syntax error, a value of 'remove' is treated the same +# as 'force'. +# +# This also affects some other instances of space following a type that are +# not covered by other options; for example, between the return type and +# parenthesis of a function type template argument, between the type and +# parenthesis of an array parameter, or between 'decltype(...)' and the +# following word. +# +# Default: force +sp_after_type = force # ignore/add/remove/force/not_defined + +# Add or remove space between 'decltype(...)' and word, +# brace or function call. +sp_after_decltype = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space before the parenthesis in the D constructs +# 'template Foo(' and 'class Foo('. +sp_before_template_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'template' and '<'. +# If set to ignore, sp_before_angle is used. +sp_template_angle = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before '<'. +sp_before_angle = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside '<' and '>'. +sp_inside_angle = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside '<>'. +sp_inside_angle_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '>' and ':'. +sp_angle_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after '>'. +sp_after_angle = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '>' and '(' as found in 'new List(foo);'. +sp_angle_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '>' and '()' as found in 'new List();'. +sp_angle_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '>' and a word as in 'List m;' or +# 'template static ...'. +sp_angle_word = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '>' and '>' in '>>' (template stuff). +# +# Default: add +sp_angle_shift = add # ignore/add/remove/force/not_defined + +# (C++11) Permit removal of the space between '>>' in 'foo >'. Note +# that sp_angle_shift cannot remove the space without this option. +sp_permit_cpp11_shift = false # true/false + +# Add or remove space before '(' of control statements ('if', 'for', 'switch', +# 'while', etc.). +sp_before_sparen = remove # ignore/add/remove/force/not_defined + +# Add or remove space inside '(' and ')' of control statements other than +# 'for'. +sp_inside_sparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after '(' of control statements other than 'for'. +# +# Overrides sp_inside_sparen. +sp_inside_sparen_open = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before ')' of control statements other than 'for'. +# +# Overrides sp_inside_sparen. +sp_inside_sparen_close = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside '(' and ')' of 'for' statements. +sp_inside_for = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after '(' of 'for' statements. +# +# Overrides sp_inside_for. +sp_inside_for_open = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before ')' of 'for' statements. +# +# Overrides sp_inside_for. +sp_inside_for_close = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '((' or '))' of control statements. +sp_sparen_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after ')' of control statements. +sp_after_sparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and '{' of control statements. +sp_sparen_brace = force # ignore/add/remove/force/not_defined + +# Add or remove space between 'do' and '{'. +sp_do_brace_open = force # ignore/add/remove/force/not_defined + +# Add or remove space between '}' and 'while'. +sp_brace_close_while = force # ignore/add/remove/force/not_defined + +# Add or remove space between 'while' and '('. Overrides sp_before_sparen. +sp_while_paren_open = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space between 'invariant' and '('. +sp_invariant_paren = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space after the ')' in 'invariant (C) c'. +sp_after_invariant_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before empty statement ';' on 'if', 'for' and 'while'. +sp_special_semi = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before ';'. +# +# Default: remove +sp_before_semi = remove # ignore/add/remove/force/not_defined + +# Add or remove space before ';' in non-empty 'for' statements. +sp_before_semi_for = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a semicolon of an empty left part of a for +# statement, as in 'for ( ; ; )'. +sp_before_semi_for_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the semicolons of an empty middle part of a for +# statement, as in 'for ( ; ; )'. +sp_between_semi_for_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after ';', except when followed by a comment. +# +# Default: add +sp_after_semi = add # ignore/add/remove/force/not_defined + +# Add or remove space after ';' in non-empty 'for' statements. +# +# Default: force +sp_after_semi_for = force # ignore/add/remove/force/not_defined + +# Add or remove space after the final semicolon of an empty part of a for +# statement, as in 'for ( ; ; )'. +sp_after_semi_for_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before '[' (except '[]'). +sp_before_square = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before '[' for a variable definition. +# +# Default: remove +sp_before_vardef_square = remove # ignore/add/remove/force/not_defined + +# Add or remove space before '[' for asm block. +sp_before_square_asm_block = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before '[]'. +sp_before_squares = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before C++17 structured bindings. +sp_cpp_before_struct_binding = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside a non-empty '[' and ']'. +sp_inside_square = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside '[]'. +sp_inside_square_empty = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space inside a non-empty Objective-C boxed array '@[' and +# ']'. If set to ignore, sp_inside_square is used. +sp_inside_square_oc_array = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after ',', i.e. 'a,b' vs. 'a, b'. +sp_after_comma = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before ',', i.e. 'a,b' vs. 'a ,b'. +# +# Default: remove +sp_before_comma = remove # ignore/add/remove/force/not_defined + +# (C#, Vala) Add or remove space between ',' and ']' in multidimensional array type +# like 'int[,,]'. +sp_after_mdatype_commas = ignore # ignore/add/remove/force/not_defined + +# (C#, Vala) Add or remove space between '[' and ',' in multidimensional array type +# like 'int[,,]'. +sp_before_mdatype_commas = ignore # ignore/add/remove/force/not_defined + +# (C#, Vala) Add or remove space between ',' in multidimensional array type +# like 'int[,,]'. +sp_between_mdatype_commas = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between an open parenthesis and comma, +# i.e. '(,' vs. '( ,'. +# +# Default: force +sp_paren_comma = force # ignore/add/remove/force/not_defined + +# Add or remove space between a type and ':'. +sp_type_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the variadic '...' when preceded by a +# non-punctuator. +# The value REMOVE will be overridden with FORCE +sp_after_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before the variadic '...' when preceded by a +# non-punctuator. +# The value REMOVE will be overridden with FORCE +sp_before_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a type and '...'. +sp_type_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a '*' and '...'. +sp_ptr_type_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and '...'. +sp_paren_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '&&' and '...'. +sp_byref_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and a qualifier such as 'const'. +sp_paren_qualifier = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and 'noexcept'. +sp_paren_noexcept = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after class ':'. +sp_after_class_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before class ':'. +sp_before_class_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after class constructor ':'. +# +# Default: add +sp_after_constr_colon = add # ignore/add/remove/force/not_defined + +# Add or remove space before class constructor ':'. +# +# Default: add +sp_before_constr_colon = add # ignore/add/remove/force/not_defined + +# Add or remove space before case ':'. +# +# Default: remove +sp_before_case_colon = remove # ignore/add/remove/force/not_defined + +# Add or remove space between 'operator' and operator sign. +sp_after_operator = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the operator symbol and the open parenthesis, as +# in 'operator ++('. +sp_after_operator_sym = ignore # ignore/add/remove/force/not_defined + +# Overrides sp_after_operator_sym when the operator has no arguments, as in +# 'operator *()'. +sp_after_operator_sym_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after C/D cast, i.e. 'cast(int)a' vs. 'cast(int) a' or +# '(int)a' vs. '(int) a'. +sp_after_cast = ignore # ignore/add/remove/force/not_defined + +# Add or remove spaces inside cast parentheses. +sp_inside_paren_cast = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the type and open parenthesis in a C++ cast, +# i.e. 'int(exp)' vs. 'int (exp)'. +sp_cpp_cast_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'sizeof' and '('. +sp_sizeof_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'sizeof' and '...'. +sp_sizeof_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'sizeof...' and '('. +sp_sizeof_ellipsis_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '...' and a parameter pack. +sp_ellipsis_parameter_pack = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a parameter pack and '...'. +sp_parameter_pack_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'decltype' and '('. +sp_decltype_paren = ignore # ignore/add/remove/force/not_defined + +# (Pawn) Add or remove space after the tag keyword. +sp_after_tag = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside enum '{' and '}'. +sp_inside_braces_enum = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside struct/union '{' and '}'. +sp_inside_braces_struct = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space inside Objective-C boxed dictionary '{' and '}' +sp_inside_braces_oc_dict = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after open brace in an unnamed temporary +# direct-list-initialization +# if statement is a brace_init_lst +# works only if sp_brace_brace is set to ignore. +sp_after_type_brace_init_lst_open = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before close brace in an unnamed temporary +# direct-list-initialization +# if statement is a brace_init_lst +# works only if sp_brace_brace is set to ignore. +sp_before_type_brace_init_lst_close = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside an unnamed temporary direct-list-initialization +# if statement is a brace_init_lst +# works only if sp_brace_brace is set to ignore +# works only if sp_before_type_brace_init_lst_close is set to ignore. +sp_inside_type_brace_init_lst = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside '{' and '}'. +sp_inside_braces = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside '{}'. +sp_inside_braces_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space around trailing return operator '->'. +sp_trailing_return = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between return type and function name. A minimum of 1 +# is forced except for pointer return types. +sp_type_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between type and open brace of an unnamed temporary +# direct-list-initialization. +sp_type_brace_init_lst = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between function name and '(' on function declaration. +sp_func_proto_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between function name and '()' on function declaration +# without parameters. +sp_func_proto_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between function name and '(' with a typedef specifier. +sp_func_type_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between alias name and '(' of a non-pointer function type typedef. +sp_func_def_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between function name and '()' on function definition +# without parameters. +sp_func_def_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside empty function '()'. +# Overrides sp_after_angle unless use_sp_after_angle_always is set to true. +sp_inside_fparens = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside function '(' and ')'. +sp_inside_fparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside the first parentheses in a function type, as in +# 'void (*x)(...)'. +sp_inside_tparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the ')' and '(' in a function type, as in +# 'void (*x)(...)'. +sp_after_tparen_close = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ']' and '(' when part of a function call. +sp_square_fparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and '{' of function. +sp_fparen_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and '{' of a function call in object +# initialization. +# +# Overrides sp_fparen_brace. +sp_fparen_brace_initializer = ignore # ignore/add/remove/force/not_defined + +# (Java) Add or remove space between ')' and '{{' of double brace initializer. +sp_fparen_dbrace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between function name and '(' on function calls. +sp_func_call_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between function name and '()' on function calls without +# parameters. If set to ignore (the default), sp_func_call_paren is used. +sp_func_call_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the user function name and '(' on function +# calls. You need to set a keyword to be a user function in the config file, +# like: +# set func_call_user tr _ i18n +sp_func_call_user_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside user function '(' and ')'. +sp_func_call_user_inside_fparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between nested parentheses with user functions, +# i.e. '((' vs. '( ('. +sp_func_call_user_paren_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a constructor/destructor and the open +# parenthesis. +sp_func_class_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a constructor without parameters or destructor +# and '()'. +sp_func_class_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after 'return'. +# +# Default: force +sp_return = force # ignore/add/remove/force/not_defined + +# Add or remove space between 'return' and '('. +sp_return_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'return' and '{'. +sp_return_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '__attribute__' and '('. +sp_attribute_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'defined' and '(' in '#if defined (FOO)'. +sp_defined_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'throw' and '(' in 'throw (something)'. +sp_throw_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'throw' and anything other than '(' as in +# '@throw [...];'. +sp_after_throw = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'catch' and '(' in 'catch (something) { }'. +# If set to ignore, sp_before_sparen is used. +sp_catch_paren = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between '@catch' and '(' +# in '@catch (something) { }'. If set to ignore, sp_catch_paren is used. +sp_oc_catch_paren = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space before Objective-C protocol list +# as in '@protocol Protocol' or '@interface MyClass : NSObject'. +sp_before_oc_proto_list = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between class name and '(' +# in '@interface className(categoryName):BaseClass' +sp_oc_classname_paren = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space between 'version' and '(' +# in 'version (something) { }'. If set to ignore, sp_before_sparen is used. +sp_version_paren = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space between 'scope' and '(' +# in 'scope (something) { }'. If set to ignore, sp_before_sparen is used. +sp_scope_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'super' and '(' in 'super (something)'. +# +# Default: remove +sp_super_paren = remove # ignore/add/remove/force/not_defined + +# Add or remove space between 'this' and '(' in 'this (something)'. +# +# Default: remove +sp_this_paren = remove # ignore/add/remove/force/not_defined + +# Add or remove space between a macro name and its definition. +sp_macro = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a macro function ')' and its definition. +sp_macro_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'else' and '{' if on the same line. +sp_else_brace = force # ignore/add/remove/force/not_defined + +# Add or remove space between '}' and 'else' if on the same line. +sp_brace_else = force # ignore/add/remove/force/not_defined + +# Add or remove space between '}' and the name of a typedef on the same line. +sp_brace_typedef = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before the '{' of a 'catch' statement, if the '{' and +# 'catch' are on the same line, as in 'catch (decl) {'. +sp_catch_brace = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space before the '{' of a '@catch' statement, if the '{' +# and '@catch' are on the same line, as in '@catch (decl) {'. +# If set to ignore, sp_catch_brace is used. +sp_oc_catch_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '}' and 'catch' if on the same line. +sp_brace_catch = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between '}' and '@catch' if on the same line. +# If set to ignore, sp_brace_catch is used. +sp_oc_brace_catch = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'finally' and '{' if on the same line. +sp_finally_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '}' and 'finally' if on the same line. +sp_brace_finally = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'try' and '{' if on the same line. +sp_try_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between get/set and '{' if on the same line. +sp_getset_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a variable and '{' for C++ uniform +# initialization. +sp_word_brace_init_lst = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a variable and '{' for a namespace. +# +# Default: add +sp_word_brace_ns = add # ignore/add/remove/force/not_defined + +# Add or remove space before the '::' operator. +sp_before_dc = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the '::' operator. +sp_after_dc = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove around the D named array initializer ':' operator. +sp_d_array_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the '!' (not) unary operator. +# +# Default: remove +sp_not = remove # ignore/add/remove/force/not_defined + +# Add or remove space between two '!' (not) unary operators. +# If set to ignore, sp_not will be used. +sp_not_not = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the '~' (invert) unary operator. +# +# Default: remove +sp_inv = remove # ignore/add/remove/force/not_defined + +# Add or remove space after the '&' (address-of) unary operator. This does not +# affect the spacing after a '&' that is part of a type. +# +# Default: remove +sp_addr = remove # ignore/add/remove/force/not_defined + +# Add or remove space around the '.' or '->' operators. +# +# Default: remove +sp_member = remove # ignore/add/remove/force/not_defined + +# Add or remove space after the '*' (dereference) unary operator. This does +# not affect the spacing after a '*' that is part of a type. +# +# Default: remove +sp_deref = remove # ignore/add/remove/force/not_defined + +# Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. +# +# Default: remove +sp_sign = remove # ignore/add/remove/force/not_defined + +# Add or remove space between '++' and '--' the word to which it is being +# applied, as in '(--x)' or 'y++;'. +# +# Default: remove +sp_incdec = remove # ignore/add/remove/force/not_defined + +# Add or remove space before a backslash-newline at the end of a line. +# +# Default: add +sp_before_nl_cont = add # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after the scope '+' or '-', as in '-(void) foo;' +# or '+(int) bar;'. +sp_after_oc_scope = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after the colon in message specs, +# i.e. '-(int) f:(int) x;' vs. '-(int) f: (int) x;'. +sp_after_oc_colon = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space before the colon in message specs, +# i.e. '-(int) f: (int) x;' vs. '-(int) f : (int) x;'. +sp_before_oc_colon = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after the colon in immutable dictionary expression +# 'NSDictionary *test = @{@"foo" :@"bar"};'. +sp_after_oc_dict_colon = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space before the colon in immutable dictionary expression +# 'NSDictionary *test = @{@"foo" :@"bar"};'. +sp_before_oc_dict_colon = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after the colon in message specs, +# i.e. '[object setValue:1];' vs. '[object setValue: 1];'. +sp_after_send_oc_colon = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space before the colon in message specs, +# i.e. '[object setValue:1];' vs. '[object setValue :1];'. +sp_before_send_oc_colon = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after the (type) in message specs, +# i.e. '-(int)f: (int) x;' vs. '-(int)f: (int)x;'. +sp_after_oc_type = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after the first (type) in message specs, +# i.e. '-(int) f:(int)x;' vs. '-(int)f:(int)x;'. +sp_after_oc_return_type = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between '@selector' and '(', +# i.e. '@selector(msgName)' vs. '@selector (msgName)'. +# Also applies to '@protocol()' constructs. +sp_after_oc_at_sel = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between '@selector(x)' and the following word, +# i.e. '@selector(foo) a:' vs. '@selector(foo)a:'. +sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space inside '@selector' parentheses, +# i.e. '@selector(foo)' vs. '@selector( foo )'. +# Also applies to '@protocol()' constructs. +sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space before a block pointer caret, +# i.e. '^int (int arg){...}' vs. ' ^int (int arg){...}'. +sp_before_oc_block_caret = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after a block pointer caret, +# i.e. '^int (int arg){...}' vs. '^ int (int arg){...}'. +sp_after_oc_block_caret = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between the receiver and selector in a message, +# as in '[receiver selector ...]'. +sp_after_oc_msg_receiver = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after '@property'. +sp_after_oc_property = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between '@synchronized' and the open parenthesis, +# i.e. '@synchronized(foo)' vs. '@synchronized (foo)'. +sp_after_oc_synchronized = ignore # ignore/add/remove/force/not_defined + +# Add or remove space around the ':' in 'b ? t : f'. +sp_cond_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before the ':' in 'b ? t : f'. +# +# Overrides sp_cond_colon. +sp_cond_colon_before = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the ':' in 'b ? t : f'. +# +# Overrides sp_cond_colon. +sp_cond_colon_after = ignore # ignore/add/remove/force/not_defined + +# Add or remove space around the '?' in 'b ? t : f'. +sp_cond_question = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before the '?' in 'b ? t : f'. +# +# Overrides sp_cond_question. +sp_cond_question_before = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the '?' in 'b ? t : f'. +# +# Overrides sp_cond_question. +sp_cond_question_after = ignore # ignore/add/remove/force/not_defined + +# In the abbreviated ternary form '(a ?: b)', add or remove space between '?' +# and ':'. +# +# Overrides all other sp_cond_* options. +sp_cond_ternary_short = ignore # ignore/add/remove/force/not_defined + +# Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make +# sense here. +sp_case_label = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space around the D '..' operator. +sp_range = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after ':' in a Java/C++11 range-based 'for', +# as in 'for (Type var : expr)'. +sp_after_for_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before ':' in a Java/C++11 range-based 'for', +# as in 'for (Type var : expr)'. +sp_before_for_colon = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space between 'extern' and '(' as in 'extern (C)'. +sp_extern_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the opening of a C++ comment, as in '// A'. +sp_cmt_cpp_start = force # ignore/add/remove/force/not_defined + +# Add or remove space in a C++ region marker comment, as in '// BEGIN'. +# A region marker is defined as a comment which is not preceded by other text +# (i.e. the comment is the first non-whitespace on the line), and which starts +# with either 'BEGIN' or 'END'. +# +# Overrides sp_cmt_cpp_start. +sp_cmt_cpp_region = ignore # ignore/add/remove/force/not_defined + +# If true, space added with sp_cmt_cpp_start will be added after Doxygen +# sequences like '///', '///<', '//!' and '//!<'. +sp_cmt_cpp_doxygen = true # true/false + +# If true, space added with sp_cmt_cpp_start will be added after Qt translator +# or meta-data comments like '//:', '//=', and '//~'. +sp_cmt_cpp_qttr = false # true/false + +# Add or remove space between #else or #endif and a trailing comment. +sp_endif_cmt = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after 'new', 'delete' and 'delete[]'. +sp_after_new = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'new' and '(' in 'new()'. +sp_between_new_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and type in 'new(foo) BAR'. +sp_after_newop_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside parentheses of the new operator +# as in 'new(foo) BAR'. +sp_inside_newop_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the open parenthesis of the new operator, +# as in 'new(foo) BAR'. +# +# Overrides sp_inside_newop_paren. +sp_inside_newop_paren_open = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before the close parenthesis of the new operator, +# as in 'new(foo) BAR'. +# +# Overrides sp_inside_newop_paren. +sp_inside_newop_paren_close = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a trailing comment. +sp_before_tr_cmt = ignore # ignore/add/remove/force/not_defined + +# Number of spaces before a trailing comment. +sp_num_before_tr_cmt = 0 # unsigned number + +# Add or remove space before an embedded comment. +# +# Default: force +sp_before_emb_cmt = force # ignore/add/remove/force/not_defined + +# Number of spaces before an embedded comment. +# +# Default: 1 +sp_num_before_emb_cmt = 1 # unsigned number + +# Add or remove space after an embedded comment. +# +# Default: force +sp_after_emb_cmt = remove # ignore/add/remove/force/not_defined + +# Number of spaces after an embedded comment. +# +# Default: 1 +sp_num_after_emb_cmt = 1 # unsigned number + +# (Java) Add or remove space between an annotation and the open parenthesis. +sp_annotation_paren = ignore # ignore/add/remove/force/not_defined + +# If true, vbrace tokens are dropped to the previous token and skipped. +sp_skip_vbrace_tokens = false # true/false + +# Add or remove space after 'noexcept'. +sp_after_noexcept = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after '_'. +sp_vala_after_translation = ignore # ignore/add/remove/force/not_defined + +# If true, a is inserted after #define. +force_tab_after_define = false # true/false + +# +# Indenting options +# + +# The number of columns to indent per level. Usually 2, 3, 4, or 8. +# +# Default: 8 +indent_columns = 2 # unsigned number + +# Whether to ignore indent for the first continuation line. Subsequent +# continuation lines will still be indented to match the first. +indent_ignore_first_continue = false # true/false + +# The continuation indent. If non-zero, this overrides the indent of '(', '[' +# and '=' continuation indents. Negative values are OK; negative value is +# absolute and not increased for each '(' or '[' level. +# +# For FreeBSD, this is set to 4. +# Requires indent_ignore_first_continue=false. +indent_continue = 0 # number + +# The continuation indent, only for class header line(s). If non-zero, this +# overrides the indent of 'class' continuation indents. +# Requires indent_ignore_first_continue=false. +indent_continue_class_head = 0 # unsigned number + +# Whether to indent empty lines (i.e. lines which contain only spaces before +# the newline character). +indent_single_newlines = false # true/false + +# The continuation indent for func_*_param if they are true. If non-zero, this +# overrides the indent. +indent_param = 0 # unsigned number + +# How to use tabs when indenting code. +# +# 0: Spaces only +# 1: Indent with tabs to brace level, align with spaces (default) +# 2: Indent and align with tabs, using spaces when not on a tabstop +# +# Default: 1 +indent_with_tabs = 0 # unsigned number + +# Whether to indent comments that are not at a brace level with tabs on a +# tabstop. Requires indent_with_tabs=2. If false, will use spaces. +indent_cmt_with_tabs = false # true/false + +# Whether to indent strings broken by '\' so that they line up. +indent_align_string = false # true/false + +# The number of spaces to indent multi-line XML strings. +# Requires indent_align_string=true. +indent_xml_string = 0 # unsigned number + +# Spaces to indent '{' from level. +indent_brace = 0 # unsigned number + +# Whether braces are indented to the body level. +indent_braces = false # true/false + +# Whether to disable indenting function braces if indent_braces=true. +indent_braces_no_func = false # true/false + +# Whether to disable indenting class braces if indent_braces=true. +indent_braces_no_class = false # true/false + +# Whether to disable indenting struct braces if indent_braces=true. +indent_braces_no_struct = false # true/false + +# Whether to indent based on the size of the brace parent, +# i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. +indent_brace_parent = false # true/false + +# Whether to indent based on the open parenthesis instead of the open brace +# in '({\n'. +indent_paren_open_brace = false # true/false + +# (C#) Whether to indent the brace of a C# delegate by another level. +indent_cs_delegate_brace = false # true/false + +# (C#) Whether to indent a C# delegate (to handle delegates with no brace) by +# another level. +indent_cs_delegate_body = false # true/false + +# Whether to indent the body of a 'namespace'. +indent_namespace = false # true/false + +# Whether to indent only the first namespace, and not any nested namespaces. +# Requires indent_namespace=true. +indent_namespace_single_indent = false # true/false + +# The number of spaces to indent a namespace block. +# If set to zero, use the value indent_columns +indent_namespace_level = 0 # unsigned number + +# If the body of the namespace is longer than this number, it won't be +# indented. Requires indent_namespace=true. 0 means no limit. +indent_namespace_limit = 0 # unsigned number + +# Whether to indent only in inner namespaces (nested in other namespaces). +# Requires indent_namespace=true. +indent_namespace_inner_only = false # true/false + +# Whether the 'extern "C"' body is indented. +indent_extern = false # true/false + +# Whether the 'class' body is indented. +indent_class = true # true/false + +# Whether to ignore indent for the leading base class colon. +indent_ignore_before_class_colon = false # true/false + +# Additional indent before the leading base class colon. +# Negative values decrease indent down to the first column. +# Requires indent_ignore_before_class_colon=false and a newline break before +# the colon (see pos_class_colon and nl_class_colon) +indent_before_class_colon = 0 # number + +# Whether to indent the stuff after a leading base class colon. +indent_class_colon = false # true/false + +# Whether to indent based on a class colon instead of the stuff after the +# colon. Requires indent_class_colon=true. +indent_class_on_colon = false # true/false + +# Whether to ignore indent for a leading class initializer colon. +indent_ignore_before_constr_colon = false # true/false + +# Whether to indent the stuff after a leading class initializer colon. +indent_constr_colon = false # true/false + +# Virtual indent from the ':' for leading member initializers. +# +# Default: 2 +indent_ctor_init_leading = 2 # unsigned number + +# Virtual indent from the ':' for following member initializers. +# +# Default: 2 +indent_ctor_init_following = 2 # unsigned number + +# Additional indent for constructor initializer list. +# Negative values decrease indent down to the first column. +indent_ctor_init = 0 # number + +# Whether to indent 'if' following 'else' as a new block under the 'else'. +# If false, 'else\nif' is treated as 'else if' for indenting purposes. +indent_else_if = false # true/false + +# Amount to indent variable declarations after a open brace. +# +# <0: Relative +# >=0: Absolute +indent_var_def_blk = 0 # number + +# Whether to indent continued variable declarations instead of aligning. +indent_var_def_cont = false # true/false + +# How to indent continued shift expressions ('<<' and '>>'). +# Set align_left_shift=false when using this. +# 0: Align shift operators instead of indenting them (default) +# 1: Indent by one level +# -1: Preserve original indentation +indent_shift = 0 # number + +# Whether to force indentation of function definitions to start in column 1. +indent_func_def_force_col1 = false # true/false + +# Whether to indent continued function call parameters one indent level, +# rather than aligning parameters under the open parenthesis. +indent_func_call_param = false # true/false + +# Whether to indent continued function definition parameters one indent level, +# rather than aligning parameters under the open parenthesis. +indent_func_def_param = false # true/false + +# for function definitions, only if indent_func_def_param is false +# Allows to align params when appropriate and indent them when not +# behave as if it was true if paren position is more than this value +# if paren position is more than the option value +indent_func_def_param_paren_pos_threshold = 0 # unsigned number + +# Whether to indent continued function call prototype one indent level, +# rather than aligning parameters under the open parenthesis. +indent_func_proto_param = false # true/false + +# Whether to indent continued function call declaration one indent level, +# rather than aligning parameters under the open parenthesis. +indent_func_class_param = false # true/false + +# Whether to indent continued class variable constructors one indent level, +# rather than aligning parameters under the open parenthesis. +indent_func_ctor_var_param = false # true/false + +# Whether to indent continued template parameter list one indent level, +# rather than aligning parameters under the open parenthesis. +indent_template_param = false # true/false + +# Double the indent for indent_func_xxx_param options. +# Use both values of the options indent_columns and indent_param. +indent_func_param_double = false # true/false + +# Indentation column for standalone 'const' qualifier on a function +# prototype. +indent_func_const = 0 # unsigned number + +# Indentation column for standalone 'throw' qualifier on a function +# prototype. +indent_func_throw = 0 # unsigned number + +# How to indent within a macro followed by a brace on the same line +# This allows reducing the indent in macros that have (for example) +# `do { ... } while (0)` blocks bracketing them. +# +# true: add an indent for the brace on the same line as the macro +# false: do not add an indent for the brace on the same line as the macro +# +# Default: true +indent_macro_brace = true # true/false + +# The number of spaces to indent a continued '->' or '.'. +# Usually set to 0, 1, or indent_columns. +indent_member = 0 # unsigned number + +# Whether lines broken at '.' or '->' should be indented by a single indent. +# The indent_member option will not be effective if this is set to true. +indent_member_single = false # true/false + +# Spaces to indent single line ('//') comments on lines before code. +indent_single_line_comments_before = 0 # unsigned number + +# Spaces to indent single line ('//') comments on lines after code. +indent_single_line_comments_after = 0 # unsigned number + +# When opening a paren for a control statement (if, for, while, etc), increase +# the indent level by this value. Negative values decrease the indent level. +indent_sparen_extra = 0 # number + +# Whether to indent trailing single line ('//') comments relative to the code +# instead of trying to keep the same absolute column. +indent_relative_single_line_comments = false # true/false + +# Spaces to indent 'case' from 'switch'. Usually 0 or indent_columns. +# It might be wise to choose the same value for the option indent_case_brace. +indent_switch_case = indent_columns # unsigned number + +# Spaces to indent the body of a 'switch' before any 'case'. +# Usually the same as indent_columns or indent_switch_case. +indent_switch_body = 0 # unsigned number + +# Whether to ignore indent for '{' following 'case'. +indent_ignore_case_brace = false # true/false + +# Spaces to indent '{' from 'case'. By default, the brace will appear under +# the 'c' in case. Usually set to 0 or indent_columns. Negative values are OK. +# It might be wise to choose the same value for the option indent_switch_case. +indent_case_brace = 0 # number + +# indent 'break' with 'case' from 'switch'. +indent_switch_break_with_case = false # true/false + +# Whether to indent preprocessor statements inside of switch statements. +# +# Default: true +indent_switch_pp = true # true/false + +# Spaces to shift the 'case' line, without affecting any other lines. +# Usually 0. +indent_case_shift = 0 # unsigned number + +# Whether to align comments before 'case' with the 'case'. +# +# Default: true +indent_case_comment = true # true/false + +# Whether to indent comments not found in first column. +# +# Default: true +indent_comment = true # true/false + +# Whether to indent comments found in first column. +indent_col1_comment = true # true/false + +# Whether to indent multi string literal in first column. +indent_col1_multi_string_literal = false # true/false + +# Align comments on adjacent lines that are this many columns apart or less. +# +# Default: 3 +indent_comment_align_thresh = 3 # unsigned number + +# Whether to ignore indent for goto labels. +indent_ignore_label = false # true/false + +# How to indent goto labels. Requires indent_ignore_label=false. +# +# >0: Absolute column where 1 is the leftmost column +# <=0: Subtract from brace indent +# +# Default: 1 +indent_label = 1 # number + +# How to indent access specifiers that are followed by a +# colon. +# +# >0: Absolute column where 1 is the leftmost column +# <=0: Subtract from brace indent +# +# Default: 1 +indent_access_spec = 0 # number + +# Whether to indent the code after an access specifier by one level. +# If true, this option forces 'indent_access_spec=0'. +indent_access_spec_body = true # true/false + +# If an open parenthesis is followed by a newline, whether to indent the next +# line so that it lines up after the open parenthesis (not recommended). +indent_paren_nl = false # true/false + +# How to indent a close parenthesis after a newline. +# +# 0: Indent to body level (default) +# 1: Align under the open parenthesis +# 2: Indent to the brace level +# -1: Preserve original indentation +indent_paren_close = 0 # number + +# Whether to indent the open parenthesis of a function definition, +# if the parenthesis is on its own line. +indent_paren_after_func_def = false # true/false + +# Whether to indent the open parenthesis of a function declaration, +# if the parenthesis is on its own line. +indent_paren_after_func_decl = false # true/false + +# Whether to indent the open parenthesis of a function call, +# if the parenthesis is on its own line. +indent_paren_after_func_call = false # true/false + +# How to indent a comma when inside braces. +# 0: Indent by one level (default) +# 1: Align under the open brace +# -1: Preserve original indentation +indent_comma_brace = 0 # number + +# How to indent a comma when inside parentheses. +# 0: Indent by one level (default) +# 1: Align under the open parenthesis +# -1: Preserve original indentation +indent_comma_paren = 0 # number + +# How to indent a Boolean operator when inside parentheses. +# 0: Indent by one level (default) +# 1: Align under the open parenthesis +# -1: Preserve original indentation +indent_bool_paren = 0 # number + +# Whether to ignore the indentation of a Boolean operator when outside +# parentheses. +indent_ignore_bool = false # true/false + +# Whether to ignore the indentation of an arithmetic operator. +indent_ignore_arith = false # true/false + +# Whether to indent a semicolon when inside a for parenthesis. +# If true, aligns under the open for parenthesis. +indent_semicolon_for_paren = false # true/false + +# Whether to ignore the indentation of a semicolon outside of a 'for' +# statement. +indent_ignore_semicolon = false # true/false + +# Whether to align the first expression to following ones +# if indent_bool_paren=1. +indent_first_bool_expr = false # true/false + +# Whether to align the first expression to following ones +# if indent_semicolon_for_paren=true. +indent_first_for_expr = false # true/false + +# If an open square is followed by a newline, whether to indent the next line +# so that it lines up after the open square (not recommended). +indent_square_nl = false # true/false + +# (ESQL/C) Whether to preserve the relative indent of 'EXEC SQL' bodies. +indent_preserve_sql = false # true/false + +# Whether to ignore the indentation of an assignment operator. +indent_ignore_assign = false # true/false + +# Whether to align continued statements at the '='. If false or if the '=' is +# followed by a newline, the next line is indent one tab. +# +# Default: true +indent_align_assign = true # true/false + +# If true, the indentation of the chunks after a '=' sequence will be set at +# LHS token indentation column before '='. +indent_off_after_assign = false # true/false + +# Whether to align continued statements at the '('. If false or the '(' is +# followed by a newline, the next line indent is one tab. +# +# Default: true +indent_align_paren = true # true/false + +# (OC) Whether to indent Objective-C code inside message selectors. +indent_oc_inside_msg_sel = false # true/false + +# (OC) Whether to indent Objective-C blocks at brace level instead of usual +# rules. +indent_oc_block = false # true/false + +# (OC) Indent for Objective-C blocks in a message relative to the parameter +# name. +# +# =0: Use indent_oc_block rules +# >0: Use specified number of spaces to indent +indent_oc_block_msg = 0 # unsigned number + +# (OC) Minimum indent for subsequent parameters +indent_oc_msg_colon = 0 # unsigned number + +# (OC) Whether to prioritize aligning with initial colon (and stripping spaces +# from lines, if necessary). +# +# Default: true +indent_oc_msg_prioritize_first_colon = true # true/false + +# (OC) Whether to indent blocks the way that Xcode does by default +# (from the keyword if the parameter is on its own line; otherwise, from the +# previous indentation level). Requires indent_oc_block_msg=true. +indent_oc_block_msg_xcode_style = false # true/false + +# (OC) Whether to indent blocks from where the brace is, relative to a +# message keyword. Requires indent_oc_block_msg=true. +indent_oc_block_msg_from_keyword = false # true/false + +# (OC) Whether to indent blocks from where the brace is, relative to a message +# colon. Requires indent_oc_block_msg=true. +indent_oc_block_msg_from_colon = false # true/false + +# (OC) Whether to indent blocks from where the block caret is. +# Requires indent_oc_block_msg=true. +indent_oc_block_msg_from_caret = false # true/false + +# (OC) Whether to indent blocks from where the brace caret is. +# Requires indent_oc_block_msg=true. +indent_oc_block_msg_from_brace = false # true/false + +# When indenting after virtual brace open and newline add further spaces to +# reach this minimum indent. +indent_min_vbrace_open = 0 # unsigned number + +# Whether to add further spaces after regular indent to reach next tabstop +# when indenting after virtual brace open and newline. +indent_vbrace_open_on_tabstop = false # true/false + +# How to indent after a brace followed by another token (not a newline). +# true: indent all contained lines to match the token +# false: indent all contained lines to match the brace +# +# Default: true +indent_token_after_brace = true # true/false + +# Whether to indent the body of a C++11 lambda. +indent_cpp_lambda_body = false # true/false + +# How to indent compound literals that are being returned. +# true: add both the indent from return & the compound literal open brace +# (i.e. 2 indent levels) +# false: only indent 1 level, don't add the indent for the open brace, only +# add the indent for the return. +# +# Default: true +indent_compound_literal_return = true # true/false + +# (C#) Whether to indent a 'using' block if no braces are used. +# +# Default: true +indent_using_block = true # true/false + +# How to indent the continuation of ternary operator. +# +# 0: Off (default) +# 1: When the `if_false` is a continuation, indent it under the `if_true` branch +# 2: When the `:` is a continuation, indent it under `?` +indent_ternary_operator = 0 # unsigned number + +# Whether to indent the statements inside ternary operator. +indent_inside_ternary_operator = false # true/false + +# If true, the indentation of the chunks after a `return` sequence will be set at return indentation column. +indent_off_after_return = false # true/false + +# If true, the indentation of the chunks after a `return new` sequence will be set at return indentation column. +indent_off_after_return_new = false # true/false + +# If true, the tokens after return are indented with regular single indentation. By default (false) the indentation is after the return token. +indent_single_after_return = false # true/false + +# Whether to ignore indent and alignment for 'asm' blocks (i.e. assume they +# have their own indentation). +indent_ignore_asm_block = false # true/false + +# Don't indent the close parenthesis of a function definition, +# if the parenthesis is on its own line. +donot_indent_func_def_close_paren = false # true/false + +# +# Newline adding and removing options +# + +# Whether to collapse empty blocks between '{' and '}' except for functions. +# Use nl_collapse_empty_body_functions to specify how empty function braces +# should be formatted. +nl_collapse_empty_body = false # true/false + +# Whether to collapse empty blocks between '{' and '}' for functions only. +# If true, overrides nl_inside_empty_func. +nl_collapse_empty_body_functions = false # true/false + +# Don't split one-line braced assignments, as in 'foo_t f = { 1, 2 };'. +nl_assign_leave_one_liners = false # true/false + +# Don't split one-line braced statements inside a 'class xx { }' body. +nl_class_leave_one_liners = false # true/false + +# Don't split one-line enums, as in 'enum foo { BAR = 15 };' +nl_enum_leave_one_liners = false # true/false + +# Don't split one-line get or set functions. +nl_getset_leave_one_liners = false # true/false + +# (C#) Don't split one-line property get or set functions. +nl_cs_property_leave_one_liners = false # true/false + +# Don't split one-line function definitions, as in 'int foo() { return 0; }'. +# might modify nl_func_type_name +nl_func_leave_one_liners = false # true/false + +# Don't split one-line C++11 lambdas, as in '[]() { return 0; }'. +nl_cpp_lambda_leave_one_liners = false # true/false + +# Don't split one-line if/else statements, as in 'if(...) b++;'. +nl_if_leave_one_liners = false # true/false + +# Don't split one-line while statements, as in 'while(...) b++;'. +nl_while_leave_one_liners = false # true/false + +# Don't split one-line do statements, as in 'do { b++; } while(...);'. +nl_do_leave_one_liners = false # true/false + +# Don't split one-line for statements, as in 'for(...) b++;'. +nl_for_leave_one_liners = false # true/false + +# (OC) Don't split one-line Objective-C messages. +nl_oc_msg_leave_one_liner = false # true/false + +# (OC) Add or remove newline between method declaration and '{'. +nl_oc_mdef_brace = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove newline between Objective-C block signature and '{'. +nl_oc_block_brace = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove blank line before '@interface' statement. +nl_oc_before_interface = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove blank line before '@implementation' statement. +nl_oc_before_implementation = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove blank line before '@end' statement. +nl_oc_before_end = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove newline between '@interface' and '{'. +nl_oc_interface_brace = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove newline between '@implementation' and '{'. +nl_oc_implementation_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newlines at the start of the file. +nl_start_of_file = ignore # ignore/add/remove/force/not_defined + +# The minimum number of newlines at the start of the file (only used if +# nl_start_of_file is 'add' or 'force'). +nl_start_of_file_min = 0 # unsigned number + +# Add or remove newline at the end of the file. +nl_end_of_file = ignore # ignore/add/remove/force/not_defined + +# The minimum number of newlines at the end of the file (only used if +# nl_end_of_file is 'add' or 'force'). +nl_end_of_file_min = 0 # unsigned number + +# Add or remove newline between '=' and '{'. +nl_assign_brace = remove # ignore/add/remove/force/not_defined + +# (D) Add or remove newline between '=' and '['. +nl_assign_square = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '[]' and '{'. +nl_tsquare_brace = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove newline after '= ['. Will also affect the newline before +# the ']'. +nl_after_square_assign = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between a function call's ')' and '{', as in +# 'list_for_each(item, &list) { }'. +nl_fcall_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'enum' and '{'. +nl_enum_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'enum' and 'class'. +nl_enum_class = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'enum class' and the identifier. +nl_enum_class_identifier = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'enum class' type and ':'. +nl_enum_identifier_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'enum class identifier :' and type. +nl_enum_colon_type = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'struct and '{'. +nl_struct_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'union' and '{'. +nl_union_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'if' and '{'. +nl_if_brace = remove # ignore/add/remove/force/not_defined + +# Add or remove newline between '}' and 'else'. +nl_brace_else = remove # ignore/add/remove/force/not_defined + +# Add or remove newline between 'else if' and '{'. If set to ignore, +# nl_if_brace is used instead. +nl_elseif_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'else' and '{'. +nl_else_brace = remove # ignore/add/remove/force/not_defined + +# Add or remove newline between 'else' and 'if'. +nl_else_if = remove # ignore/add/remove/force/not_defined + +# Add or remove newline before '{' opening brace +nl_before_opening_brace_func_class_def = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline before 'if'/'else if' closing parenthesis. +nl_before_if_closing_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '}' and 'finally'. +nl_brace_finally = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'finally' and '{'. +nl_finally_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'try' and '{'. +nl_try_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between get/set and '{'. +nl_getset_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'for' and '{'. +nl_for_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline before the '{' of a 'catch' statement, as in +# 'catch (decl) {'. +nl_catch_brace = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove newline before the '{' of a '@catch' statement, as in +# '@catch (decl) {'. If set to ignore, nl_catch_brace is used. +nl_oc_catch_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '}' and 'catch'. +nl_brace_catch = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove newline between '}' and '@catch'. If set to ignore, +# nl_brace_catch is used. +nl_oc_brace_catch = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '}' and ']'. +nl_brace_square = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '}' and ')' in a function invocation. +nl_brace_fparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'while' and '{'. +nl_while_brace = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove newline between 'scope (x)' and '{'. +nl_scope_brace = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove newline between 'unittest' and '{'. +nl_unittest_brace = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove newline between 'version (x)' and '{'. +nl_version_brace = ignore # ignore/add/remove/force/not_defined + +# (C#) Add or remove newline between 'using' and '{'. +nl_using_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between two open or close braces. Due to general +# newline/brace handling, REMOVE may not work. +nl_brace_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'do' and '{'. +nl_do_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '}' and 'while' of 'do' statement. +nl_brace_while = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'switch' and '{'. +nl_switch_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'synchronized' and '{'. +nl_synchronized_brace = ignore # ignore/add/remove/force/not_defined + +# Add a newline between ')' and '{' if the ')' is on a different line than the +# if/for/etc. +# +# Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch and +# nl_catch_brace. +nl_multi_line_cond = false # true/false + +# Add a newline after '(' if an if/for/while/switch condition spans multiple +# lines +nl_multi_line_sparen_open = ignore # ignore/add/remove/force/not_defined + +# Add a newline before ')' if an if/for/while/switch condition spans multiple +# lines. Overrides nl_before_if_closing_paren if both are specified. +nl_multi_line_sparen_close = ignore # ignore/add/remove/force/not_defined + +# Force a newline in a define after the macro name for multi-line defines. +nl_multi_line_define = false # true/false + +# Whether to add a newline before 'case', and a blank line before a 'case' +# statement that follows a ';' or '}'. +nl_before_case = false # true/false + +# Whether to add a newline after a 'case' statement. +nl_after_case = false # true/false + +# Add or remove newline between a case ':' and '{'. +# +# Overrides nl_after_case. +nl_case_colon_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between ')' and 'throw'. +nl_before_throw = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'namespace' and '{'. +nl_namespace_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template class. +nl_template_class = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template class declaration. +# +# Overrides nl_template_class. +nl_template_class_decl = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<>' of a specialized class declaration. +# +# Overrides nl_template_class_decl. +nl_template_class_decl_special = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template class definition. +# +# Overrides nl_template_class. +nl_template_class_def = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<>' of a specialized class definition. +# +# Overrides nl_template_class_def. +nl_template_class_def_special = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template function. +nl_template_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template function +# declaration. +# +# Overrides nl_template_func. +nl_template_func_decl = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<>' of a specialized function +# declaration. +# +# Overrides nl_template_func_decl. +nl_template_func_decl_special = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template function +# definition. +# +# Overrides nl_template_func. +nl_template_func_def = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<>' of a specialized function +# definition. +# +# Overrides nl_template_func_def. +nl_template_func_def_special = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template variable. +nl_template_var = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'template<...>' and 'using' of a templated +# type alias. +nl_template_using = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'class' and '{'. +nl_class_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline before or after (depending on pos_class_comma, +# may not be IGNORE) each',' in the base class list. +nl_class_init_args = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after each ',' in the constructor member +# initialization. Related to nl_constr_colon, pos_constr_colon and +# pos_constr_comma. +nl_constr_init_args = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline before first element, after comma, and after last +# element, in 'enum'. +nl_enum_own_lines = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between return type and function name in a function +# definition. +# might be modified by nl_func_leave_one_liners +nl_func_type_name = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between return type and function name inside a class +# definition. If set to ignore, nl_func_type_name or nl_func_proto_type_name +# is used instead. +nl_func_type_name_class = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between class specification and '::' +# in 'void A::f() { }'. Only appears in separate member implementation (does +# not appear with in-line implementation). +nl_func_class_scope = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between function scope and name, as in +# 'void A :: f() { }'. +nl_func_scope_name = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between return type and function name in a prototype. +nl_func_proto_type_name = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between a function name and the opening '(' in the +# declaration. +nl_func_paren = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_paren for functions with no parameters. +nl_func_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between a function name and the opening '(' in the +# definition. +nl_func_def_paren = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_def_paren for functions with no parameters. +nl_func_def_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between a function name and the opening '(' in the +# call. +nl_func_call_paren = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_call_paren for functions with no parameters. +nl_func_call_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after '(' in a function declaration. +nl_func_decl_start = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after '(' in a function definition. +nl_func_def_start = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_decl_start when there is only one parameter. +nl_func_decl_start_single = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_def_start when there is only one parameter. +nl_func_def_start_single = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline after '(' in a function declaration if '(' and ')' +# are in different lines. If false, nl_func_decl_start is used instead. +nl_func_decl_start_multi_line = false # true/false + +# Whether to add a newline after '(' in a function definition if '(' and ')' +# are in different lines. If false, nl_func_def_start is used instead. +nl_func_def_start_multi_line = false # true/false + +# Add or remove newline after each ',' in a function declaration. +nl_func_decl_args = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after each ',' in a function definition. +nl_func_def_args = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after each ',' in a function call. +nl_func_call_args = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline after each ',' in a function declaration if '(' +# and ')' are in different lines. If false, nl_func_decl_args is used instead. +nl_func_decl_args_multi_line = false # true/false + +# Whether to add a newline after each ',' in a function definition if '(' +# and ')' are in different lines. If false, nl_func_def_args is used instead. +nl_func_def_args_multi_line = false # true/false + +# Add or remove newline before the ')' in a function declaration. +nl_func_decl_end = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline before the ')' in a function definition. +nl_func_def_end = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_decl_end when there is only one parameter. +nl_func_decl_end_single = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_def_end when there is only one parameter. +nl_func_def_end_single = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline before ')' in a function declaration if '(' and ')' +# are in different lines. If false, nl_func_decl_end is used instead. +nl_func_decl_end_multi_line = false # true/false + +# Whether to add a newline before ')' in a function definition if '(' and ')' +# are in different lines. If false, nl_func_def_end is used instead. +nl_func_def_end_multi_line = false # true/false + +# Add or remove newline between '()' in a function declaration. +nl_func_decl_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '()' in a function definition. +nl_func_def_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '()' in a function call. +nl_func_call_empty = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline after '(' in a function call, +# has preference over nl_func_call_start_multi_line. +nl_func_call_start = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline before ')' in a function call. +nl_func_call_end = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline after '(' in a function call if '(' and ')' are in +# different lines. +nl_func_call_start_multi_line = false # true/false + +# Whether to add a newline after each ',' in a function call if '(' and ')' +# are in different lines. +nl_func_call_args_multi_line = false # true/false + +# Whether to add a newline before ')' in a function call if '(' and ')' are in +# different lines. +nl_func_call_end_multi_line = false # true/false + +# Whether to respect nl_func_call_XXX option in case of closure args. +nl_func_call_args_multi_line_ignore_closures = false # true/false + +# Whether to add a newline after '<' of a template parameter list. +nl_template_start = false # true/false + +# Whether to add a newline after each ',' in a template parameter list. +nl_template_args = false # true/false + +# Whether to add a newline before '>' of a template parameter list. +nl_template_end = false # true/false + +# (OC) Whether to put each Objective-C message parameter on a separate line. +# See nl_oc_msg_leave_one_liner. +nl_oc_msg_args = false # true/false + +# (OC) Minimum number of Objective-C message parameters before applying nl_oc_msg_args. +nl_oc_msg_args_min_params = 0 # unsigned number + +# (OC) Max code width of Objective-C message before applying nl_oc_msg_args. +nl_oc_msg_args_max_code_width = 0 # unsigned number + +# Add or remove newline between function signature and '{'. +nl_fdef_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between function signature and '{', +# if signature ends with ')'. Overrides nl_fdef_brace. +nl_fdef_brace_cond = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between C++11 lambda signature and '{'. +nl_cpp_ldef_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'return' and the return expression. +nl_return_expr = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'throw' and the throw expression. +nl_throw_expr = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline after semicolons, except in 'for' statements. +nl_after_semicolon = false # true/false + +# (Java) Add or remove newline between the ')' and '{{' of the double brace +# initializer. +nl_paren_dbrace_open = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline after the type in an unnamed temporary +# direct-list-initialization, better: +# before a direct-list-initialization. +nl_type_brace_init_lst = remove # ignore/add/remove/force/not_defined + +# Whether to add a newline after the open brace in an unnamed temporary +# direct-list-initialization. +nl_type_brace_init_lst_open = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline before the close brace in an unnamed temporary +# direct-list-initialization. +nl_type_brace_init_lst_close = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline before '{'. +nl_before_brace_open = false # true/false + +# Whether to add a newline after '{'. +nl_after_brace_open = false # true/false + +# Whether to add a newline between the open brace and a trailing single-line +# comment. Requires nl_after_brace_open=true. +nl_after_brace_open_cmt = false # true/false + +# Whether to add a newline after a virtual brace open with a non-empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open = false # true/false + +# Whether to add a newline after a virtual brace open with an empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open_empty = false # true/false + +# Whether to add a newline after '}'. Does not apply if followed by a +# necessary ';'. +nl_after_brace_close = false # true/false + +# Whether to add a newline after a virtual brace close, +# as in 'if (foo) a++; return;'. +nl_after_vbrace_close = false # true/false + +# Add or remove newline between the close brace and identifier, +# as in 'struct { int a; } b;'. Affects enumerations, unions and +# structures. If set to ignore, uses nl_after_brace_close. +nl_brace_struct_var = ignore # ignore/add/remove/force/not_defined + +# Whether to alter newlines in '#define' macros. +nl_define_macro = false # true/false + +# Whether to alter newlines between consecutive parenthesis closes. The number +# of closing parentheses in a line will depend on respective open parenthesis +# lines. +nl_squeeze_paren_close = false # true/false + +# Whether to remove blanks after '#ifxx' and '#elxx', or before '#elxx' and +# '#endif'. Does not affect top-level #ifdefs. +nl_squeeze_ifdef = false # true/false + +# Makes the nl_squeeze_ifdef option affect the top-level #ifdefs as well. +nl_squeeze_ifdef_top_level = false # true/false + +# Add or remove blank line before 'if'. +nl_before_if = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line after 'if' statement. Add/Force work only if the +# next token is not a closing brace. +nl_after_if = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line before 'for'. +nl_before_for = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line after 'for' statement. +nl_after_for = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line before 'while'. +nl_before_while = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line after 'while' statement. +nl_after_while = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line before 'switch'. +nl_before_switch = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line after 'switch' statement. +nl_after_switch = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line before 'synchronized'. +nl_before_synchronized = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line after 'synchronized' statement. +nl_after_synchronized = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line before 'do'. +nl_before_do = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line after 'do/while' statement. +nl_after_do = ignore # ignore/add/remove/force/not_defined + +# Ignore nl_before_{if,for,switch,do,synchronized} if the control +# statement is immediately after a case statement. +# if nl_before_{if,for,switch,do} is set to remove, this option +# does nothing. +nl_before_ignore_after_case = false # true/false + +# Whether to put a blank line before 'return' statements, unless after an open +# brace. +nl_before_return = false # true/false + +# Whether to put a blank line after 'return' statements, unless followed by a +# close brace. +nl_after_return = false # true/false + +# Whether to put a blank line before a member '.' or '->' operators. +nl_before_member = ignore # ignore/add/remove/force/not_defined + +# (Java) Whether to put a blank line after a member '.' or '->' operators. +nl_after_member = ignore # ignore/add/remove/force/not_defined + +# Whether to double-space commented-entries in 'struct'/'union'/'enum'. +nl_ds_struct_enum_cmt = false # true/false + +# Whether to force a newline before '}' of a 'struct'/'union'/'enum'. +# (Lower priority than eat_blanks_before_close_brace.) +nl_ds_struct_enum_close_brace = false # true/false + +# Add or remove newline before or after (depending on pos_class_colon) a class +# colon, as in 'class Foo : public Bar'. +nl_class_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline around a class constructor colon. The exact position +# depends on nl_constr_init_args, pos_constr_colon and pos_constr_comma. +nl_constr_colon = ignore # ignore/add/remove/force/not_defined + +# Whether to collapse a two-line namespace, like 'namespace foo\n{ decl; }' +# into a single line. If true, prevents other brace newline rules from turning +# such code into four lines. If true, it also preserves one-liner namespaces. +nl_namespace_two_to_one_liner = false # true/false + +# Whether to remove a newline in simple unbraced if statements, turning them +# into one-liners, as in 'if(b)\n i++;' => 'if(b) i++;'. +nl_create_if_one_liner = false # true/false + +# Whether to remove a newline in simple unbraced for statements, turning them +# into one-liners, as in 'for (...)\n stmt;' => 'for (...) stmt;'. +nl_create_for_one_liner = false # true/false + +# Whether to remove a newline in simple unbraced while statements, turning +# them into one-liners, as in 'while (expr)\n stmt;' => 'while (expr) stmt;'. +nl_create_while_one_liner = false # true/false + +# Whether to collapse a function definition whose body (not counting braces) +# is only one line so that the entire definition (prototype, braces, body) is +# a single line. +nl_create_func_def_one_liner = false # true/false + +# Whether to split one-line simple list definitions into three lines by +# adding newlines, as in 'int a[12] = { 0 };'. +nl_create_list_one_liner = false # true/false + +# Whether to split one-line simple unbraced if statements into two lines by +# adding a newline, as in 'if(b) i++;'. +nl_split_if_one_liner = false # true/false + +# Whether to split one-line simple unbraced for statements into two lines by +# adding a newline, as in 'for (...) stmt;'. +nl_split_for_one_liner = false # true/false + +# Whether to split one-line simple unbraced while statements into two lines by +# adding a newline, as in 'while (expr) stmt;'. +nl_split_while_one_liner = false # true/false + +# Don't add a newline before a cpp-comment in a parameter list of a function +# call. +donot_add_nl_before_cpp_comment = false # true/false + +# +# Blank line options +# + +# The maximum number of consecutive newlines (3 = 2 blank lines). +nl_max = 0 # unsigned number + +# The maximum number of consecutive newlines in a function. +nl_max_blank_in_func = 0 # unsigned number + +# The number of newlines inside an empty function body. +# This option overrides eat_blanks_after_open_brace and +# eat_blanks_before_close_brace, but is ignored when +# nl_collapse_empty_body_functions=true +nl_inside_empty_func = 0 # unsigned number + +# The number of newlines before a function prototype. +nl_before_func_body_proto = 0 # unsigned number + +# The number of newlines before a multi-line function definition. Where +# applicable, this option is overridden with eat_blanks_after_open_brace=true +nl_before_func_body_def = 0 # unsigned number + +# The number of newlines before a class constructor/destructor prototype. +nl_before_func_class_proto = 0 # unsigned number + +# The number of newlines before a class constructor/destructor definition. +nl_before_func_class_def = 0 # unsigned number + +# The number of newlines after a function prototype. +nl_after_func_proto = 0 # unsigned number + +# The number of newlines after a function prototype, if not followed by +# another function prototype. +nl_after_func_proto_group = 0 # unsigned number + +# The number of newlines after a class constructor/destructor prototype. +nl_after_func_class_proto = 0 # unsigned number + +# The number of newlines after a class constructor/destructor prototype, +# if not followed by another constructor/destructor prototype. +nl_after_func_class_proto_group = 0 # unsigned number + +# Whether one-line method definitions inside a class body should be treated +# as if they were prototypes for the purposes of adding newlines. +# +# Requires nl_class_leave_one_liners=true. Overrides nl_before_func_body_def +# and nl_before_func_class_def for one-liners. +nl_class_leave_one_liner_groups = false # true/false + +# The number of newlines after '}' of a multi-line function body. +nl_after_func_body = 0 # unsigned number + +# The number of newlines after '}' of a multi-line function body in a class +# declaration. Also affects class constructors/destructors. +# +# Overrides nl_after_func_body. +nl_after_func_body_class = 0 # unsigned number + +# The number of newlines after '}' of a single line function body. Also +# affects class constructors/destructors. +# +# Overrides nl_after_func_body and nl_after_func_body_class. +nl_after_func_body_one_liner = 0 # unsigned number + +# The number of newlines before a block of typedefs. If nl_after_access_spec +# is non-zero, that option takes precedence. +# +# 0: No change (default). +nl_typedef_blk_start = 0 # unsigned number + +# The number of newlines after a block of typedefs. +# +# 0: No change (default). +nl_typedef_blk_end = 0 # unsigned number + +# The maximum number of consecutive newlines within a block of typedefs. +# +# 0: No change (default). +nl_typedef_blk_in = 0 # unsigned number + +# The minimum number of blank lines after a block of variable definitions +# at the top of a function body. If any preprocessor directives appear +# between the opening brace of the function and the variable block, then +# it is considered as not at the top of the function.Newlines are added +# before trailing preprocessor directives, if any exist. +# +# 0: No change (default). +nl_var_def_blk_end_func_top = 0 # unsigned number + +# The minimum number of empty newlines before a block of variable definitions +# not at the top of a function body. If nl_after_access_spec is non-zero, +# that option takes precedence. Newlines are not added at the top of the +# file or just after an opening brace. Newlines are added above any +# preprocessor directives before the block. +# +# 0: No change (default). +nl_var_def_blk_start = 0 # unsigned number + +# The minimum number of empty newlines after a block of variable definitions +# not at the top of a function body. Newlines are not added if the block +# is at the bottom of the file or just before a preprocessor directive. +# +# 0: No change (default). +nl_var_def_blk_end = 0 # unsigned number + +# The maximum number of consecutive newlines within a block of variable +# definitions. +# +# 0: No change (default). +nl_var_def_blk_in = 0 # unsigned number + +# The minimum number of newlines before a multi-line comment. +# Doesn't apply if after a brace open or another multi-line comment. +nl_before_block_comment = 0 # unsigned number + +# The minimum number of newlines before a single-line C comment. +# Doesn't apply if after a brace open or other single-line C comments. +nl_before_c_comment = 0 # unsigned number + +# The minimum number of newlines before a CPP comment. +# Doesn't apply if after a brace open or other CPP comments. +nl_before_cpp_comment = 0 # unsigned number + +# Whether to force a newline after a multi-line comment. +nl_after_multiline_comment = false # true/false + +# Whether to force a newline after a label's colon. +nl_after_label_colon = false # true/false + +# The number of newlines before a struct definition. +nl_before_struct = 0 # unsigned number + +# The number of newlines after '}' or ';' of a struct/enum/union definition. +nl_after_struct = 0 # unsigned number + +# The number of newlines before a class definition. +nl_before_class = 0 # unsigned number + +# The number of newlines after '}' or ';' of a class definition. +nl_after_class = 0 # unsigned number + +# The number of newlines before a namespace. +nl_before_namespace = 0 # unsigned number + +# The number of newlines after '{' of a namespace. This also adds newlines +# before the matching '}'. +# +# 0: Apply eat_blanks_after_open_brace or eat_blanks_before_close_brace if +# applicable, otherwise no change. +# +# Overrides eat_blanks_after_open_brace and eat_blanks_before_close_brace. +nl_inside_namespace = 0 # unsigned number + +# The number of newlines after '}' of a namespace. +nl_after_namespace = 0 # unsigned number + +# The number of newlines before an access specifier label. This also includes +# the Qt-specific 'signals:' and 'slots:'. Will not change the newline count +# if after a brace open. +# +# 0: No change (default). +nl_before_access_spec = 0 # unsigned number + +# The number of newlines after an access specifier label. This also includes +# the Qt-specific 'signals:' and 'slots:'. Will not change the newline count +# if after a brace open. +# +# 0: No change (default). +# +# Overrides nl_typedef_blk_start and nl_var_def_blk_start. +nl_after_access_spec = 0 # unsigned number + +# The number of newlines between a function definition and the function +# comment, as in '// comment\n void foo() {...}'. +# +# 0: No change (default). +nl_comment_func_def = 0 # unsigned number + +# The number of newlines after a try-catch-finally block that isn't followed +# by a brace close. +# +# 0: No change (default). +nl_after_try_catch_finally = 0 # unsigned number + +# (C#) The number of newlines before and after a property, indexer or event +# declaration. +# +# 0: No change (default). +nl_around_cs_property = 0 # unsigned number + +# (C#) The number of newlines between the get/set/add/remove handlers. +# +# 0: No change (default). +nl_between_get_set = 0 # unsigned number + +# (C#) Add or remove newline between property and the '{'. +nl_property_brace = ignore # ignore/add/remove/force/not_defined + +# Whether to remove blank lines after '{'. +eat_blanks_after_open_brace = false # true/false + +# Whether to remove blank lines before '}'. +eat_blanks_before_close_brace = false # true/false + +# How aggressively to remove extra newlines not in preprocessor. +# +# 0: No change (default) +# 1: Remove most newlines not handled by other config +# 2: Remove all newlines and reformat completely by config +nl_remove_extra_newlines = 0 # unsigned number + +# (Java) Add or remove newline after an annotation statement. Only affects +# annotations that are after a newline. +nl_after_annotation = ignore # ignore/add/remove/force/not_defined + +# (Java) Add or remove newline between two annotations. +nl_between_annotation = ignore # ignore/add/remove/force/not_defined + +# The number of newlines before a whole-file #ifdef. +# +# 0: No change (default). +nl_before_whole_file_ifdef = 0 # unsigned number + +# The number of newlines after a whole-file #ifdef. +# +# 0: No change (default). +nl_after_whole_file_ifdef = 0 # unsigned number + +# The number of newlines before a whole-file #endif. +# +# 0: No change (default). +nl_before_whole_file_endif = 0 # unsigned number + +# The number of newlines after a whole-file #endif. +# +# 0: No change (default). +nl_after_whole_file_endif = 0 # unsigned number + +# +# Positioning options +# + +# The position of arithmetic operators in wrapped expressions. +pos_arith = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of assignment in wrapped expressions. Do not affect '=' +# followed by '{'. +pos_assign = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of Boolean operators in wrapped expressions. +pos_bool = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of comparison operators in wrapped expressions. +pos_compare = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of conditional operators, as in the '?' and ':' of +# 'expr ? stmt : stmt', in wrapped expressions. +pos_conditional = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of the comma in wrapped expressions. +pos_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of the comma in enum entries. +pos_enum_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of the comma in the base class list if there is more than one +# line. Affects nl_class_init_args. +pos_class_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of the comma in the constructor initialization list. +# Related to nl_constr_colon, nl_constr_init_args and pos_constr_colon. +pos_constr_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of trailing/leading class colon, between class and base class +# list. Affects nl_class_colon. +pos_class_colon = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of colons between constructor and member initialization. +# Related to nl_constr_colon, nl_constr_init_args and pos_constr_comma. +pos_constr_colon = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of shift operators in wrapped expressions. +pos_shift = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# +# Line splitting options +# + +# Try to limit code width to N columns. +code_width = 0 # unsigned number + +# Whether to fully split long 'for' statements at semi-colons. +ls_for_split_full = false # true/false + +# Whether to fully split long function prototypes/calls at commas. +# The option ls_code_width has priority over the option ls_func_split_full. +ls_func_split_full = false # true/false + +# Whether to split lines as close to code_width as possible and ignore some +# groupings. +# The option ls_code_width has priority over the option ls_func_split_full. +ls_code_width = false # true/false + +# +# Code alignment options (not left column spaces/tabs) +# + +# Whether to keep non-indenting tabs. +align_keep_tabs = false # true/false + +# Whether to use tabs for aligning. +align_with_tabs = false # true/false + +# Whether to bump out to the next tab when aligning. +align_on_tabstop = false # true/false + +# Whether to right-align numbers. +align_number_right = false # true/false + +# Whether to keep whitespace not required for alignment. +align_keep_extra_space = false # true/false + +# Whether to align variable definitions in prototypes and functions. +align_func_params = false # true/false + +# The span for aligning parameter definitions in function on parameter name. +# +# 0: Don't align (default). +align_func_params_span = 0 # unsigned number + +# The threshold for aligning function parameter definitions. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_func_params_thresh = 0 # number + +# The gap for aligning function parameter definitions. +align_func_params_gap = 0 # unsigned number + +# The span for aligning constructor value. +# +# 0: Don't align (default). +align_constr_value_span = 0 # unsigned number + +# The threshold for aligning constructor value. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_constr_value_thresh = 0 # number + +# The gap for aligning constructor value. +align_constr_value_gap = 0 # unsigned number + +# Whether to align parameters in single-line functions that have the same +# name. The function names must already be aligned with each other. +align_same_func_call_params = false # true/false + +# The span for aligning function-call parameters for single line functions. +# +# 0: Don't align (default). +align_same_func_call_params_span = 0 # unsigned number + +# The threshold for aligning function-call parameters for single line +# functions. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_same_func_call_params_thresh = 0 # number + +# The span for aligning variable definitions. +# +# 0: Don't align (default). +align_var_def_span = 0 # unsigned number + +# How to consider (or treat) the '*' in the alignment of variable definitions. +# +# 0: Part of the type 'void * foo;' (default) +# 1: Part of the variable 'void *foo;' +# 2: Dangling 'void *foo;' +# Dangling: the '*' will not be taken into account when aligning. +align_var_def_star_style = 0 # unsigned number + +# How to consider (or treat) the '&' in the alignment of variable definitions. +# +# 0: Part of the type 'long & foo;' (default) +# 1: Part of the variable 'long &foo;' +# 2: Dangling 'long &foo;' +# Dangling: the '&' will not be taken into account when aligning. +align_var_def_amp_style = 0 # unsigned number + +# The threshold for aligning variable definitions. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_var_def_thresh = 0 # number + +# The gap for aligning variable definitions. +align_var_def_gap = 0 # unsigned number + +# Whether to align the colon in struct bit fields. +align_var_def_colon = false # true/false + +# The gap for aligning the colon in struct bit fields. +align_var_def_colon_gap = 0 # unsigned number + +# Whether to align any attribute after the variable name. +align_var_def_attribute = false # true/false + +# Whether to align inline struct/enum/union variable definitions. +align_var_def_inline = false # true/false + +# The span for aligning on '=' in assignments. +# +# 0: Don't align (default). +align_assign_span = 0 # unsigned number + +# The span for aligning on '=' in function prototype modifier. +# +# 0: Don't align (default). +align_assign_func_proto_span = 0 # unsigned number + +# The threshold for aligning on '=' in assignments. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_assign_thresh = 0 # number + +# Whether to align on the left most assignment when multiple +# definitions are found on the same line. +# Depends on 'align_assign_span' and 'align_assign_thresh' settings. +align_assign_on_multi_var_defs = false # true/false + +# The span for aligning on '{' in braced init list. +# +# 0: Don't align (default). +align_braced_init_list_span = 0 # unsigned number + +# The threshold for aligning on '{' in braced init list. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_braced_init_list_thresh = 0 # number + +# How to apply align_assign_span to function declaration "assignments", i.e. +# 'virtual void foo() = 0' or '~foo() = {default|delete}'. +# +# 0: Align with other assignments (default) +# 1: Align with each other, ignoring regular assignments +# 2: Don't align +align_assign_decl_func = 0 # unsigned number + +# The span for aligning on '=' in enums. +# +# 0: Don't align (default). +align_enum_equ_span = 0 # unsigned number + +# The threshold for aligning on '=' in enums. +# Use a negative number for absolute thresholds. +# +# 0: no limit (default). +align_enum_equ_thresh = 0 # number + +# The span for aligning class member definitions. +# +# 0: Don't align (default). +align_var_class_span = 0 # unsigned number + +# The threshold for aligning class member definitions. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_var_class_thresh = 0 # number + +# The gap for aligning class member definitions. +align_var_class_gap = 0 # unsigned number + +# The span for aligning struct/union member definitions. +# +# 0: Don't align (default). +align_var_struct_span = 0 # unsigned number + +# The threshold for aligning struct/union member definitions. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_var_struct_thresh = 0 # number + +# The gap for aligning struct/union member definitions. +align_var_struct_gap = 0 # unsigned number + +# The span for aligning struct initializer values. +# +# 0: Don't align (default). +align_struct_init_span = 0 # unsigned number + +# The span for aligning single-line typedefs. +# +# 0: Don't align (default). +align_typedef_span = 0 # unsigned number + +# The minimum space between the type and the synonym of a typedef. +align_typedef_gap = 0 # unsigned number + +# How to align typedef'd functions with other typedefs. +# +# 0: Don't mix them at all (default) +# 1: Align the open parenthesis with the types +# 2: Align the function type name with the other type names +align_typedef_func = 0 # unsigned number + +# How to consider (or treat) the '*' in the alignment of typedefs. +# +# 0: Part of the typedef type, 'typedef int * pint;' (default) +# 1: Part of type name: 'typedef int *pint;' +# 2: Dangling: 'typedef int *pint;' +# Dangling: the '*' will not be taken into account when aligning. +align_typedef_star_style = 0 # unsigned number + +# How to consider (or treat) the '&' in the alignment of typedefs. +# +# 0: Part of the typedef type, 'typedef int & intref;' (default) +# 1: Part of type name: 'typedef int &intref;' +# 2: Dangling: 'typedef int &intref;' +# Dangling: the '&' will not be taken into account when aligning. +align_typedef_amp_style = 0 # unsigned number + +# The span for aligning comments that end lines. +# +# 0: Don't align (default). +align_right_cmt_span = 0 # unsigned number + +# Minimum number of columns between preceding text and a trailing comment in +# order for the comment to qualify for being aligned. Must be non-zero to have +# an effect. +align_right_cmt_gap = 0 # unsigned number + +# If aligning comments, whether to mix with comments after '}' and #endif with +# less than three spaces before the comment. +align_right_cmt_mix = false # true/false + +# Whether to only align trailing comments that are at the same brace level. +align_right_cmt_same_level = false # true/false + +# Minimum column at which to align trailing comments. Comments which are +# aligned beyond this column, but which can be aligned in a lesser column, +# may be "pulled in". +# +# 0: Ignore (default). +align_right_cmt_at_col = 0 # unsigned number + +# The span for aligning function prototypes. +# +# 0: Don't align (default). +align_func_proto_span = 0 # unsigned number + +# How to consider (or treat) the '*' in the alignment of function prototypes. +# +# 0: Part of the type 'void * foo();' (default) +# 1: Part of the function 'void *foo();' +# 2: Dangling 'void *foo();' +# Dangling: the '*' will not be taken into account when aligning. +align_func_proto_star_style = 0 # unsigned number + +# How to consider (or treat) the '&' in the alignment of function prototypes. +# +# 0: Part of the type 'long & foo();' (default) +# 1: Part of the function 'long &foo();' +# 2: Dangling 'long &foo();' +# Dangling: the '&' will not be taken into account when aligning. +align_func_proto_amp_style = 0 # unsigned number + +# The threshold for aligning function prototypes. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_func_proto_thresh = 0 # number + +# Minimum gap between the return type and the function name. +align_func_proto_gap = 0 # unsigned number + +# Whether to align function prototypes on the 'operator' keyword instead of +# what follows. +align_on_operator = false # true/false + +# Whether to mix aligning prototype and variable declarations. If true, +# align_var_def_XXX options are used instead of align_func_proto_XXX options. +align_mix_var_proto = false # true/false + +# Whether to align single-line functions with function prototypes. +# Uses align_func_proto_span. +align_single_line_func = false # true/false + +# Whether to align the open brace of single-line functions. +# Requires align_single_line_func=true. Uses align_func_proto_span. +align_single_line_brace = false # true/false + +# Gap for align_single_line_brace. +align_single_line_brace_gap = 0 # unsigned number + +# (OC) The span for aligning Objective-C message specifications. +# +# 0: Don't align (default). +align_oc_msg_spec_span = 0 # unsigned number + +# Whether to align macros wrapped with a backslash and a newline. This will +# not work right if the macro contains a multi-line comment. +align_nl_cont = false # true/false + +# Whether to align macro functions and variables together. +align_pp_define_together = false # true/false + +# The span for aligning on '#define' bodies. +# +# =0: Don't align (default) +# >0: Number of lines (including comments) between blocks +align_pp_define_span = 0 # unsigned number + +# The minimum space between label and value of a preprocessor define. +align_pp_define_gap = 0 # unsigned number + +# Whether to align lines that start with '<<' with previous '<<'. +# +# Default: true +align_left_shift = true # true/false + +# Whether to align comma-separated statements following '<<' (as used to +# initialize Eigen matrices). +align_eigen_comma_init = false # true/false + +# Whether to align text after 'asm volatile ()' colons. +align_asm_colon = false # true/false + +# (OC) Span for aligning parameters in an Objective-C message call +# on the ':'. +# +# 0: Don't align. +align_oc_msg_colon_span = 0 # unsigned number + +# (OC) Whether to always align with the first parameter, even if it is too +# short. +align_oc_msg_colon_first = false # true/false + +# (OC) Whether to align parameters in an Objective-C '+' or '-' declaration +# on the ':'. +align_oc_decl_colon = false # true/false + +# (OC) Whether to not align parameters in an Objectve-C message call if first +# colon is not on next line of the message call (the same way Xcode does +# alignment) +align_oc_msg_colon_xcode_like = false # true/false + +# +# Comment modification options +# + +# Try to wrap comments at N columns. +cmt_width = 0 # unsigned number + +# How to reflow comments. +# +# 0: No reflowing (apart from the line wrapping due to cmt_width) (default) +# 1: No touching at all +# 2: Full reflow (enable cmt_indent_multi for indent with line wrapping due to cmt_width) +cmt_reflow_mode = 0 # unsigned number + +# Path to a file that contains regular expressions describing patterns for +# which the end of one line and the beginning of the next will be folded into +# the same sentence or paragraph during full comment reflow. The regular +# expressions are described using ECMAScript syntax. The syntax for this +# specification is as follows, where "..." indicates the custom regular +# expression and "n" indicates the nth end_of_prev_line_regex and +# beg_of_next_line_regex regular expression pair: +# +# end_of_prev_line_regex[1] = "...$" +# beg_of_next_line_regex[1] = "^..." +# end_of_prev_line_regex[2] = "...$" +# beg_of_next_line_regex[2] = "^..." +# . +# . +# . +# end_of_prev_line_regex[n] = "...$" +# beg_of_next_line_regex[n] = "^..." +# +# Note that use of this option overrides the default reflow fold regular +# expressions, which are internally defined as follows: +# +# end_of_prev_line_regex[1] = "[\w,\]\)]$" +# beg_of_next_line_regex[1] = "^[\w,\[\(]" +# end_of_prev_line_regex[2] = "\.$" +# beg_of_next_line_regex[2] = "^[A-Z]" +cmt_reflow_fold_regex_file = "" # string + +# Whether to indent wrapped lines to the start of the encompassing paragraph +# during full comment reflow (cmt_reflow_mode = 2). Overrides the value +# specified by cmt_sp_after_star_cont. +# +# Note that cmt_align_doxygen_javadoc_tags overrides this option for +# paragraphs associated with javadoc tags +cmt_reflow_indent_to_paragraph_start = false # true/false + +# Whether to convert all tabs to spaces in comments. If false, tabs in +# comments are left alone, unless used for indenting. +cmt_convert_tab_to_spaces = false # true/false + +# Whether to apply changes to multi-line comments, including cmt_width, +# keyword substitution and leading chars. +# +# Default: true +cmt_indent_multi = true # true/false + +# Whether to align doxygen javadoc-style tags ('@param', '@return', etc.) +# and corresponding fields such that groups of consecutive block tags, +# parameter names, and descriptions align with one another. Overrides that +# which is specified by the cmt_sp_after_star_cont. If cmt_width > 0, it may +# be necessary to enable cmt_indent_multi and set cmt_reflow_mode = 2 +# in order to achieve the desired alignment for line-wrapping. +cmt_align_doxygen_javadoc_tags = false # true/false + +# The number of spaces to insert after the star and before doxygen +# javadoc-style tags (@param, @return, etc). Requires enabling +# cmt_align_doxygen_javadoc_tags. Overrides that which is specified by the +# cmt_sp_after_star_cont. +# +# Default: 1 +cmt_sp_before_doxygen_javadoc_tags = 1 # unsigned number + +# Whether to change trailing, single-line c-comments into cpp-comments. +cmt_trailing_single_line_c_to_cpp = false # true/false + +# Whether to group c-comments that look like they are in a block. +cmt_c_group = false # true/false + +# Whether to put an empty '/*' on the first line of the combined c-comment. +cmt_c_nl_start = false # true/false + +# Whether to add a newline before the closing '*/' of the combined c-comment. +cmt_c_nl_end = false # true/false + +# Whether to change cpp-comments into c-comments. +cmt_cpp_to_c = false # true/false + +# Whether to group cpp-comments that look like they are in a block. Only +# meaningful if cmt_cpp_to_c=true. +cmt_cpp_group = false # true/false + +# Whether to put an empty '/*' on the first line of the combined cpp-comment +# when converting to a c-comment. +# +# Requires cmt_cpp_to_c=true and cmt_cpp_group=true. +cmt_cpp_nl_start = false # true/false + +# Whether to add a newline before the closing '*/' of the combined cpp-comment +# when converting to a c-comment. +# +# Requires cmt_cpp_to_c=true and cmt_cpp_group=true. +cmt_cpp_nl_end = false # true/false + +# Whether to put a star on subsequent comment lines. +cmt_star_cont = false # true/false + +# The number of spaces to insert at the start of subsequent comment lines. +cmt_sp_before_star_cont = 0 # unsigned number + +# The number of spaces to insert after the star on subsequent comment lines. +cmt_sp_after_star_cont = 0 # unsigned number + +# For multi-line comments with a '*' lead, remove leading spaces if the first +# and last lines of the comment are the same length. +# +# Default: true +cmt_multi_check_last = true # true/false + +# For multi-line comments with a '*' lead, remove leading spaces if the first +# and last lines of the comment are the same length AND if the length is +# bigger as the first_len minimum. +# +# Default: 4 +cmt_multi_first_len_minimum = 4 # unsigned number + +# Path to a file that contains text to insert at the beginning of a file if +# the file doesn't start with a C/C++ comment. If the inserted text contains +# '$(filename)', that will be replaced with the current file's name. +cmt_insert_file_header = "" # string + +# Path to a file that contains text to insert at the end of a file if the +# file doesn't end with a C/C++ comment. If the inserted text contains +# '$(filename)', that will be replaced with the current file's name. +cmt_insert_file_footer = "" # string + +# Path to a file that contains text to insert before a function definition if +# the function isn't preceded by a C/C++ comment. If the inserted text +# contains '$(function)', '$(javaparam)' or '$(fclass)', these will be +# replaced with, respectively, the name of the function, the javadoc '@param' +# and '@return' stuff, or the name of the class to which the member function +# belongs. +cmt_insert_func_header = "" # string + +# Path to a file that contains text to insert before a class if the class +# isn't preceded by a C/C++ comment. If the inserted text contains '$(class)', +# that will be replaced with the class name. +cmt_insert_class_header = "" # string + +# Path to a file that contains text to insert before an Objective-C message +# specification, if the method isn't preceded by a C/C++ comment. If the +# inserted text contains '$(message)' or '$(javaparam)', these will be +# replaced with, respectively, the name of the function, or the javadoc +# '@param' and '@return' stuff. +cmt_insert_oc_msg_header = "" # string + +# Whether a comment should be inserted if a preprocessor is encountered when +# stepping backwards from a function name. +# +# Applies to cmt_insert_oc_msg_header, cmt_insert_func_header and +# cmt_insert_class_header. +cmt_insert_before_preproc = false # true/false + +# Whether a comment should be inserted if a function is declared inline to a +# class definition. +# +# Applies to cmt_insert_func_header. +# +# Default: true +cmt_insert_before_inlines = true # true/false + +# Whether a comment should be inserted if the function is a class constructor +# or destructor. +# +# Applies to cmt_insert_func_header. +cmt_insert_before_ctor_dtor = false # true/false + +# +# Code modifying options (non-whitespace) +# + +# Add or remove braces on a single-line 'do' statement. +mod_full_brace_do = force # ignore/add/remove/force/not_defined + +# Add or remove braces on a single-line 'for' statement. +mod_full_brace_for = force # ignore/add/remove/force/not_defined + +# (Pawn) Add or remove braces on a single-line function definition. +mod_full_brace_function = force # ignore/add/remove/force/not_defined + +# Add or remove braces on a single-line 'if' statement. Braces will not be +# removed if the braced statement contains an 'else'. +mod_full_brace_if = force # ignore/add/remove/force/not_defined + +# Whether to enforce that all blocks of an 'if'/'else if'/'else' chain either +# have, or do not have, braces. Overrides mod_full_brace_if. +# +# 0: Don't override mod_full_brace_if +# 1: Add braces to all blocks if any block needs braces and remove braces if +# they can be removed from all blocks +# 2: Add braces to all blocks if any block already has braces, regardless of +# whether it needs them +# 3: Add braces to all blocks if any block needs braces and remove braces if +# they can be removed from all blocks, except if all blocks have braces +# despite none needing them +mod_full_brace_if_chain = 0 # unsigned number + +# Whether to add braces to all blocks of an 'if'/'else if'/'else' chain. +# If true, mod_full_brace_if_chain will only remove braces from an 'if' that +# does not have an 'else if' or 'else'. +mod_full_brace_if_chain_only = false # true/false + +# Add or remove braces on single-line 'while' statement. +mod_full_brace_while = ignore # ignore/add/remove/force/not_defined + +# Add or remove braces on single-line 'using ()' statement. +mod_full_brace_using = ignore # ignore/add/remove/force/not_defined + +# Don't remove braces around statements that span N newlines +mod_full_brace_nl = 0 # unsigned number + +# Whether to prevent removal of braces from 'if'/'for'/'while'/etc. blocks +# which span multiple lines. +# +# Affects: +# mod_full_brace_for +# mod_full_brace_if +# mod_full_brace_if_chain +# mod_full_brace_if_chain_only +# mod_full_brace_while +# mod_full_brace_using +# +# Does not affect: +# mod_full_brace_do +# mod_full_brace_function +mod_full_brace_nl_block_rem_mlcond = false # true/false + +# Add or remove unnecessary parentheses on 'return' statement. +mod_paren_on_return = ignore # ignore/add/remove/force/not_defined + +# Add or remove unnecessary parentheses on 'throw' statement. +mod_paren_on_throw = ignore # ignore/add/remove/force/not_defined + +# (Pawn) Whether to change optional semicolons to real semicolons. +mod_pawn_semicolon = false # true/false + +# Whether to fully parenthesize Boolean expressions in 'while' and 'if' +# statement, as in 'if (a && b > c)' => 'if (a && (b > c))'. +mod_full_paren_if_bool = false # true/false + +# Whether to fully parenthesize Boolean expressions after '=' +# statement, as in 'x = a && b > c;' => 'x = (a && (b > c));'. +mod_full_paren_assign_bool = false # true/false + +# Whether to fully parenthesize Boolean expressions after '=' +# statement, as in 'return a && b > c;' => 'return (a && (b > c));'. +mod_full_paren_return_bool = false # true/false + +# Whether to remove superfluous semicolons. +mod_remove_extra_semicolon = false # true/false + +# Whether to remove duplicate include. +mod_remove_duplicate_include = false # true/false + +# If a function body exceeds the specified number of newlines and doesn't have +# a comment after the close brace, a comment will be added. +mod_add_long_function_closebrace_comment = 0 # unsigned number + +# If a namespace body exceeds the specified number of newlines and doesn't +# have a comment after the close brace, a comment will be added. +mod_add_long_namespace_closebrace_comment = 0 # unsigned number + +# If a class body exceeds the specified number of newlines and doesn't have a +# comment after the close brace, a comment will be added. +mod_add_long_class_closebrace_comment = 0 # unsigned number + +# If a switch body exceeds the specified number of newlines and doesn't have a +# comment after the close brace, a comment will be added. +mod_add_long_switch_closebrace_comment = 0 # unsigned number + +# If an #ifdef body exceeds the specified number of newlines and doesn't have +# a comment after the #endif, a comment will be added. +mod_add_long_ifdef_endif_comment = 0 # unsigned number + +# If an #ifdef or #else body exceeds the specified number of newlines and +# doesn't have a comment after the #else, a comment will be added. +mod_add_long_ifdef_else_comment = 0 # unsigned number + +# Whether to take care of the case by the mod_sort_xx options. +mod_sort_case_sensitive = false # true/false + +# Whether to sort consecutive single-line 'import' statements. +mod_sort_import = false # true/false + +# (C#) Whether to sort consecutive single-line 'using' statements. +mod_sort_using = false # true/false + +# Whether to sort consecutive single-line '#include' statements (C/C++) and +# '#import' statements (Objective-C). Be aware that this has the potential to +# break your code if your includes/imports have ordering dependencies. +mod_sort_include = false # true/false + +# Whether to prioritize '#include' and '#import' statements that contain +# filename without extension when sorting is enabled. +mod_sort_incl_import_prioritize_filename = false # true/false + +# Whether to prioritize '#include' and '#import' statements that does not +# contain extensions when sorting is enabled. +mod_sort_incl_import_prioritize_extensionless = false # true/false + +# Whether to prioritize '#include' and '#import' statements that contain +# angle over quotes when sorting is enabled. +mod_sort_incl_import_prioritize_angle_over_quotes = false # true/false + +# Whether to ignore file extension in '#include' and '#import' statements +# for sorting comparison. +mod_sort_incl_import_ignore_extension = false # true/false + +# Whether to group '#include' and '#import' statements when sorting is enabled. +mod_sort_incl_import_grouping_enabled = false # true/false + +# Whether to move a 'break' that appears after a fully braced 'case' before +# the close brace, as in 'case X: { ... } break;' => 'case X: { ... break; }'. +mod_move_case_break = false # true/false + +# Whether to move a 'return' that appears after a fully braced 'case' before +# the close brace, as in 'case X: { ... } return;' => 'case X: { ... return; }'. +mod_move_case_return = false # true/false + +# Add or remove braces around a fully braced case statement. Will only remove +# braces if there are no variable declarations in the block. +mod_case_brace = ignore # ignore/add/remove/force/not_defined + +# Whether to remove a void 'return;' that appears as the last statement in a +# function. +mod_remove_empty_return = false # true/false + +# Add or remove the comma after the last value of an enumeration. +mod_enum_last_comma = ignore # ignore/add/remove/force/not_defined + +# Syntax to use for infinite loops. +# +# 0: Leave syntax alone (default) +# 1: Rewrite as `for(;;)` +# 2: Rewrite as `while(true)` +# 3: Rewrite as `do`...`while(true);` +# 4: Rewrite as `while(1)` +# 5: Rewrite as `do`...`while(1);` +# +# Infinite loops that do not already match one of these syntaxes are ignored. +# Other options that affect loop formatting will be applied after transforming +# the syntax. +mod_infinite_loop = 0 # unsigned number + +# Add or remove the 'int' keyword in 'int short'. +mod_int_short = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'short int'. +mod_short_int = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'int long'. +mod_int_long = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'long int'. +mod_long_int = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'int signed'. +mod_int_signed = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'signed int'. +mod_signed_int = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'int unsigned'. +mod_int_unsigned = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'unsigned int'. +mod_unsigned_int = ignore # ignore/add/remove/force/not_defined + +# If there is a situation where mod_int_* and mod_*_int would result in +# multiple int keywords, whether to keep the rightmost int (the default) or the +# leftmost int. +mod_int_prefer_int_on_left = false # true/false + +# (OC) Whether to organize the properties. If true, properties will be +# rearranged according to the mod_sort_oc_property_*_weight factors. +mod_sort_oc_properties = false # true/false + +# (OC) Weight of a class property modifier. +mod_sort_oc_property_class_weight = 0 # number + +# (OC) Weight of 'atomic' and 'nonatomic'. +mod_sort_oc_property_thread_safe_weight = 0 # number + +# (OC) Weight of 'readwrite' when organizing properties. +mod_sort_oc_property_readwrite_weight = 0 # number + +# (OC) Weight of a reference type specifier ('retain', 'copy', 'assign', +# 'weak', 'strong') when organizing properties. +mod_sort_oc_property_reference_weight = 0 # number + +# (OC) Weight of getter type ('getter=') when organizing properties. +mod_sort_oc_property_getter_weight = 0 # number + +# (OC) Weight of setter type ('setter=') when organizing properties. +mod_sort_oc_property_setter_weight = 0 # number + +# (OC) Weight of nullability type ('nullable', 'nonnull', 'null_unspecified', +# 'null_resettable') when organizing properties. +mod_sort_oc_property_nullability_weight = 0 # number + +# +# Preprocessor options +# + +# How to use tabs when indenting preprocessor code. +# +# -1: Use 'indent_with_tabs' setting (default) +# 0: Spaces only +# 1: Indent with tabs to brace level, align with spaces +# 2: Indent and align with tabs, using spaces when not on a tabstop +# +# Default: -1 +pp_indent_with_tabs = -1 # number + +# Add or remove indentation of preprocessor directives inside #if blocks +# at brace level 0 (file-level). +pp_indent = add # ignore/add/remove/force/not_defined + +# Whether to indent #if/#else/#endif at the brace level. If false, these are +# indented from column 1. +pp_indent_at_level = true # true/false + +# Whether to indent #if/#else/#endif at the parenthesis level if the brace +# level is 0. If false, these are indented from column 1. +pp_indent_at_level0 = false # true/false + +# Specifies the number of columns to indent preprocessors per level +# at brace level 0 (file-level). If pp_indent_at_level=false, also specifies +# the number of columns to indent preprocessors per level +# at brace level > 0 (function-level). +# +# Default: 1 +pp_indent_count = 2 # unsigned number + +# Add or remove space after # based on pp level of #if blocks. +pp_space_after = ignore # ignore/add/remove/force/not_defined + +# Sets the number of spaces per level added with pp_space_after. +pp_space_count = 0 # unsigned number + +# The indent for '#region' and '#endregion' in C# and '#pragma region' in +# C/C++. Negative values decrease indent down to the first column. +pp_indent_region = 0 # number + +# Whether to indent the code between #region and #endregion. +pp_region_indent_code = false # true/false + +# If pp_indent_at_level=true, sets the indent for #if, #else and #endif when +# not at file-level. Negative values decrease indent down to the first column. +# +# =0: Indent preprocessors using output_tab_size +# >0: Column at which all preprocessors will be indented +pp_indent_if = 0 # number + +# Whether to indent the code between #if, #else and #endif. +pp_if_indent_code = false # true/false + +# Whether to indent the body of an #if that encompasses all the code in the file. +pp_indent_in_guard = false # true/false + +# Whether to indent '#define' at the brace level. If false, these are +# indented from column 1. +pp_define_at_level = false # true/false + +# Whether to indent '#include' at the brace level. +pp_include_at_level = false # true/false + +# Whether to ignore the '#define' body while formatting. +pp_ignore_define_body = false # true/false + +# An offset value that controls the indentation of the body of a multiline #define. +# 'body' refers to all the lines of a multiline #define except the first line. +# Requires 'pp_ignore_define_body = false'. +# +# <0: Absolute column: the body indentation starts off at the specified column +# (ex. -3 ==> the body is indented starting from column 3) +# >=0: Relative to the column of the '#' of '#define' +# (ex. 3 ==> the body is indented starting 3 columns at the right of '#') +# +# Default: 8 +pp_multiline_define_body_indent = 8 # number + +# Whether to indent case statements between #if, #else, and #endif. +# Only applies to the indent of the preprocessor that the case statements +# directly inside of. +# +# Default: true +pp_indent_case = true # true/false + +# Whether to indent whole function definitions between #if, #else, and #endif. +# Only applies to the indent of the preprocessor that the function definition +# is directly inside of. +# +# Default: true +pp_indent_func_def = true # true/false + +# Whether to indent extern C blocks between #if, #else, and #endif. +# Only applies to the indent of the preprocessor that the extern block is +# directly inside of. +# +# Default: true +pp_indent_extern = true # true/false + +# How to indent braces directly inside #if, #else, and #endif. +# Requires pp_if_indent_code=true and only applies to the indent of the +# preprocessor that the braces are directly inside of. +# 0: No extra indent +# 1: Indent by one level +# -1: Preserve original indentation +# +# Default: 1 +pp_indent_brace = 1 # number + +# Whether to print warning messages for unbalanced #if and #else blocks. +# This will print a message in the following cases: +# - if an #ifdef block ends on a different indent level than +# where it started from. Example: +# +# #ifdef TEST +# int i; +# { +# int j; +# #endif +# +# - an #elif/#else block ends on a different indent level than +# the corresponding #ifdef block. Example: +# +# #ifdef TEST +# int i; +# #else +# } +# int j; +# #endif +pp_warn_unbalanced_if = false # true/false + +# +# Sort includes options +# + +# The regex for include category with priority 0. +include_category_0 = "" # string + +# The regex for include category with priority 1. +include_category_1 = "" # string + +# The regex for include category with priority 2. +include_category_2 = "" # string + +# +# Use or Do not Use options +# + +# true: indent_func_call_param will be used (default) +# false: indent_func_call_param will NOT be used +# +# Default: true +use_indent_func_call_param = true # true/false + +# The value of the indentation for a continuation line is calculated +# differently if the statement is: +# - a declaration: your case with QString fileName ... +# - an assignment: your case with pSettings = new QSettings( ... +# +# At the second case the indentation value might be used twice: +# - at the assignment +# - at the function call (if present) +# +# To prevent the double use of the indentation value, use this option with the +# value 'true'. +# +# true: indent_continue will be used only once +# false: indent_continue will be used every time (default) +# +# Requires indent_ignore_first_continue=false. +use_indent_continue_only_once = false # true/false + +# The indentation can be: +# - after the assignment, at the '[' character +# - at the beginning of the lambda body +# +# true: indentation will be at the beginning of the lambda body +# false: indentation will be after the assignment (default) +indent_cpp_lambda_only_once = false # true/false + +# Whether sp_after_angle takes precedence over sp_inside_fparen. This was the +# historic behavior, but is probably not the desired behavior, so this is off +# by default. +use_sp_after_angle_always = false # true/false + +# Whether to apply special formatting for Qt SIGNAL/SLOT macros. Essentially, +# this tries to format these so that they match Qt's normalized form (i.e. the +# result of QMetaObject::normalizedSignature), which can slightly improve the +# performance of the QObject::connect call, rather than how they would +# otherwise be formatted. +# +# See options_for_QT.cpp for details. +# +# Default: true +use_options_overriding_for_qt_macros = true # true/false + +# If true: the form feed character is removed from the list of whitespace +# characters. See https://en.cppreference.com/w/cpp/string/byte/isspace. +use_form_feed_no_more_as_whitespace_character = false # true/false + +# +# Warn levels - 1: error, 2: warning (default), 3: note +# + +# (C#) Warning is given if doing tab-to-\t replacement and we have found one +# in a C# verbatim string literal. +# +# Default: 2 +warn_level_tabs_found_in_verbatim_string_literals = 2 # unsigned number + +# Limit the number of loops. +# Used by uncrustify.cpp to exit from infinite loop. +# 0: no limit. +debug_max_number_of_loops = 0 # number + +# Set the number of the line to protocol; +# Used in the function prot_the_line if the 2. parameter is zero. +# 0: nothing protocol. +debug_line_number_to_protocol = 0 # number + +# Set the number of second(s) before terminating formatting the current file, +# 0: no timeout. +# only for linux +debug_timeout = 0 # number + +# Set the number of characters to be printed if the text is too long, +# 0: do not truncate. +debug_truncate = 0 # unsigned number + +# sort (or not) the tracking info. +# +# Default: true +debug_sort_the_tracks = true # true/false + +# decode (or not) the flags as a new line. +# only if the -p option is set. +debug_decode_the_flags = false # true/false + +# insert the number of the line at the beginning of each line +set_numbering_for_html_output = false # true/false + +# Meaning of the settings: +# Ignore - do not do any changes +# Add - makes sure there is 1 or more space/brace/newline/etc +# Force - makes sure there is exactly 1 space/brace/newline/etc, +# behaves like Add in some contexts +# Remove - removes space/brace/newline/etc +# +# +# - Token(s) can be treated as specific type(s) with the 'set' option: +# `set tokenType tokenString [tokenString...]` +# +# Example: +# `set BOOL __AND__ __OR__` +# +# tokenTypes are defined in src/token_enum.h, use them without the +# 'CT_' prefix: 'CT_BOOL' => 'BOOL' +# +# +# - Token(s) can be treated as type(s) with the 'type' option. +# `type tokenString [tokenString...]` +# +# Example: +# `type int c_uint_8 Rectangle` +# +# This can also be achieved with `set TYPE int c_uint_8 Rectangle` +# +# +# To embed whitespace in tokenStrings use the '\' escape character, or quote +# the tokenStrings. These quotes are supported: "'` +# +# +# - Support for the auto detection of languages through the file ending can be +# added using the 'file_ext' command. +# `file_ext langType langString [langString..]` +# +# Example: +# `file_ext CPP .ch .cxx .cpp.in` +# +# langTypes are defined in uncrusify_types.h in the lang_flag_e enum, use +# them without the 'LANG_' prefix: 'LANG_CPP' => 'CPP' +# +# +# - Custom macro-based indentation can be set up using 'macro-open', +# 'macro-else' and 'macro-close'. +# `(macro-open | macro-else | macro-close) tokenString` +# +# Example: +# `macro-open BEGIN_TEMPLATE_MESSAGE_MAP` +# `macro-open BEGIN_MESSAGE_MAP` +# `macro-close END_MESSAGE_MAP` +# +# +# option(s) with 'not default' value: 0 +# diff --git a/lib/lib_rf/RadioLibTasmotaAlert.md b/lib/lib_rf/RadioLibTasmotaAlert.md new file mode 100644 index 000000000..3ffb450e7 --- /dev/null +++ b/lib/lib_rf/RadioLibTasmotaAlert.md @@ -0,0 +1,16 @@ +TasmotaAlert + +Action to take in case of new release of RadioLib + +20240327 + +1 - Remove folder `\lib\lib_rfRadioLib\examples\NonArduino` (Fixes Github vulnerability alerts) +2 - Change in file `\lib\lib_rf\RadioLib\src\ArduinoHal.cpp` below function (Fixes ESP8266 Panic core_esp8266_main.cpp:133 __yield) +``` +void inline ArduinoHal::yield() { + #if !defined(RADIOLIB_YIELD_UNSUPPORTED) +// ::yield(); + ::delay(0); + #endif +} +``` diff --git a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp index 6887ff594..1cc2ae2b3 100755 --- a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp +++ b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp @@ -34,6 +34,7 @@ #include "WiFiClientSecureLightBearSSL.h" // needs to be before "ESP8266WiFi.h" to avoid conflict with Arduino headers #include "ESP8266WiFi.h" +#include "WiFiHelper.h" #include "WiFiClient.h" #include "StackThunk_light.h" #include "lwip/opt.h" @@ -318,7 +319,7 @@ int WiFiClientSecure_light::connect(const char* name, uint16_t port, int32_t tim DEBUG_BSSL("connect(%s,%d)\n", name, port); IPAddress remote_addr; clearLastError(); - if (!WiFi.hostByName(name, remote_addr)) { + if (!WiFiHelper::hostByName(name, remote_addr)) { DEBUG_BSSL("connect: Name loopup failure\n"); setLastError(ERR_CANT_RESOLVE_IP); return 0; @@ -337,7 +338,7 @@ int WiFiClientSecure_light::connect(const char* name, uint16_t port) { DEBUG_BSSL("connect(%s,%d)\n", name, port); IPAddress remote_addr; clearLastError(); - if (!WiFi.hostByName(name, remote_addr)) { + if (!WiFiHelper::hostByName(name, remote_addr)) { DEBUG_BSSL("connect: Name loopup failure\n"); setLastError(ERR_CANT_RESOLVE_IP); return 0; @@ -557,11 +558,17 @@ int WiFiClientSecure_light::_run_until(unsigned target, bool blocking) { DEBUG_BSSL("_run_until: Not connected\n"); return -1; } + uint32_t t = millis(); for (int no_work = 0; blocking || no_work < 2;) { if (blocking) { // Only for blocking operations can we afford to yield() optimistic_yield(100); } + + if (((int32_t)(millis() - (t + this->_loopTimeout)) >= 0)){ + DEBUG_BSSL("_run_until: Timeout\n"); + return -1; + } int state; state = br_ssl_engine_current_state(_eng); diff --git a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h index a93960086..3f0a892a5 100755 --- a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h +++ b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h @@ -131,6 +131,7 @@ class WiFiClientSecure_light : public WiFiClient { } private: + uint32_t _loopTimeout=5000; void _clear(); bool _ctx_present; std::shared_ptr _sc; diff --git a/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_TCPClient.h b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_TCPClient.h index 9302f6d4e..43bb799d2 100644 --- a/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_TCPClient.h +++ b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_TCPClient.h @@ -46,6 +46,7 @@ #if defined(ESP32) +#include "ESP8266WiFi.h" #if defined(ESP_MAIL_WIFI_IS_AVAILABLE) #define WIFI_HAS_HOST_BY_NAME #endif @@ -456,7 +457,7 @@ public: int hostByName(const char *name, IPAddress &ip) { #if defined(ESP_MAIL_WIFI_IS_AVAILABLE) - return WiFi.hostByName(name, ip); + return WiFiHelper::hostByName(name, ip); #else return 1; #endif diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h index 94cf3d6c1..425e4d1b2 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h @@ -16,73 +16,4 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#pragma once -#include - -#define ENC_TYPE_NONE WIFI_AUTH_OPEN -#define ENC_TYPE_WEP WIFI_AUTH_WEP -#define ENC_TYPE_CCMP WIFI_AUTH_WPA2_PSK -#define ENC_TYPE_TKIP WIFI_AUTH_WPA_WPA2_PSK -#define ENC_TYPE_AUTO WIFI_AUTH_MAX + 1 - -#define WIFI_NONE_SLEEP 0 -#define WIFI_LIGHT_SLEEP 1 -#define WIFI_MODEM_SLEEP 2 - -// ESP8266 -typedef enum WiFiPhyMode -{ - TAS_WIFI_PHY_MODE_LR = 0, TAS_WIFI_PHY_MODE_11B = 1, TAS_WIFI_PHY_MODE_11G = 2, TAS_WIFI_PHY_MODE_11N = 3 -} WiFiPhyMode_t; - -/* -// ESP32 was never defined until IDF 4.4 -typedef enum -{ - WIFI_PHY_MODE_LR, // PHY mode for Low Rate - WIFI_PHY_MODE_11B, // PHY mode for 11b - WIFI_PHY_MODE_11G, // PHY mode for 11g - WIFI_PHY_MODE_HT20, // PHY mode for 11n Bandwidth HT20 - WIFI_PHY_MODE_HT40, // PHY mode for 11n Bandwidth HT40 - WIFI_PHY_MODE_HE20, // PHY mode for 11n Bandwidth HE20 -} wifi_phy_mode_t; -*/ - -class WiFiClass32 : public WiFiClass -{ -public: - wl_status_t begin(const char* wpa2_ssid, wpa2_auth_method_t method, const char* wpa2_identity=NULL, const char* wpa2_username=NULL, const char *wpa2_password=NULL, const char* ca_pem=NULL, const char* client_crt=NULL, const char* client_key=NULL, int32_t channel=0, const uint8_t* bssid=0, bool connect=true); - wl_status_t begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); - wl_status_t begin(char* ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); - wl_status_t begin(); - - static void hostname(const char* aHostname) - { - WiFi.setHostname(aHostname); - } - static void setSleepMode(int iSleepMode); - static int getPhyMode(); - static bool setPhyMode(WiFiPhyMode_t mode); - - static void wps_disable(); - static void setOutputPower(int n); - static void forceSleepBegin(); - static void forceSleepWake(); - static bool getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t* &bssid, int32_t &channel, bool &hidden_scan); - - static void dnsDone(void); // used by the callback to stop the dns timer - int hostByName(const char* aHostname, IPAddress& aResult, int32_t timer_ms); - int hostByName(const char* aHostname, IPAddress& aResult); - - void scrubDNS(void); -protected: -#ifdef USE_IPV6 - ip_addr_t dns_save4[DNS_MAX_SERVERS] = {}; // IPv4 DNS servers - ip_addr_t dns_save6[DNS_MAX_SERVERS] = {}; // IPv6 DNS servers -#endif // USE_IPV6 -}; - -void wifi_station_disconnect(); -void wifi_station_dhcpc_start(); -extern WiFiClass32 WiFi32; -#define WiFi WiFi32 +#include diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp index dc2908eec..21bdc542e 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp @@ -323,6 +323,18 @@ int32_t analogAttach(uint32_t pin, bool output_invert) { // returns ledc chan return chan; } +void analogDetachAll(void) { + for (uint32_t pin = 0; pin < SOC_GPIO_PIN_COUNT; pin++) { + if (pin_to_channel[pin] > 0) { +#if ESP_IDF_VERSION_MAJOR < 5 + ledcDetachPin(pin); +#else + ledcDetach(pin); +#endif + } + } +} + extern "C" uint32_t ledcReadFreq2(uint8_t chan) { // extern "C" uint32_t __wrap_ledcReadFreq(uint8_t chan) { if (chan > MAX_PWMS) { diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h index 659e34b55..0a5f99a3b 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h @@ -45,6 +45,7 @@ extern "C" uint32_t ledcReadFreq2(uint8_t chan); uint8_t ledcReadResolution(uint8_t chan); + // // analogAttach - attach a GPIO to a hardware PWM // @@ -55,6 +56,12 @@ uint8_t ledcReadResolution(uint8_t chan); // Returns: hardware channel number, or -1 if it failed int32_t analogAttach(uint32_t pin, bool output_invert = false); // returns the ledc channel, or -1 if failed. This is implicitly called by analogWrite if the channel was not already allocated +// +// analogDetachAll - detach all attached GPIOs from a hardware PWM +// +// This solves ghost PWM activity on reconfigured GPIOs after a restart +void analogDetachAll(void); + // change both freq and range // `0`: set to global value // `-1`: keep unchanged diff --git a/lib/libesp32/HttpClientLight/src/HTTPUpdateLight.cpp b/lib/libesp32/HttpClientLight/src/HTTPUpdateLight.cpp index 93b1008db..41f029bc4 100644 --- a/lib/libesp32/HttpClientLight/src/HTTPUpdateLight.cpp +++ b/lib/libesp32/HttpClientLight/src/HTTPUpdateLight.cpp @@ -195,7 +195,7 @@ HTTPUpdateResult HTTPUpdateLight::handleUpdate(HTTPClientLight& http, const Stri http.setFollowRedirects(_followRedirects); http.setUserAgent("ESP32-http-Update"); http.addHeader("Cache-Control", "no-cache"); - http.addHeader("x-ESP32-STA-MAC", WiFi.macAddress()); + http.addHeader("x-ESP32-STA-MAC", WiFiHelper::macAddress()); http.addHeader("x-ESP32-AP-MAC", WiFi.softAPmacAddress()); http.addHeader("x-ESP32-free-space", String(ESP.getFreeSketchSpace())); http.addHeader("x-ESP32-sketch-size", String(ESP.getSketchSize())); diff --git a/lib/libesp32/HttpClientLight/src/HTTPUpdateLight.h b/lib/libesp32/HttpClientLight/src/HTTPUpdateLight.h index 372f9f1b0..8846445b3 100644 --- a/lib/libesp32/HttpClientLight/src/HTTPUpdateLight.h +++ b/lib/libesp32/HttpClientLight/src/HTTPUpdateLight.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include diff --git a/lib/libesp32/HttpClientLight/src/HttpClientLight.cpp b/lib/libesp32/HttpClientLight/src/HttpClientLight.cpp index 62eea2ea8..2705d9694 100644 --- a/lib/libesp32/HttpClientLight/src/HttpClientLight.cpp +++ b/lib/libesp32/HttpClientLight/src/HttpClientLight.cpp @@ -1166,7 +1166,7 @@ bool HTTPClientLight::connect(void) } else { IPAddress remote_addr; // Add include "ESP8266WiFi.h" for this to work - if (!WiFi.hostByName(_host.c_str(), remote_addr)) { + if (!WiFiHelper::hostByName(_host.c_str(), remote_addr)) { return false; } if(!_client->connect(remote_addr, _port, _connectTimeout)) { diff --git a/lib/libesp32/berry/Makefile b/lib/libesp32/berry/Makefile index 5907e22db..ee3e32847 100755 --- a/lib/libesp32/berry/Makefile +++ b/lib/libesp32/berry/Makefile @@ -1,4 +1,4 @@ -CFLAGS = -Wall -Wextra -std=c99 -O2 -Wno-zero-length-array -Wno-empty-translation-unit +CFLAGS = -Wall -Wextra -std=c99 -O2 -Wno-zero-length-array -Wno-empty-translation-unit -DUSE_BERRY_INT64 DEBUG_FLAGS = -O0 -g -DBE_DEBUG TEST_FLAGS = $(DEBUG_FLAGS) --coverage -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined LIBS = -lm @@ -7,8 +7,8 @@ CC = clang # install clang!! gcc seems to produce a defect berry binary MKDIR = mkdir LFLAGS = -INCPATH = src default ../re1.5 -SRCPATH = src default ../re1.5 +INCPATH = src default ../re1.5 ../berry_mapping/src ../berry_int64/src generate +SRCPATH = src default ../re1.5 ../berry_mapping/src ../berry_int64/src GENERATE = generate CONFIG = default/berry_conf.h COC = tools/coc/coc diff --git a/lib/libesp32/berry/berry.exe b/lib/libesp32/berry/berry.exe index 12351863c..01fe9434b 100644 Binary files a/lib/libesp32/berry/berry.exe and b/lib/libesp32/berry/berry.exe differ diff --git a/lib/libesp32/berry/default/be_modtab.c b/lib/libesp32/berry/default/be_modtab.c index a4e7c7a33..9d4591783 100644 --- a/lib/libesp32/berry/default/be_modtab.c +++ b/lib/libesp32/berry/default/be_modtab.c @@ -308,10 +308,11 @@ BERRY_LOCAL bclass_array be_class_table = { &be_native_class(AudioOpusDecoder), &be_native_class(AudioInputI2S), #endif // defined(USE_I2S_AUDIO_BERRY) && (ESP_IDF_VERSION_MAJOR >= 5) +#endif // TASMOTA + #if defined(USE_BERRY_INT64) || defined(USE_MATTER_DEVICE) &be_native_class(int64), #endif -#endif // TASMOTA NULL, /* do not remove */ }; diff --git a/lib/libesp32/berry/default/be_re_lib.c b/lib/libesp32/berry/default/be_re_lib.c index f06a794b8..ab7f6644c 100644 --- a/lib/libesp32/berry/default/be_re_lib.c +++ b/lib/libesp32/berry/default/be_re_lib.c @@ -8,6 +8,7 @@ #include "be_constobj.h" #include "be_mem.h" #include "be_object.h" +#include "be_exec.h" #include "../../re1.5/re1.5.h" /******************************************************************** @@ -46,6 +47,9 @@ int be_re_compile(bvm *vm) { } ByteProg *code = be_os_malloc(sizeof(ByteProg) + sz); + if (code == NULL) { + be_throw(vm, BE_MALLOC_FAIL); /* lack of heap space */ + } int ret = re1_5_compilecode(code, regex_str); if (ret != 0) { be_raise(vm, "internal_error", "error in regex"); @@ -113,11 +117,16 @@ int be_re_match_search(bvm *vm, bbool is_anchored, bbool size_only) { } ByteProg *code = be_os_malloc(sizeof(ByteProg) + sz); + if (code == NULL) { + be_throw(vm, BE_MALLOC_FAIL); /* lack of heap space */ + } int ret = re1_5_compilecode(code, regex_str); if (ret != 0) { + be_os_free(code); be_raise(vm, "internal_error", "error in regex"); } be_re_match_search_run(vm, code, hay, is_anchored, size_only); + be_os_free(code); be_return(vm); } be_raise(vm, "type_error", NULL); @@ -138,8 +147,12 @@ int be_re_match_search_all(bvm *vm, bbool is_anchored) { } ByteProg *code = be_os_malloc(sizeof(ByteProg) + sz); + if (code == NULL) { + be_throw(vm, BE_MALLOC_FAIL); /* lack of heap space */ + } int ret = re1_5_compilecode(code, regex_str); if (ret != 0) { + be_os_free(code); be_raise(vm, "internal_error", "error in regex"); } @@ -152,6 +165,7 @@ int be_re_match_search_all(bvm *vm, bbool is_anchored) { be_pop(vm, 1); } be_pop(vm, 1); + be_os_free(code); be_return(vm); } be_raise(vm, "type_error", NULL); @@ -328,11 +342,17 @@ int be_re_split(bvm *vm) { } ByteProg *code = be_os_malloc(sizeof(ByteProg) + sz); + if (code == NULL) { + be_throw(vm, BE_MALLOC_FAIL); /* lack of heap space */ + } int ret = re1_5_compilecode(code, regex_str); if (ret != 0) { + be_os_free(code); be_raise(vm, "internal_error", "error in regex"); } - return re_pattern_split_run(vm, code, hay, split_limit); + ret = re_pattern_split_run(vm, code, hay, split_limit); + be_os_free(code); + return ret; } be_raise(vm, "type_error", NULL); } diff --git a/lib/libesp32/berry/default/berry.c b/lib/libesp32/berry/default/berry.c index 4ddf7b6f0..76756bbc2 100644 --- a/lib/libesp32/berry/default/berry.c +++ b/lib/libesp32/berry/default/berry.c @@ -14,6 +14,8 @@ #include #include +#include "be_mapping.h" + /* using GNU/readline library */ #if defined(USE_READLINE_LIB) #include @@ -403,6 +405,7 @@ int main(int argc, char *argv[]) { int res; bvm *vm = be_vm_new(); /* create a virtual machine instance */ + be_set_ctype_func_hanlder(vm, be_call_ctype_func); res = analysis_args(vm, argc, argv); be_vm_delete(vm); /* free all objects and vm */ return res; diff --git a/lib/libesp32/berry/gen.sh b/lib/libesp32/berry/gen.sh index a0edbd2df..e248a977f 100755 --- a/lib/libesp32/berry/gen.sh +++ b/lib/libesp32/berry/gen.sh @@ -5,4 +5,4 @@ # Included in the Platformio build process with `pio-tools/gen-berry-structures.py # rm -Rf ./generate/be_*.h -python3 tools/coc/coc -o generate src default ../berry_tasmota/src ../berry_mapping/src ../berry_int64/src ../../libesp32_lvgl/lv_binding_berry/src ../berry_matter/src/solidify ../berry_matter/src ../berry_animate/src/solidify ../berry_animate/src ../../libesp32_lvgl/lv_binding_berry/src/solidify ../../libesp32_lvgl/lv_binding_berry/generate -c default/berry_conf.h +python3 tools/coc/coc -o generate src default ../berry_tasmota/src ../berry_mapping/src ../berry_int64/src ../../libesp32_lvgl/lv_binding_berry/src ../../libesp32_lvgl/lv_haspmota/src/solidify ../berry_matter/src/solidify ../berry_matter/src ../berry_animate/src/solidify ../berry_animate/src ../../libesp32_lvgl/lv_binding_berry/src/solidify ../../libesp32_lvgl/lv_binding_berry/generate -c default/berry_conf.h diff --git a/lib/libesp32/berry/src/be_code.c b/lib/libesp32/berry/src/be_code.c index 7a1b2bd00..d6e1be99e 100644 --- a/lib/libesp32/berry/src/be_code.c +++ b/lib/libesp32/berry/src/be_code.c @@ -84,7 +84,7 @@ static int codeABx(bfuncinfo *finfo, bopcode op, int a, int bx) /* returns false if the move operation happened, or true if there was a register optimization and `b` should be replaced by `a` */ static bbool code_move(bfuncinfo *finfo, int a, int b) { - if (finfo->pc) { /* If not the first instruction of the function */ + if (finfo->pc > finfo->binfo->lastjmp) { /* If not the first instruction of the function */ binstruction *i = be_vector_end(&finfo->code); /* get the last instruction */ bopcode op = IGET_OP(*i); if (op <= OP_LDNIL) { /* binop or unop */ @@ -171,6 +171,13 @@ static int get_jump(bfuncinfo *finfo, int pc) static void patchlistaux(bfuncinfo *finfo, int list, int vtarget, int dtarget) { + /* mark the last destination point of a jump to avoid false register optimization */ + if (vtarget > finfo->binfo->lastjmp) { + finfo->binfo->lastjmp = vtarget; + } + if (dtarget > finfo->binfo->lastjmp) { + finfo->binfo->lastjmp = dtarget; + } while (list != NO_JUMP) { int next = get_jump(finfo, list); if (isjumpbool(finfo, list)) { @@ -721,10 +728,14 @@ int be_code_setvar(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2, bbool keep_reg) setsupvar(finfo, OP_SETUPV, e1, src); break; case ETMEMBER: /* store to member R(A).RK(B) <- RK(C) */ - setsfxvar(finfo, OP_SETMBR, e1, src); - break; case ETINDEX: /* store to member R(A)[RK(B)] <- RK(C) */ - setsfxvar(finfo, OP_SETIDX, e1, src); + setsfxvar(finfo, (e1->type == ETMEMBER) ? OP_SETMBR : OP_SETIDX, e1, src); + if (keep_reg && e2->type == ETREG && e1->v.ss.obj >= be_list_count(finfo->local)) { + /* special case of walrus assignemnt when we need to recreate an ETREG */ + code_move(finfo, e1->v.ss.obj, src); /* move from ETREG to MEMBER instance*/ + free_expreg(finfo, e2); /* free source (checks only ETREG) */ + e2->v.idx = e1->v.ss.obj; /* update to new register */ + } break; default: return 1; diff --git a/lib/libesp32/berry/src/be_exec.c b/lib/libesp32/berry/src/be_exec.c index 43791c66a..794987933 100644 --- a/lib/libesp32/berry/src/be_exec.c +++ b/lib/libesp32/berry/src/be_exec.c @@ -79,6 +79,10 @@ void be_throw(bvm *vm, int errorcode) #if BE_USE_PERF_COUNTERS vm->counter_exc++; #endif + /* if BE_MALLOC_FAIL then call */ + if (errorcode == BE_MALLOC_FAIL) { + if (vm->obshook != NULL) (*vm->obshook)(vm, BE_OBS_MALLOC_FAIL, vm->gc.usage); + } if (vm->errjmp) { vm->errjmp->status = errorcode; exec_throw(vm->errjmp); diff --git a/lib/libesp32/berry/src/be_introspectlib.c b/lib/libesp32/berry/src/be_introspectlib.c index ba54aad25..78e7eb0e5 100644 --- a/lib/libesp32/berry/src/be_introspectlib.c +++ b/lib/libesp32/berry/src/be_introspectlib.c @@ -122,7 +122,7 @@ static int m_toptr(bvm *vm) if (top >= 1) { bvalue *v = be_indexof(vm, 1); if (var_type(v) == BE_STRING) { - be_pushcomptr(vm, be_tostring(vm, 1)); + be_pushcomptr(vm, (void*)be_tostring(vm, 1)); be_return(vm); } else if (var_basetype(v) >= BE_FUNCTION || var_type(v) == BE_COMPTR) { be_pushcomptr(vm, var_toobj(v)); diff --git a/lib/libesp32/berry/src/be_jsonlib.c b/lib/libesp32/berry/src/be_jsonlib.c index db2b20677..615e8bebc 100644 --- a/lib/libesp32/berry/src/be_jsonlib.c +++ b/lib/libesp32/berry/src/be_jsonlib.c @@ -8,6 +8,7 @@ #include "be_object.h" #include "be_mem.h" #include +#include #if BE_USE_JSON_MODULE @@ -515,6 +516,15 @@ static void value_dump(bvm *vm, int *indent, int idx, int fmt) } else if (be_isnil(vm, idx)) { /* convert to json null */ be_stack_require(vm, 1 + BE_STACK_FREE_MIN); be_pushstring(vm, "null"); + } else if (be_isreal(vm, idx)) { + be_stack_require(vm, 1 + BE_STACK_FREE_MIN); + breal v = be_toreal(vm, idx); + if (isnan(v) || isinf(v)) { + be_pushstring(vm, "null"); + } else { + be_tostring(vm, idx); + be_pushvalue(vm, idx); /* push to top */ + }; } else if (be_isnumber(vm, idx) || be_isbool(vm, idx)) { /* convert to json number and boolean */ be_stack_require(vm, 1 + BE_STACK_FREE_MIN); be_tostring(vm, idx); diff --git a/lib/libesp32/berry/src/be_lexer.c b/lib/libesp32/berry/src/be_lexer.c index 90031d3f6..4e41bf8f6 100644 --- a/lib/libesp32/berry/src/be_lexer.c +++ b/lib/libesp32/berry/src/be_lexer.c @@ -354,7 +354,9 @@ static btokentype scan_decimal(blexer *lexer) if (has_decimal_dots || is_realexp) { type = TokenReal; } - lexer->buf.s[lexer->buf.len] = '\0'; + /* use save_char to add the null terminator, */ + /* since it handles expanding the buffer if needed. */ + save_char(lexer, '\0'); if (type == TokenReal) { setreal(lexer, be_str2real(lexbuf(lexer), NULL)); } else { @@ -431,7 +433,7 @@ static btokentype scan_string(blexer *lexer); /* forward declaration */ /* scan f-string and transpile it to `format(...)` syntax then feeding the normal lexer and parser */ static void scan_f_string(blexer *lexer) { - char ch; + char ch = '\0'; clear_buf(lexer); scan_string(lexer); /* first scan the entire string in lexer->buf */ diff --git a/lib/libesp32/berry/src/be_mathlib.c b/lib/libesp32/berry/src/be_mathlib.c index b9598f525..52abeffd7 100644 --- a/lib/libesp32/berry/src/be_mathlib.c +++ b/lib/libesp32/berry/src/be_mathlib.c @@ -45,6 +45,17 @@ static int m_isnan(bvm *vm) be_return(vm); } +static int m_isinf(bvm *vm) +{ + if (be_top(vm) >= 1 && be_isreal(vm, 1)) { + breal x = be_toreal(vm, 1); + be_pushbool(vm, isinf(x)); + } else { + be_pushbool(vm, bfalse); + } + be_return(vm); +} + static int m_abs(bvm *vm) { if (be_top(vm) >= 1 && be_isnumber(vm, 1)) { @@ -284,6 +295,7 @@ static int m_rand(bvm *vm) #if !BE_USE_PRECOMPILED_OBJECT be_native_module_attr_table(math) { be_native_module_function("isnan", m_isnan), + be_native_module_function("isinf", m_isinf), be_native_module_function("abs", m_abs), be_native_module_function("ceil", m_ceil), be_native_module_function("floor", m_floor), @@ -308,6 +320,7 @@ be_native_module_attr_table(math) { be_native_module_function("rand", m_rand), be_native_module_real("pi", M_PI), be_native_module_real("nan", NAN), + be_native_module_real("inf", INFINITY), be_native_module_int("imax", M_IMAX), be_native_module_int("imin", M_IMIN), }; @@ -317,6 +330,7 @@ be_define_native_module(math, NULL); /* @const_object_info_begin module math (scope: global, depend: BE_USE_MATH_MODULE) { isnan, func(m_isnan) + isinf, func(m_isinf) abs, func(m_abs) ceil, func(m_ceil) floor, func(m_floor) @@ -341,6 +355,7 @@ module math (scope: global, depend: BE_USE_MATH_MODULE) { rand, func(m_rand) pi, real(M_PI) nan, real(NAN) + inf, real(INFINITY) imax, int(M_IMAX) imin, int(M_IMIN) } diff --git a/lib/libesp32/berry/src/be_parser.c b/lib/libesp32/berry/src/be_parser.c index be001bf97..2567410d6 100644 --- a/lib/libesp32/berry/src/be_parser.c +++ b/lib/libesp32/berry/src/be_parser.c @@ -197,6 +197,7 @@ static void begin_block(bfuncinfo *finfo, bblockinfo *binfo, int type) binfo->type = (bbyte)type; binfo->hasupval = 0; binfo->sideeffect = 0; + binfo->lastjmp = 0; binfo->beginpc = finfo->pc; /* set starting pc for this block */ binfo->nactlocals = (bbyte)be_list_count(finfo->local); /* count number of local variables in previous block */ if (type & BLOCK_LOOP) { @@ -917,30 +918,6 @@ static void primary_expr(bparser *parser, bexpdesc *e) } } -/* parse a single string literal as parameter */ -static void call_single_string_expr(bparser *parser, bexpdesc *e) -{ - bexpdesc arg; - bfuncinfo *finfo = parser->finfo; - int base; - - /* func 'string_literal' */ - check_var(parser, e); - if (e->type == ETMEMBER) { - push_error(parser, "method not allowed for string prefix"); - } - - base = be_code_nextreg(finfo, e); /* allocate a new base reg if not at top already */ - simple_expr(parser, &arg); - be_code_nextreg(finfo, &arg); /* move result to next reg */ - - be_code_call(finfo, base, 1); /* only one arg */ - if (e->type != ETREG) { - e->type = ETREG; - e->v.idx = base; - } -} - static void suffix_expr(bparser *parser, bexpdesc *e) { primary_expr(parser, e); @@ -955,9 +932,6 @@ static void suffix_expr(bparser *parser, bexpdesc *e) case OptLSB: /* '[' index */ index_expr(parser, e); break; - case TokenString: - call_single_string_expr(parser, e); /* " string literal */ - break; default: return; } @@ -1119,7 +1093,7 @@ static void sub_expr(bparser *parser, bexpdesc *e, int prio) } init_exp(&e2, ETVOID, 0); sub_expr(parser, &e2, binary_op_prio(op)); /* parse right side */ - if ((e2.type == ETVOID) && (op == OptConnect)) { + if ((op == OptConnect) && (e2.type == ETVOID) && (e2.v.s == NULL)) { /* 'e2.v.s == NULL' checks that it's not an undefined variable */ init_exp(&e2, ETINT, M_IMAX); } else { check_var(parser, &e2); /* check if valid */ @@ -1145,7 +1119,7 @@ static void walrus_expr(bparser *parser, bexpdesc *e) expr(parser, e); check_var(parser, e); if (check_newvar(parser, &e1)) { /* new variable */ - new_var(parser, e1.v.s, e); + new_var(parser, e1.v.s, &e1); } if (be_code_setvar(parser->finfo, &e1, e, btrue /* do not release register */ )) { parser->lexer.linenumber = line; diff --git a/lib/libesp32/berry/src/be_parser.h b/lib/libesp32/berry/src/be_parser.h index 8498bfa99..9b7d11e0e 100644 --- a/lib/libesp32/berry/src/be_parser.h +++ b/lib/libesp32/berry/src/be_parser.h @@ -53,7 +53,8 @@ typedef struct bblockinfo { bbyte nactlocals; /* number of active local variables */ bbyte type; /* block type mask */ bbyte hasupval; /* has upvalue mark */ - bbyte sideeffect; /* did the last expr/statement had a side effect */ + bbyte sideeffect; /* did the last expr/statement had a side effect */ + int lastjmp; /* pc for the last jump, prevents false register optimizations */ int breaklist; /* break list */ int beginpc; /* begin pc */ int continuelist; /* continue list */ diff --git a/lib/libesp32/berry/src/be_strlib.c b/lib/libesp32/berry/src/be_strlib.c index a52b8b670..2ce560910 100644 --- a/lib/libesp32/berry/src/be_strlib.c +++ b/lib/libesp32/berry/src/be_strlib.c @@ -21,6 +21,21 @@ #define is_digit(c) ((c) >= '0' && (c) <= '9') #define skip_space(s) while (is_space(*(s))) { ++(s); } +static int str_strncasecmp(const char *s1, const char *s2, size_t n) +{ + if (n == 0) return 0; + + while (n-- != 0 && tolower(*s1) == tolower(*s2)) { + if (n == 0 || *s1 == '\0' || *s2 == '\0') + break; + s1++; + s2++; + } + + return tolower(*(const unsigned char *)s1) + - tolower(*(const unsigned char *)s2); +} + typedef bint (*str_opfunc)(const char*, const char*, bint, bint); bstring* be_strcat(bvm *vm, bstring *s1, bstring *s2) @@ -534,7 +549,7 @@ static const char* skip2dig(const char *s) return s; } -static const char* get_mode(const char *str, char *buf) +static const char* get_mode(const char *str, char *buf, size_t buf_len) { const char *p = str; while (*p && strchr(FLAGES, *p)) { /* skip flags */ @@ -545,8 +560,13 @@ static const char* get_mode(const char *str, char *buf) p = skip2dig(++p); /* skip width (2 digits at most) */ } *(buf++) = '%'; - strncpy(buf, str, p - str + 1); - buf[p - str + 1] = '\0'; + size_t mode_size = p - str + 1; + /* Leave 2 bytes for the leading % and the trailing '\0' */ + if (mode_size > buf_len - 2) { + mode_size = buf_len - 2; + } + strncpy(buf, str, mode_size); + buf[mode_size] = '\0'; return p; } @@ -617,7 +637,7 @@ int be_str_format(bvm *vm) } pushstr(vm, format, p - format); concat2(vm); - p = get_mode(p + 1, mode); + p = get_mode(p + 1, mode, sizeof(mode)); buf[0] = '\0'; if (index > top && *p != '%') { be_raise(vm, "runtime_error", be_pushfstring(vm, @@ -669,6 +689,17 @@ int be_str_format(bvm *vm) } break; } + case 'q': { + const char *s = be_toescape(vm, index, 'q'); + int len = be_strlen(vm, index); + if (len > 100 && strlen(mode) == 2) { + be_pushvalue(vm, index); + } else { + snprintf(buf, sizeof(buf), "%s", s); + be_pushstring(vm, buf); + } + break; + } default: /* error */ be_raise(vm, "runtime_error", be_pushfstring(vm, "invalid option '%%%c' to 'format'", *p)); @@ -940,6 +971,60 @@ static int str_escape(bvm *vm) be_return_nil(vm); } +static int str_startswith(bvm *vm) +{ + int top = be_top(vm); + if (top >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { + bbool case_insensitive = bfalse; + if (top >= 3 && be_isbool(vm, 3)) { + case_insensitive = be_tobool(vm, 3); + } + bbool result = bfalse; + const char *s = be_tostring(vm, 1); + const char *p = be_tostring(vm, 2); + size_t len = (size_t)be_strlen(vm, 2); + if (case_insensitive) { + if (str_strncasecmp(s, p, len) == 0) { + result = btrue; + } + } else { + if (strncmp(s, p, len) == 0) { + result = btrue; + } + } + be_pushbool(vm, result); + be_return(vm); + } + be_return_nil(vm); +} + +static int str_endswith(bvm *vm) +{ + int top = be_top(vm); + if (top >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { + bbool case_insensitive = bfalse; + if (top >= 3 && be_isbool(vm, 3)) { + case_insensitive = be_tobool(vm, 3); + } + bbool result = bfalse; + const char *s = be_tostring(vm, 1); + const char *p = be_tostring(vm, 2); + size_t len = (size_t)be_strlen(vm, 2); + if (case_insensitive) { + if (str_strncasecmp(s + (int)strlen(s) - (int)len, p, len) == 0) { + result = btrue; + } + } else { + if (strncmp(s + (int)strlen(s) - (int)len, p, len) == 0) { + result = btrue; + } + } + be_pushbool(vm, result); + be_return(vm); + } + be_return_nil(vm); +} + #if !BE_USE_PRECOMPILED_OBJECT be_native_module_attr_table(string) { be_native_module_function("format", be_str_format), @@ -954,6 +1039,8 @@ be_native_module_attr_table(string) { be_native_module_function("tr", str_tr), be_native_module_function("escape", str_escape), be_native_module_function("replace", str_replace), + be_native_module_function("startswith", str_startswith), + be_native_module_function("endswith", str_endswith), }; be_define_native_module(string, NULL); @@ -972,6 +1059,8 @@ module string (scope: global, depend: BE_USE_STRING_MODULE) { tr, func(str_tr) escape, func(str_escape) replace, func(str_replace) + startswith, func(str_startswith) + endswith, func(str_endswith) } @const_object_info_end */ #include "../generate/be_fixed_string.h" diff --git a/lib/libesp32/berry/src/be_vm.c b/lib/libesp32/berry/src/be_vm.c index a9de9675f..37352e588 100644 --- a/lib/libesp32/berry/src/be_vm.c +++ b/lib/libesp32/berry/src/be_vm.c @@ -723,22 +723,20 @@ newframe: /* a new call frame */ } } else if (var_isnumber(a) && var_isnumber(b)) { #if CONFIG_IDF_TARGET_ESP32 /* when running on ESP32 in IRAM, there is a bug in early chip revision */ - union bvaldata x, y; // TASMOTA workaround for ESP32 rev0 bug - x.i = a->v.i; - if (var_isint(a)) { x.r = (breal) x.i; } - y.i = b->v.i; - if (var_isint(b)) { y.r = (breal) y.i; } - if (y.r == cast(breal, 0)) { - vm_error(vm, "divzero_error", "division by zero"); - } - var_setreal(dst, x.r / y.r); + union bvaldata x0, y0; // TASMOTA workaround for ESP32 rev0 bug + x0.i = a->v.i; + if (var_isint(a)) { x0.r = (breal) x0.i; } + y0.i = b->v.i; + if (var_isint(b)) { y0.r = (breal) y0.i; } + breal x = x0.r, y = y0.r; #else // CONFIG_IDF_TARGET_ESP32 breal x = var2real(a), y = var2real(b); +#endif // CONFIG_IDF_TARGET_ESP32 if (y == cast(breal, 0)) { vm_error(vm, "divzero_error", "division by zero"); + } else { + var_setreal(dst, x / y); } - var_setreal(dst, x / y); -#endif // CONFIG_IDF_TARGET_ESP32 } else if (var_isinstance(a)) { ins_binop(vm, "/", ins); } else { @@ -749,18 +747,28 @@ newframe: /* a new call frame */ opcase(MOD): { bvalue *dst = RA(), *a = RKB(), *b = RKC(); if (var_isint(a) && var_isint(b)) { - var_setint(dst, ibinop(%, a, b)); + bint x = var_toint(a), y = var_toint(b); + if (y == 0) { + vm_error(vm, "divzero_error", "division by zero"); + } else { + var_setint(dst, x % y); + } } else if (var_isnumber(a) && var_isnumber(b)) { #if CONFIG_IDF_TARGET_ESP32 /* when running on ESP32 in IRAM, there is a bug in early chip revision */ - union bvaldata x, y; // TASMOTA workaround for ESP32 rev0 bug - x.i = a->v.i; - if (var_isint(a)) { x.r = (breal) x.i; } - y.i = b->v.i; - if (var_isint(b)) { y.r = (breal) y.i; } - var_setreal(dst, mathfunc(fmod)(x.r, y.r)); -#else // CONFIG_IDF_TARGET_ESP32 - var_setreal(dst, mathfunc(fmod)(var_toreal(a), var_toreal(b))); -#endif // CONFIG_IDF_TARGET_ESP32 + union bvaldata x0, y0; // TASMOTA workaround for ESP32 rev0 bug + x0.i = a->v.i; + if (var_isint(a)) { x0.r = (breal) x0.i; } + y0.i = b->v.i; + if (var_isint(b)) { y0.r = (breal) y0.i; } + breal x = x0.r, y = y0.r; +#else + breal x = var2real(a), y = var2real(b); +#endif + if (y == cast(breal, 0)) { + vm_error(vm, "divzero_error", "division by zero"); + } else { + var_setreal(dst, mathfunc(fmod)(x, y)); + } } else if (var_isinstance(a)) { ins_binop(vm, "%", ins); } else { diff --git a/lib/libesp32/berry/src/berry.h b/lib/libesp32/berry/src/berry.h index 962a01ebb..e8ee792de 100644 --- a/lib/libesp32/berry/src/berry.h +++ b/lib/libesp32/berry/src/berry.h @@ -676,6 +676,7 @@ enum beobshookevents { BE_OBS_GC_END, /**< end of GC, arg = allocated size */ BE_OBS_VM_HEARTBEAT, /**< VM heartbeat called every million instructions */ BE_OBS_STACK_RESIZE_START, /**< Berry stack resized */ + BE_OBS_MALLOC_FAIL, /**< Memory allocation failed */ }; typedef int (*bctypefunc)(bvm*, const void*); /**< bctypefunc */ diff --git a/lib/libesp32/berry/tests/division_by_zero.be b/lib/libesp32/berry/tests/division_by_zero.be new file mode 100644 index 000000000..7dbaccfd2 --- /dev/null +++ b/lib/libesp32/berry/tests/division_by_zero.be @@ -0,0 +1,47 @@ + +try + # Test integer division + var div = 1/0 + assert(false) # Should not reach this point +except .. as e,m + + assert(e == "divzero_error") + assert(m == "division by zero") +end + + +try + # Test integer modulo + var div = 1%0 + assert(false) +except .. as e,m + assert(e == "divzero_error") + assert(m == "division by zero") +end + +try + # Test float division + var div = 1.1/0.0 + assert(false) +except .. as e,m + assert(e == "divzero_error") + assert(m == "division by zero") +end + +try + # Test float modulo + var div = 1.1%0.0 + assert(false) +except .. as e,m + assert(e == "divzero_error") + assert(m == "division by zero") +end + + +# Check normal division & modulo +assert(1/2 == 0) +assert(1%2 == 1) +assert(1.0/2.0 == 0.5) +assert(1.0%2.0 == 1.0) +assert(4/2 == 2) +assert(4%2 == 0) diff --git a/lib/libesp32/berry/tests/lexer.be b/lib/libesp32/berry/tests/lexer.be index 2114cab54..db2945bc7 100644 --- a/lib/libesp32/berry/tests/lexer.be +++ b/lib/libesp32/berry/tests/lexer.be @@ -36,6 +36,10 @@ check(45.1e2, 4510) check(45.e2, 4500) check(45.e+2, 4500) +# Ensure pathologically long numbers don't crash the lexer (or cause an buffer overflow) +assert(000000000000000000000000000000000000E0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 == 0.0); + + test_source('x = 5; 0...x;', 'unexpected symbol near \'.\'') test_source('x = 5; 0...x;', 'unexpected symbol near \'.\'') test_source('0xg', 'invalid hexadecimal number') diff --git a/lib/libesp32/berry/tests/math.be b/lib/libesp32/berry/tests/math.be index 12facca63..232ffa285 100644 --- a/lib/libesp32/berry/tests/math.be +++ b/lib/libesp32/berry/tests/math.be @@ -10,5 +10,37 @@ assert(math.isnan(n*0)) assert(!math.isnan(0)) assert(!math.isnan(1.5)) +assert(!math.isnan(math.inf)) assert(n != n) #- nan is never identical to itself -# + +#- inf -# +i = math.inf +assert(str(i) == 'inf') +assert(str(-i) == '-inf') # inf has a sign +assert(math.isinf(i)) +assert(math.isinf(i+i)) +assert(math.isinf(i+1)) +# the following result in nan +assert(math.isnan(i*0)) +assert(math.isnan(i-i)) +assert(math.isnan(i/i)) + +assert(!math.isinf(0)) +assert(!math.isinf(1.5)) +assert(!math.isinf(math.nan)) + +assert(i == i) #- equality works for inf -# +assert(i == i+1) + +#- nan and inf convert to null in json -# +import json + +m_nan = {"v": math.nan} +assert(json.dump(m_nan) == '{"v":null}') +m_inf1 = {"v": math.inf} +assert(json.dump(m_inf1) == '{"v":null}') +m_inf2 = {"v": -math.inf} +assert(json.dump(m_inf2) == '{"v":null}') +m_v = {"v": 3.5} +assert(json.dump(m_v) == '{"v":3.5}') diff --git a/lib/libesp32/berry/tests/parser.be b/lib/libesp32/berry/tests/parser.be new file mode 100644 index 000000000..2b64b4c50 --- /dev/null +++ b/lib/libesp32/berry/tests/parser.be @@ -0,0 +1,11 @@ +# Test some sparser specific bugs + +# https://github.com/berry-lang/berry/issues/396 +def f() + if true + var a = 1 + a = true ? a+1 : a+2 + return a + end +end +assert(f() == 2) diff --git a/lib/libesp32/berry/tests/string.be b/lib/libesp32/berry/tests/string.be index 82f824451..448ca5215 100644 --- a/lib/libesp32/berry/tests/string.be +++ b/lib/libesp32/berry/tests/string.be @@ -147,6 +147,11 @@ assert(string.format("%s", nil) == 'nil') assert(string.format("%s", true) == 'true') assert(string.format("%s", false) == 'false') +assert(string.format("%q", "\ntest") == '\'\\ntest\'') + +# corrupt format string should not crash the VM +string.format("%0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f", 3.5) + # format is now synonym to string.format assert(format == string.format) assert(format("%.1f", 3) == '3.0') @@ -169,3 +174,42 @@ var a = 'foobar{0}' assert(f"S = {a}" == 'S = foobar{0}') assert(f"S = {a:i}" == 'S = 0') assert(f"{a=}" == 'a=foobar{0}') + +# startswith case sensitive +assert(string.startswith("", "") == true) +assert(string.startswith("qwerty", "qw") == true) +assert(string.startswith("qwerty", "qwerty") == true) +assert(string.startswith("qwerty", "") == true) +assert(string.startswith("qwerty", "qW") == false) +assert(string.startswith("qwerty", "QW") == false) +assert(string.startswith("qwerty", "qz") == false) +assert(string.startswith("qwerty", "qwertyw") == false) + +# startswith case insensitive +assert(string.startswith("qwerty", "qw", true) == true) +assert(string.startswith("qwerty", "qwerty", true) == true) +assert(string.startswith("qwerty", "", true) == true) +assert(string.startswith("qwerty", "qW", true) == true) +assert(string.startswith("qwerty", "QW", true) == true) +assert(string.startswith("qwerty", "qz", true) == false) +assert(string.startswith("qwerty", "qwertyw", true) == false) + +# endswith case sensitive +assert(string.endswith("", "") == true) +assert(string.endswith("qwerty", "ty") == true) +assert(string.endswith("qwerty", "qwerty") == true) +assert(string.endswith("qwerty", "") == true) +assert(string.endswith("qwerty", "tY") == false) +assert(string.endswith("qwerty", "TY") == false) +assert(string.endswith("qwerty", "tr") == false) +assert(string.endswith("qwerty", "qwertyw") == false) + +# endswith case insensitive +assert(string.endswith("", "", true) == true) +assert(string.endswith("qwerty", "ty", true) == true) +assert(string.endswith("qwerty", "qwerty", true) == true) +assert(string.endswith("qwerty", "", true) == true) +assert(string.endswith("qwerty", "tY", true) == true) +assert(string.endswith("qwerty", "TY", true) == true) +assert(string.endswith("qwerty", "tr", true) == false) +assert(string.endswith("qwerty", "qwertyw", true) == false) diff --git a/lib/libesp32/berry/tests/walrus.be b/lib/libesp32/berry/tests/walrus.be index faa92fa15..a08090e74 100644 --- a/lib/libesp32/berry/tests/walrus.be +++ b/lib/libesp32/berry/tests/walrus.be @@ -33,3 +33,49 @@ assert_attribute_error("var a,b def f() a end") # while the following does have side effect def f() a := b end + +# bug when using walrus with member +def id(x) return x end +var a = 1 +import global +def f() return id(global.a := 42) end +assert(f() == 42) +# bug: returns + +def concat(x, y, z) return str(x)+str(y)+str(z) end +var a = 1 +import global +def f() return concat(global.a := 1, global.a := 42, global.a := 0) end +assert(f() == "1420") +# bug: returns '142' + +# same bug when using index +def id(x) return x end +l = [10,11] +import global +def f() return id(global.l[0] := 42) end +assert(f() == 42) +# bug: returns [42, 11] + +# bug when using member for self +class confused_walrus + var b + def f() + var c = 1 + if self.b := true + c = 2 + end + return self + end +end +var ins = confused_walrus() +assert(ins.f() == ins) + +# Check overwriting a builtin (https://github.com/berry-lang/berry/issues/416) + +def check_overwrite_builtin() + print := 1 + assert(print == 1) +end + +check_overwrite_builtin() diff --git a/lib/libesp32/berry_int64/src/be_int64_class.c b/lib/libesp32/berry_int64/src/be_int64_class.c index 4e06354ea..48dfc923a 100644 --- a/lib/libesp32/berry_int64/src/be_int64_class.c +++ b/lib/libesp32/berry_int64/src/be_int64_class.c @@ -62,22 +62,23 @@ int64_t* int64_fromstring(bvm *vm, const char* s) { } BE_FUNC_CTYPE_DECLARE(int64_fromstring, "int64", "@s") +// is the int64 within int32 range? +bbool int64_isint(int64_t *i64) { + return (*i64 >= INT32_MIN && *i64 <= INT32_MAX); +} +BE_FUNC_CTYPE_DECLARE(int64_isint, "b", ".") + int32_t int64_toint(int64_t *i64) { return (int32_t) *i64; } BE_FUNC_CTYPE_DECLARE(int64_toint, "i", ".") -void int64_set(int64_t *i64, int32_t high, int32_t low) { - *i64 = ((int64_t)high << 32) | ((int64_t)low & 0xFFFFFFFF); -} -BE_FUNC_CTYPE_DECLARE(int64_set, "", ".ii") - -int64_t* int64_fromu32(bvm *vm, uint32_t low) { +int64_t* int64_fromu32(bvm *vm, uint32_t low, uint32_t high) { int64_t* r64 = (int64_t*)be_malloc(vm, sizeof(int64_t)); - *r64 = low; + *r64 = low | (((int64_t)high) << 32); return r64; } -BE_FUNC_CTYPE_DECLARE(int64_fromu32, "int64", "@i") +BE_FUNC_CTYPE_DECLARE(int64_fromu32, "int64", "@i[i]") int64_t* int64_add(bvm *vm, int64_t *i64, int64_t *j64) { int64_t* r64 = (int64_t*)be_malloc(vm, sizeof(int64_t)); @@ -87,6 +88,14 @@ int64_t* int64_add(bvm *vm, int64_t *i64, int64_t *j64) { } BE_FUNC_CTYPE_DECLARE(int64_add, "int64", "@(int64)(int64)") +int64_t* int64_add32(bvm *vm, int64_t *i64, int32_t j32) { + int64_t* r64 = (int64_t*)be_malloc(vm, sizeof(int64_t)); + // it's possible that arg j64 is nullptr, since class type does allow NULLPTR to come through. + *r64 = *i64 + j32; + return r64; +} +BE_FUNC_CTYPE_DECLARE(int64_add32, "int64", "@(int64)i") + int64_t* int64_sub(bvm *vm, int64_t *i64, int64_t *j64) { int64_t* r64 = (int64_t*)be_malloc(vm, sizeof(int64_t)); // it's possible that arg j64 is nullptr, since class type does allow NULLPTR to come through. @@ -179,22 +188,90 @@ bbool int64_lte(int64_t *i64, int64_t *j64) { } BE_FUNC_CTYPE_DECLARE(int64_lte, "b", ".(int64)") +bbool int64_tobool(int64_t *i64) { + return *i64 != 0; +} +BE_FUNC_CTYPE_DECLARE(int64_tobool, "b", ".") + void* int64_tobytes(int64_t *i64, size_t *len) { if (len) { *len = sizeof(int64_t); } return i64; } BE_FUNC_CTYPE_DECLARE(int64_tobytes, "&", ".") -void int64_frombytes(int64_t *i64, uint8_t* ptr, size_t len, int32_t idx) { +int64_t* int64_frombytes(bvm *vm, uint8_t* ptr, size_t len, int32_t idx) { + int64_t* r64 = (int64_t*)be_malloc(vm, sizeof(int64_t)); if (idx < 0) { idx = len + idx; } // support negative index, counting from the end if (idx < 0) { idx = 0; } // sanity check if (idx > len) { idx = len; } uint32_t usable_len = len - idx; if (usable_len > sizeof(int64_t)) { usable_len = sizeof(int64_t); } - *i64 = 0; // start with 0 - memmove(i64, ptr + idx, usable_len); + *r64 = 0; // start with 0 + memmove(r64, ptr + idx, usable_len); + return r64; } -BE_FUNC_CTYPE_DECLARE(int64_frombytes, "", ".(bytes)~[i]") +BE_FUNC_CTYPE_DECLARE(int64_frombytes, "int64", "@(bytes)~[i]") + +/* + +def toint64(i) + if (type(i) == 'int') return int64.fromu32(i) end + if (type(i) == 'instance') && isinstance(i, int64) return i end + return nil +end + +*/ + +/******************************************************************** +** Solidified function: toint64 +********************************************************************/ +be_local_closure(toint64, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str(int), + /* K1 */ be_nested_str(int64), + /* K2 */ be_nested_str(fromu32), + /* K3 */ be_nested_str(instance), + }), + &be_const_str_to64, + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0x60040004, // 0000 GETGBL R1 G4 + 0x5C080000, // 0001 MOVE R2 R0 + 0x7C040200, // 0002 CALL R1 1 + 0x1C040300, // 0003 EQ R1 R1 K0 + 0x78060004, // 0004 JMPF R1 #000A + 0xB8060200, // 0005 GETNGBL R1 K1 + 0x8C040302, // 0006 GETMET R1 R1 K2 + 0x5C0C0000, // 0007 MOVE R3 R0 + 0x7C040400, // 0008 CALL R1 2 + 0x80040200, // 0009 RET 1 R1 + 0x60040004, // 000A GETGBL R1 G4 + 0x5C080000, // 000B MOVE R2 R0 + 0x7C040200, // 000C CALL R1 1 + 0x1C040303, // 000D EQ R1 R1 K3 + 0x78060005, // 000E JMPF R1 #0015 + 0x6004000F, // 000F GETGBL R1 G15 + 0x5C080000, // 0010 MOVE R2 R0 + 0xB80E0200, // 0011 GETNGBL R3 K1 + 0x7C040400, // 0012 CALL R1 2 + 0x78060000, // 0013 JMPF R1 #0015 + 0x80040000, // 0014 RET 1 R0 + 0x4C040000, // 0015 LDNIL R1 + 0x80040200, // 0016 RET 1 R1 + }) + ) +); +/*******************************************************************/ + #include "be_fixed_be_class_int64.h" @@ -203,13 +280,16 @@ class be_class_int64 (scope: global, name: int64) { _p, var init, ctype_func(int64_init) deinit, ctype_func(int64_deinit) - set, ctype_func(int64_set) fromu32, static_ctype_func(int64_fromu32) + toint64, static_closure(toint64_closure) tostring, ctype_func(int64_tostring) fromstring, static_ctype_func(int64_fromstring) + isint, ctype_func(int64_isint) toint, ctype_func(int64_toint) + tobool, ctype_func(int64_tobool) + add, ctype_func(int64_add32) +, ctype_func(int64_add) -, ctype_func(int64_sub) *, ctype_func(int64_mul) @@ -224,6 +304,6 @@ class be_class_int64 (scope: global, name: int64) { <=, ctype_func(int64_lte) tobytes, ctype_func(int64_tobytes) - frombytes, ctype_func(int64_frombytes) + frombytes, static_ctype_func(int64_frombytes) } @const_object_info_end */ diff --git a/lib/libesp32/berry_int64/tests/int64.be b/lib/libesp32/berry_int64/tests/int64.be index 047330085..311b0f72c 100644 --- a/lib/libesp32/berry_int64/tests/int64.be +++ b/lib/libesp32/berry_int64/tests/int64.be @@ -8,15 +8,9 @@ assert(int(int64(-5)) == -5) assert(str(int64(-5)) == "-5") # testing large numbers -a = int64() -a.set(0x7FFFFFFF,0xFFFFFFFF) # max positive number -assert(str(a) == "9223372036854775807") - -a.set(0x80000000,0x00000000) -assert(str(a) == "-9223372036854775808") - -a.set(10,10) -assert(str(a) == "42949672970") +assert(str(int64.fromu32(0xFFFFFFFF, 0x7FFFFFFF)) == "9223372036854775807") # max positive number +assert(str(int64.fromu32(0x00000000, 0x80000000)) == "-9223372036854775808") +assert(str(int64.fromu32(10,10)) == "42949672970") # addition assert(str(int64(10) + int64(20)) == "30") @@ -97,19 +91,18 @@ assert(a.tobytes() == bytes("0000000000000080")) assert(int64(-1).tobytes() == bytes("FFFFFFFFFFFFFFFF")) # frombytes -a = int64() -a.frombytes(bytes("0A00000000000000"), 0) -assert(a.tobytes() == bytes("0A00000000000000")) -a.frombytes(bytes("0A00000000000000")) # with implicit index 0 -assert(a.tobytes() == bytes("0A00000000000000")) -a.frombytes(bytes("0A00000000000000"), 1) # index 1 and incomplete (7 bytes) -assert(a.tobytes() == bytes("0000000000000000")) +assert(int64.frombytes(bytes("0A00000000000000"), 0) == bytes("0A00000000000000")) # with implicit index 0 +assert(int64.frombytes(bytes("0A00000000000000")) == bytes("0A00000000000000")) +assert(int64.frombytes(bytes("0A00000000000000"), 1) == bytes("0000000000000000")) # index 1 and incomplete (7 bytes) -a.frombytes(bytes("00FFFFFFFFFFFFFFFF"), 1) # index 1 and incomplete (7 bytes) -assert(a.tobytes() == bytes("FFFFFFFFFFFFFFFF")) -a.frombytes(bytes("00FFFFFFFFFFFFFFFF"), -2) # from end -assert(a.tobytes() == bytes("FFFF000000000000")) -a.frombytes(bytes("")) # empty -assert(a.tobytes() == bytes("0000000000000000")) -a.frombytes(bytes(""),4) # empty with wrong index -assert(a.tobytes() == bytes("0000000000000000")) +assert(int64.frombytes(bytes("00FFFFFFFFFFFFFFFF"), 1) == bytes("FFFFFFFFFFFFFFFF")) # index 1 and incomplete (7 bytes) +assert(int64.frombytes(bytes("00FFFFFFFFFFFFFFFF"), -2) == bytes("FFFF000000000000")) # from end +assert(int64.frombytes(bytes("")) == bytes("0000000000000000")) # empty +assert(int64.frombytes(bytes(""),4) == bytes("0000000000000000")) # empty with wrong index + +# fromu32 +assert(int64.fromu32(0).tobytes() == bytes("0000000000000000")) +assert(int64.fromu32(0xFFFFFFFF).tobytes() == bytes("FFFFFFFF00000000")) +assert(int64.fromu32(0xFFFFFFFF, 1).tobytes() == bytes("FFFFFFFF01000000")) +assert(int64.fromu32(-1, 1).tobytes() == bytes("FFFFFFFF01000000")) +assert(int64.fromu32(-1, -1).tobytes() == bytes("FFFFFFFFFFFFFFFF")) diff --git a/lib/libesp32/berry_mapping/src/be_cb_module.c b/lib/libesp32/berry_mapping/src/be_cb_module.c index 111ba95e0..f0f2ab2d6 100644 --- a/lib/libesp32/berry_mapping/src/be_cb_module.c +++ b/lib/libesp32/berry_mapping/src/be_cb_module.c @@ -280,7 +280,7 @@ void be_cb_deinit(bvm *vm) { for (int32_t slot = 0; slot < BE_MAX_CB; slot++) { if (be_cb_hooks[slot].vm == vm) { be_cb_hooks[slot].vm = NULL; - be_cb_hooks[slot].f.type == BE_NIL; + be_cb_hooks[slot].f.type = BE_NIL; } } // remove the vm gen_cb for this vm diff --git a/lib/libesp32/berry_mapping/src/be_class_wrapper.c b/lib/libesp32/berry_mapping/src/be_class_wrapper.c index 2f29ab95a..1c567306b 100644 --- a/lib/libesp32/berry_mapping/src/be_class_wrapper.c +++ b/lib/libesp32/berry_mapping/src/be_class_wrapper.c @@ -12,6 +12,10 @@ #include "be_mapping.h" #include "be_exec.h" #include +#include + +/* Ubuntu 22.04 LTS seems to have an invalid or missing signature for strtok_r, forcing a correct one */ +extern char *strtok_r(char *str, const char *delim, char **saveptr); typedef intptr_t (*fn_any_callable)(intptr_t p0, intptr_t p1, intptr_t p2, intptr_t p3, intptr_t p4, intptr_t p5, intptr_t p6, intptr_t p7); @@ -168,7 +172,7 @@ int be_find_global_or_module_member(bvm *vm, const char * name) { // if object instance, get `_p` member and convert it recursively intptr_t be_convert_single_elt(bvm *vm, int idx, const char * arg_type, int *buf_len) { // berry_log_C("be_convert_single_elt(idx=%i, argtype='%s', type=%s)", idx, arg_type ? arg_type : "", be_typename(vm, idx)); - int ret = 0; + intptr_t ret = 0; char provided_type = 0; idx = be_absindex(vm, idx); // make sure we have an absolute index @@ -191,13 +195,13 @@ intptr_t be_convert_single_elt(bvm *vm, int idx, const char * arg_type, int *buf be_pop(vm, 3 + ret); // berry_log_C("func=%p", func); - return (int32_t) func; + return (intptr_t) func; } else { be_raisef(vm, "type_error", "Can't find callback generator: 'cb.make_cb'"); } } else if (be_iscomptr(vm, idx)) { // if it's a pointer, just pass it without any change - return (int32_t) be_tocomptr(vm, idx);; + return (intptr_t) be_tocomptr(vm, idx);; } else { be_raise(vm, "type_error", "Closure expected for callback type"); } @@ -236,7 +240,7 @@ intptr_t be_convert_single_elt(bvm *vm, int idx, const char * arg_type, int *buf // check if the instance is a subclass of `bytes()`` if (be_isbytes(vm, idx)) { size_t len; - intptr_t ret = (intptr_t) be_tobytes(vm, idx, &len); + ret = (intptr_t) be_tobytes(vm, idx, &len); if (buf_len) { *buf_len = (int) len; } return ret; } else { @@ -245,7 +249,7 @@ intptr_t be_convert_single_elt(bvm *vm, int idx, const char * arg_type, int *buf be_pop(vm, 1); // remove `nil` be_getmember(vm, idx, ".p"); } // else `nil` is on top of stack - int32_t ret = be_convert_single_elt(vm, -1, NULL, NULL); // recurse + ret = be_convert_single_elt(vm, -1, NULL, NULL); // recurse be_pop(vm, 1); if (arg_type_len > 1) { @@ -314,7 +318,7 @@ int be_check_arg_type(bvm *vm, int arg_start, int argc, const char * arg_type, i p_idx++; } - for (uint32_t i = 0; i < argc; i++) { + for (int i = 0; i < argc; i++) { type_short_name[0] = 0; // clear string // extract individual type if (arg_type) { diff --git a/lib/libesp32/berry_mapping/src/be_const_members.c b/lib/libesp32/berry_mapping/src/be_const_members.c index 753f30940..29c60d7ca 100644 --- a/lib/libesp32/berry_mapping/src/be_const_members.c +++ b/lib/libesp32/berry_mapping/src/be_const_members.c @@ -23,6 +23,7 @@ #include "be_mapping.h" #include "be_exec.h" #include "be_string.h" +#include "be_module.h" #include /*********************************************************************************************\ * Takes a pointer to be_const_member_t array and size diff --git a/lib/libesp32/berry_mapping/src/be_mapping.h b/lib/libesp32/berry_mapping/src/be_mapping.h index f0ab9d22c..8310a580d 100644 --- a/lib/libesp32/berry_mapping/src/be_mapping.h +++ b/lib/libesp32/berry_mapping/src/be_mapping.h @@ -23,7 +23,6 @@ typedef const void* be_constptr; .v.nf = (const void*) &ctype_func_def##_f, \ .type = BE_CTYPE_FUNC \ } -typedef const void* be_constptr; #define be_const_static_ctype_func(_f) { \ .v.nf = (const void*) &ctype_func_def##_f, \ .type = BE_CTYPE_FUNC | BE_STATIC \ diff --git a/lib/libesp32/berry_matter/solidify_all.be b/lib/libesp32/berry_matter/solidify_all.be index cf19458aa..dd27dbfc1 100755 --- a/lib/libesp32/berry_matter/solidify_all.be +++ b/lib/libesp32/berry_matter/solidify_all.be @@ -16,7 +16,6 @@ var globs = "path,ctypes_bytes_dyn,tasmota,ccronexpr,gpio,light,webclient,load,M "lv_clock,lv_clock_icon,lv_signal_arcs,lv_signal_bars,lv_wifi_arcs_icon,lv_wifi_arcs," "lv_wifi_bars_icon,lv_wifi_bars," "_lvgl," - "int64" for g:string2.split(globs, ",") global.(g) = nil diff --git a/lib/libesp32/berry_matter/src/be_matter_module.c b/lib/libesp32/berry_matter/src/be_matter_module.c index 90176e59a..ed3feb2c6 100644 --- a/lib/libesp32/berry_matter/src/be_matter_module.c +++ b/lib/libesp32/berry_matter/src/be_matter_module.c @@ -197,7 +197,8 @@ extern int matter_publish_command(bvm *vm); #include "solidify/solidified_Matter_0_Inspect.h" extern const bclass be_class_Matter_TLV; // need to declare it upfront because of circular reference -#include "solidify/solidified_Matter_Path.h" +#include "solidify/solidified_Matter_Path_0.h" +#include "solidify/solidified_Matter_Path_1_Generator.h" #include "solidify/solidified_Matter_TLV.h" #include "solidify/solidified_Matter_IM_Data.h" #include "solidify/solidified_Matter_UDPServer.h" @@ -420,6 +421,7 @@ module matter (scope: global, strings: weak) { // Interation Model Path, class(be_class_Matter_Path) + PathGenerator, class(be_class_Matter_PathGenerator) IM_Status, class(be_class_Matter_IM_Status) IM_InvokeResponse, class(be_class_Matter_IM_InvokeResponse) IM_WriteResponse, class(be_class_Matter_IM_WriteResponse) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Fabric.be b/lib/libesp32/berry_matter/src/embedded/Matter_Fabric.be index a2f3daa00..b77f1bd1a 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Fabric.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Fabric.be @@ -98,14 +98,10 @@ class Matter_Fabric : Matter_Expirable def get_fabric_index() return self.fabric_index end def get_fabric_id_as_int64() - var i64 = int64() - i64.frombytes(self.fabric_id) - return i64 + return int64.frombytes(self.fabric_id) end def get_device_id_as_int64() - var i64 = int64() - i64.frombytes(self.device_id) - return i64 + return int64.frombytes(self.device_id) end def get_admin_vendor_name() @@ -339,6 +335,55 @@ class Matter_Fabric : Matter_Expirable return "{" + r.concat(",") + "}" end + ############################################################# + # Fabric::writejson(f) + # + # convert a single entry as json + # write to file + ############################################################# + def writejson(f) + import json + import introspect + + f.write("{") + + self.persist_pre() + var keys = [] + for k : introspect.members(self) + var v = introspect.get(self, k) + if type(v) != 'function' && k[0] != '_' keys.push(k) end + end + keys = matter.sort(keys) + + var first = true + for k : keys + var v = introspect.get(self, k) + if v == nil continue end + if isinstance(v, bytes) v = "$$" + v.tob64() end # bytes + if (!first) f.write(",") end + f.write(format("%s:%s", json.dump(str(k)), json.dump(v))) + first = false + end + + # add sessions + var first_session = true + for sess : self._sessions.persistables() + if first_session + f.write(',"_sessions":[') + else + f.write(",") + end + f.write(sess.tojson()) + first_session = false + end + if !first_session + f.write("]") + end + + self.persist_post() + f.write("}") + end + ############################################################# # fromjson() # diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_IM.be b/lib/libesp32/berry_matter/src/embedded/Matter_IM.be index 628ed5a3c..1e4ca0a78 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_IM.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_IM.be @@ -241,6 +241,7 @@ class Matter_IM attr_name = attr_name ? " (" + attr_name + ")" : "" # Special case to report unsupported item, if pi==nil + ctx.status = nil # reset status, just in case var res = (pi != nil) ? pi.read_attribute(session, ctx, self.tlv_solo) : nil var found = true # stop expansion since we have a value var a1_raw_or_list # contains either a bytes() buffer to append, or a list of bytes(), or nil @@ -290,9 +291,13 @@ class Matter_IM end end else - tasmota.log(format("MTR: >Read_Attr (%6i) %s%s - IGNORED", session.local_session_id, str(ctx), attr_name), 3) + if !no_log + tasmota.log(format("MTR: >Read_Attr (%6i) %s%s - IGNORED", session.local_session_id, str(ctx), attr_name), 3) + end # ignore if content is nil and status is undefined - found = false + if direct + found = false + end end # a1_raw_or_list if either nil, bytes(), of list(bytes()) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Message.be b/lib/libesp32/berry_matter/src/embedded/Matter_Message.be index 70ff59835..f70d2f2b0 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Message.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Message.be @@ -379,7 +379,7 @@ class Matter_Frame n.add(self.flags, 1) n.add(self.message_counter, 4) if self.source_node_id - n .. source_node_id + n .. self.source_node_id else if session.peer_node_id n .. session.peer_node_id diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Path.be b/lib/libesp32/berry_matter/src/embedded/Matter_Path_0.be similarity index 97% rename from lib/libesp32/berry_matter/src/embedded/Matter_Path.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Path_0.be index 5dd1c7d77..ff675c136 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Path.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Path_0.be @@ -1,5 +1,5 @@ # -# Matter_IM_Path.be - suppport for Matter simple Path object +# Matter_IM_Path_0.be - suppport for Matter simple Path object # # Copyright (C) 2023 Stephan Hadinger & Theo Arends # diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Path_1_Generator.be b/lib/libesp32/berry_matter/src/embedded/Matter_Path_1_Generator.be new file mode 100644 index 000000000..eae306543 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Path_1_Generator.be @@ -0,0 +1,273 @@ +# +# Matter_IM_Path_1.be - suppport for Matter concrete path generator +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import matter + +#@ solidify:Matter_PathGenerator,weak + +################################################################################# +# Matter_PathGenerator +# +# INPUT: Takes a context: +# - plugin +# - path (abstract or concrete) +# - session +# +# OUTPUT: +# - returns a concrete Path +# - or `nil` if exhausted +################################################################################# +class Matter_PathGenerator + var device # reference of device main object + var path_in # input path (abstract or concrete) + var session # session object in which the request was made + # current status + var pi # plugin object, `nil` waiting for value, `false` exhausted values + var cluster # current cluster number, `nil` waiting for value, `false` exhausted values + var attribute # current attribute number, `nil` waiting for value, `false` exhausted values + # cache + var clusters # list of clusters sorted + # + var endpoint_found # did we find a valid endpoint? + var cluster_found # did we find a valid cluster? + var attribute_found # did we find a valid attribute? + + # reused at each output + var path_concrete # placeholder for output concrete path + + def init(device) + self.device = device + end + + # start generator + def start(path_in, session) + self.path_concrete = matter.Path() + self.reset() + self.path_in = path_in + self.session = session + # + self.endpoint_found = false + self.cluster_found = false + self.attribute_found = false + end + + def reset() + var n = nil + self.path_in = n + self.session = n + self.path_concrete.reset() + # + self.pi = n # pre-load first plugin + self.cluster = n + self.attribute = n + self.clusters = n + self.clusters = n + end + + def get_pi() + return self.pi + end + ################################################################################ + # next + # + # Generate next concrete path + # Returns: + # - a path object (that is valid until next call) + # - `nil` if no more objects + def next() + if (self.path_in == nil) return nil end + + while (self.pi != false) # loop until we exhausted endpoints + # PRE: self.pi is not `false` + if (self.pi == nil) || (self.cluster == false) # no endpoint yet, or exhausted clusters + self._next_endpoint() + continue + end + # PRE: self.pi is valid, self.cluster is not false + self.endpoint_found = true + if (self.cluster == nil) || (self.attribute == false) # no cluster yet, or exhausted attributes + self._next_cluster() + continue + end + # PRE: self.pi and self.cluster are valid, self.attribute is not false + self.cluster_found = true + self._next_attribute() # advance to first or next attribute + if (self.attribute == false) + continue # iterate so that we explore next cluster + end + # we have a concrete path + self.attribute_found = true + var path_concrete = self.path_concrete + path_concrete.reset() + path_concrete.endpoint = self.pi.get_endpoint() + path_concrete.cluster = self.cluster + path_concrete.attribute = self.attribute + return path_concrete + end + # we exhausted all endpoints - finish and clean + self.reset() + return nil + end + + #------------------------------------------------------------------------------# + # advance to next endpoint + def _next_endpoint() + if (self.pi == false) return false end # exhausted all possible values + + var plugins = self.device.plugins # shortcut + var ep_filter = self.path_in.endpoint + # cluster and attribute are now undefined + self.cluster = nil + self.attribute = nil + # idx contains the index of current plugin, or `nil` if not started + var idx = -1 + if (self.pi != nil) + idx = plugins.find(self.pi) # find index in current list + end + # safeguard + if (idx != nil) + while (idx + 1 < size(plugins)) + idx += 1 # move to next item + self.pi = plugins[idx] + if (ep_filter == nil) || (ep_filter == self.pi.get_endpoint()) + self.clusters = self.pi.get_cluster_list_sorted() # memoize clusters + return self.pi + end + # iterate + end + end + self.pi = false + return false + end + + #------------------------------------------------------------------------------# + # advance to next cluster + # + # self.clusters already contains the sorted list of clusters of pi + def _next_cluster() + if (self.cluster == false) return false end # exhausted all possible values + + var clusters = self.clusters + var cl_filter = self.path_in.cluster + # attribute is now undefined + self.attribute = nil + var idx = -1 + if (self.cluster != nil) + idx = clusters.find(self.cluster) # find index in current list + end + # safeguard + if (idx != nil) + while (idx + 1 < size(clusters)) + idx += 1 # move to next item + self.cluster = clusters[idx] + if (cl_filter == nil) || (cl_filter == self.cluster) + return self.cluster + end + end + end + self.cluster = false + return false + end + + #------------------------------------------------------------------------------# + # advance to next attribute + # + # self.clusters already contains the sorted list of clusters of pi + def _next_attribute() + if (self.attribute == false) return false end # exhausted all possible values + + var attributes = self.pi.get_attribute_list(self.cluster) + var attr_filter = self.path_in.attribute + var idx = -1 + if (self.attribute != nil) + idx = attributes.find(self.attribute) # find index in current list + end + # safeguard + if (idx != nil) + while (idx + 1 < size(attributes)) + idx += 1 # move to next item + self.attribute = attributes[idx] + if (attr_filter == nil) || (attr_filter == self.attribute) + return self.attribute + end + end + end + self.attribute = false + return false + end + +end +matter.PathGenerator = Matter_PathGenerator + +#- + +# Tests + +var gen = matter.PathGenerator(matter_device) + +def gen_path_dump(endpoint, cluster, attribute) + var path = matter.Path() + path.endpoint = endpoint + path.cluster = cluster + path.attribute = attribute + gen.start(path) + var cp + while (cp := gen.next()) + print(cp) + end +end + + +gen_path_dump(nil, nil, nil) +gen_path_dump(1, nil, nil) +gen_path_dump(1, 3, nil) +gen_path_dump(nil, 5, nil) +gen_path_dump(nil, nil, 0xFFFB) +gen_path_dump(4, 5, 5) +gen_path_dump(4, 5, 6) + + + +var gen = matter.PathGenerator(matter_device) +var path = matter.Path() +path.endpoint = nil +gen.start(path) + +# print(gen._next_endpoint()) +# print(gen._next_cluster()) +# print(gen._next_attribute()) + + + +var gen = matter.PathGenerator(matter_device) +var path = matter.Path() +path.endpoint = 4 +path.cluster = 5 +path.attribute = 1 +gen.start(path) + + + + +var cp +while (cp := gen.next()) + print(cp) +end + +-# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_0.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_0.be index 2a53cc501..d8315c3ec 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_0.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_0.be @@ -233,12 +233,8 @@ class Matter_Plugin def get_endpoint() return self.endpoint end - def get_cluster_list() - var ret = [] - for k: self.clusters.keys() - ret.push(k) - end - return ret + def get_cluster_list_sorted() + return self.device.k2l(self.clusters) end def contains_cluster(cluster) return self.clusters.contains(cluster) @@ -302,7 +298,7 @@ class Matter_Plugin return dtl elif attribute == 0x0001 # ---------- ServerList / list[cluster-id] ---------- var sl = TLV.Matter_TLV_array() - for cl: self.get_cluster_list() + for cl: self.get_cluster_list_sorted() sl.add_TLV(nil, TLV.U4, cl) end return sl @@ -347,6 +343,8 @@ class Matter_Plugin return tlv_solo.set(TLV.U4, clusterrevision) end + # no handler found, return nil + return nil end ############################################################# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_1_Root.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_1_Root.be index 87af9396b..086d335aa 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_1_Root.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_1_Root.be @@ -159,7 +159,7 @@ class Matter_Plugin_Root : Matter_Plugin var nocs = nocl.add_struct(nil) nocs.add_TLV(1, TLV.B2, loc_fabric.get_noc()) # NOC nocs.add_TLV(2, TLV.B2, loc_fabric.get_icac()) # ICAC - nocs.add_TLV(matter.AGGREGATOR_ENDPOINT, TLV.U2, loc_fabric.get_fabric_index()) # Label + nocs.add_TLV(0xFE, TLV.U2, loc_fabric.get_fabric_index()) # Label end return nocl elif attribute == 0x0001 # ---------- Fabrics / list[FabricDescriptorStruct] ---------- diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Session_Store.be b/lib/libesp32/berry_matter/src/embedded/Matter_Session_Store.be index e59d35770..7e531d36a 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Session_Store.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Session_Store.be @@ -35,7 +35,8 @@ class Matter_Session_Store var device # device root object var sessions var fabrics # list of provisioned fabrics - static var _FABRICS = "_matter_fabrics.json" + static var _FABRICS = "/_matter_fabrics.json" + static var _FABRICS_TEMP = "/_matter_fabrics.tmp" # temporary saved file before renaming to _FABRICS ############################################################# def init(device) @@ -318,12 +319,13 @@ class Matter_Session_Store ############################################################# def save_fabrics() import json + import path try self.remove_expired() # clean before saving var sessions_saved = 0 var fabrics_saved = 0 - var f = open(self._FABRICS, "w") + var f = open(self._FABRICS_TEMP, "w") f.write("[") for fab : self.fabrics.persistables() @@ -331,15 +333,20 @@ class Matter_Session_Store if fabrics_saved > 0 f.write(",") end - var f_json = fab.tojson() - f.write(f_json) + fab.writejson(f) fabrics_saved += 1 end f.write("]") f.close() - tasmota.log(f"MTR: =Saved {fabrics_saved} fabric(s) and {sessions_saved} session(s)", 2) - self.device.event_fabrics_saved() # signal event + # saving went well, now remove previous version and rename + path.remove(self._FABRICS) + if (path.rename(self._FABRICS_TEMP, self._FABRICS)) + tasmota.log(f"MTR: =Saved {fabrics_saved} fabric(s) and {sessions_saved} session(s)", 2) + self.device.event_fabrics_saved() # signal event + else + tasmota.log(f"MTR: Saving Fabrics failed", 2) + end except .. as e, m tasmota.log("MTR: Session_Store::save Exception:" + str(e) + "|" + str(m), 2) end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be b/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be index 9c19e0b36..74a10d25a 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be @@ -241,8 +241,7 @@ class Matter_TLV var item_len = TLV._len[item_type] if item_len == 8 # i64 / u64 / double - self.val = int64() - self.val.frombytes(b, idx) + self.val = int64.frombytes(b, idx) idx += 8 elif item_type == TLV.BFALSE || item_type == TLV.BTRUE # bool self.val = (item_type == TLV.BTRUE) @@ -970,64 +969,3 @@ end # add to matter import matter matter.TLV = Matter_TLV - -#- - -# Test -import matter - -def test_TLV(b, s) - var m = matter.TLV.parse(b) - assert(m.tostring() == s) - assert(m.tlv2raw() == b) - assert(m.encode_len() == size(b)) -end - -test_TLV(bytes("2502054C"), "2 = 19461U") -test_TLV(bytes("0001"), "1") -test_TLV(bytes("08"), "false") -test_TLV(bytes("09"), "true") - -var TLV = matter.TLV -assert(TLV.create_TLV(TLV.BOOL, 1).tlv2raw() == bytes("09")) -assert(TLV.create_TLV(TLV.BOOL, true).tlv2raw() == bytes("09")) -assert(TLV.create_TLV(TLV.BOOL, 0).tlv2raw() == bytes("08")) -assert(TLV.create_TLV(TLV.BOOL, false).tlv2raw() == bytes("08")) - -test_TLV(bytes("00FF"), "-1") -test_TLV(bytes("05FFFF"), "65535U") - -test_TLV(bytes("0A0000C03F"), "1.5") -test_TLV(bytes("0C06466f6f626172"), '"Foobar"') -test_TLV(bytes("1006466f6f626172"), "466F6F626172") -test_TLV(bytes("e4f1ffeddeedfe55aa2a"), "0xFFF1::0xDEED:0xAA55FEED = 42U") -test_TLV(bytes("300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66"), "1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66") - -# context specific -test_TLV(bytes("24012a"), "1 = 42U") -test_TLV(bytes("4401002a"), "Matter::0x00000001 = 42U") - -# int64 -test_TLV(bytes("030102000000000000"), "513") -test_TLV(bytes("070102000000000000"), "513U") -test_TLV(bytes("03FFFFFFFFFFFFFFFF"), "-1") -test_TLV(bytes("07FFFFFFFFFFFFFF7F"), "9223372036854775807U") - -# structure -test_TLV(bytes("1518"), "{}") -test_TLV(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280418"), "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false}") -test_TLV(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818"), "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false, 5 = {1 = 5000U, 2 = 300U}}") - -# list -test_TLV(bytes("1718"), "[[]]") -test_TLV(bytes("17000120002a000200032000ef18"), "[[1, 0 = 42, 2, 3, 0 = -17]]") - -# array -test_TLV(bytes("1618"), "[]") -test_TLV(bytes("160000000100020003000418"), "[0, 1, 2, 3, 4]") - -# mix -test_TLV(bytes("16002a02f067fdff15180a33338f410c0648656c6c6f2118"), '[42, -170000, {}, 17.9, "Hello!"]') -test_TLV(bytes("153600172403312504FCFF18172402002403302404001817240200240330240401181724020024033024040218172402002403302404031817240200240328240402181724020024032824040418172403312404031818280324FF0118"), '{0 = [[[3 = 49U, 4 = 65532U]], [[2 = 0U, 3 = 48U, 4 = 0U]], [[2 = 0U, 3 = 48U, 4 = 1U]], [[2 = 0U, 3 = 48U, 4 = 2U]], [[2 = 0U, 3 = 48U, 4 = 3U]], [[2 = 0U, 3 = 40U, 4 = 2U]], [[2 = 0U, 3 = 40U, 4 = 4U]], [[3 = 49U, 4 = 3U]]], 3 = false, 255 = 1U}') - --# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_zz_Device.be b/lib/libesp32/berry_matter/src/embedded/Matter_zz_Device.be index 5459b581b..799d75e8e 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_zz_Device.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_zz_Device.be @@ -523,27 +523,6 @@ class Matter_Device # returns: `true` if processed succesfully, `false` if error occured. If `direct`, the error is returned to caller, but if expanded the error is silently ignored and the attribute skipped. # In case of `direct` but the endpoint/cluster/attribute is not suppported, it calls `cb(nil, ctx, true)` so you have a chance to encode the exact error (UNSUPPORTED_ENDPOINT/UNSUPPORTED_CLUSTER/UNSUPPORTED_ATTRIBUTE/UNREPORTABLE_ATTRIBUTE) def process_attribute_expansion(ctx, cb) - ################################################################################# - # Returns the keys of a map as a sorted list - ################################################################################# - def keys_sorted(m) - var l = [] - for k: m.keys() - l.push(k) - end - # insertion sort - for i:1..size(l)-1 - var k = l[i] - var j = i - while (j > 0) && (l[j-1] > k) - l[j] = l[j-1] - j -= 1 - end - l[j] = k - end - return l - end - var endpoint = ctx.endpoint var cluster = ctx.cluster var attribute = ctx.attribute @@ -555,68 +534,22 @@ class Matter_Device # tasmota.log(f"MTR: process_attribute_expansion {str(ctx))}", 4) - # build the list of candidates + # build the generator for all endpoint/cluster/attributes candidates + var path_generator = matter.PathGenerator(self) + path_generator.start(ctx, nil) # TODO add session if we think it's needed later - # list of all endpoints - var all = {} # map of {endpoint: {cluster: {attributes:[pi]}} - # tasmota.log(format("MTR: endpoint=%s cluster=%s attribute=%s", endpoint, cluster, attribute), 4) - for pi: self.plugins - var ep = pi.get_endpoint() # get supported endpoints for this plugin - - if endpoint != nil && ep != endpoint continue end # skip if specific endpoint and no match - # from now on, 'ep' is a good candidate - if !all.contains(ep) all[ep] = {} end # create empty structure if not already in the list - endpoint_found = true - - # now explore the cluster list for 'ep' - var cluster_list = pi.get_cluster_list() # cluster_list is the actual list of candidate cluster for this pluging and endpoint - # tasmota.log(format("MTR: pi=%s ep=%s cl_list=%s", str(pi), str(ep), str(cluster_list)), 4) - for cl: cluster_list - if cluster != nil && cl != cluster continue end # skip if specific cluster and no match - # from now on, 'cl' is a good candidate - if !all[ep].contains(cl) all[ep][cl] = {} end - cluster_found = true - - # now filter on attributes - var attr_list = pi.get_attribute_list(cl) - # tasmota.log(format("MTR: pi=%s ep=%s cl=%s at_list=%s", str(pi), str(ep), str(cl), str(attr_list)), 4) - for at: attr_list - if attribute != nil && at != attribute continue end # skip if specific attribute and no match - # from now on, 'at' is a good candidate - if !all[ep][cl].contains(at) all[ep][cl][at] = [] end - attribute_found = true - - all[ep][cl][at].push(pi) # add plugin to the list - end - end - end - - # import json - # tasmota.log("MTR: all = " + json.dump(all), 2) - - # iterate on candidates - for ep: keys_sorted(all) - for cl: keys_sorted(all[ep]) - for at: keys_sorted(all[ep][cl]) - for pi: all[ep][cl][at] - # tasmota.log(format("MTR: expansion [%02X]%04X/%04X", ep, cl, at), 3) - ctx.endpoint = ep - ctx.cluster = cl - ctx.attribute = at - var finished = cb(pi, ctx, direct) # call the callback with the plugin and the context - # tasmota.log("MTR: gc="+str(tasmota.gc()), 2) - if direct && finished return end - end - end - end + var concrete_path + while ((concrete_path := path_generator.next()) != nil) + var finished = cb(path_generator.get_pi(), concrete_path, direct) # call the callback with the plugin and the context + if direct && finished return end end # we didn't have any successful match, report an error if direct (non-expansion request) if direct # since it's a direct request, ctx has already the correct endpoint/cluster/attribute - if !endpoint_found ctx.status = matter.UNSUPPORTED_ENDPOINT - elif !cluster_found ctx.status = matter.UNSUPPORTED_CLUSTER - elif !attribute_found ctx.status = matter.UNSUPPORTED_ATTRIBUTE + if !path_generator.endpoint_found ctx.status = matter.UNSUPPORTED_ENDPOINT + elif !path_generator.cluster_found ctx.status = matter.UNSUPPORTED_CLUSTER + elif !path_generator.attribute_found ctx.status = matter.UNSUPPORTED_ATTRIBUTE else ctx.status = matter.UNREPORTABLE_ATTRIBUTE end cb(nil, ctx, true) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_zzz_TLV_test.be b/lib/libesp32/berry_matter/src/embedded/Matter_zzz_TLV_test.be new file mode 100644 index 000000000..7b8eab8a0 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_zzz_TLV_test.be @@ -0,0 +1,77 @@ +# +# Matter_TLV.be - implements the encoding and decoding of Matter TLV structures (Tag/Lenght/Value) Appendix A. +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# Support for Matter Protocol: TLV encoding and decoding + +# Test +import matter + +def test_TLV(b, s) + var m = matter.TLV.parse(b) + assert(m.tostring() == s) + assert(m.tlv2raw() == b) + assert(m.encode_len() == size(b)) +end + +test_TLV(bytes("2502054C"), "2 = 19461U") +test_TLV(bytes("0001"), "1") +test_TLV(bytes("08"), "false") +test_TLV(bytes("09"), "true") + +var TLV = matter.TLV +assert(TLV.create_TLV(TLV.BOOL, 1).tlv2raw() == bytes("09")) +assert(TLV.create_TLV(TLV.BOOL, true).tlv2raw() == bytes("09")) +assert(TLV.create_TLV(TLV.BOOL, 0).tlv2raw() == bytes("08")) +assert(TLV.create_TLV(TLV.BOOL, false).tlv2raw() == bytes("08")) + +test_TLV(bytes("00FF"), "-1") +test_TLV(bytes("05FFFF"), "65535U") + +test_TLV(bytes("0A0000C03F"), "1.5") +test_TLV(bytes("0C06466f6f626172"), '"Foobar"') +test_TLV(bytes("1006466f6f626172"), "466F6F626172") +test_TLV(bytes("e4f1ffeddeedfe55aa2a"), "0xFFF1::0xDEED:0xAA55FEED = 42U") +test_TLV(bytes("300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66"), "1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66") + +# context specific +test_TLV(bytes("24012a"), "1 = 42U") +test_TLV(bytes("4401002a"), "Matter::0x00000001 = 42U") + +# int64 +test_TLV(bytes("030102000000000000"), "513") +test_TLV(bytes("070102000000000000"), "513U") +test_TLV(bytes("03FFFFFFFFFFFFFFFF"), "-1") +test_TLV(bytes("07FFFFFFFFFFFFFF7F"), "9223372036854775807U") + +# structure +test_TLV(bytes("1518"), "{}") +test_TLV(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280418"), "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false}") +test_TLV(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818"), "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false, 5 = {1 = 5000U, 2 = 300U}}") + +# list +test_TLV(bytes("1718"), "[[]]") +test_TLV(bytes("17000120002a000200032000ef18"), "[[1, 0 = 42, 2, 3, 0 = -17]]") + +# array +test_TLV(bytes("1618"), "[]") +test_TLV(bytes("160000000100020003000418"), "[0, 1, 2, 3, 4]") + +# mix +test_TLV(bytes("16002a02f067fdff15180a33338f410c0648656c6c6f2118"), '[42, -170000, {}, 17.9, "Hello!"]') +test_TLV(bytes("153600172403312504FCFF18172402002403302404001817240200240330240401181724020024033024040218172402002403302404031817240200240328240402181724020024032824040418172403312404031818280324FF0118"), '{0 = [[[3 = 49U, 4 = 65532U]], [[2 = 0U, 3 = 48U, 4 = 0U]], [[2 = 0U, 3 = 48U, 4 = 1U]], [[2 = 0U, 3 = 48U, 4 = 2U]], [[2 = 0U, 3 = 48U, 4 = 3U]], [[2 = 0U, 3 = 40U, 4 = 2U]], [[2 = 0U, 3 = 40U, 4 = 4U]], [[3 = 49U, 4 = 3U]]], 3 = false, 255 = 1U}') diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Fabric.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Fabric.h index 434360b2f..c882ed705 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Fabric.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Fabric.h @@ -7,83 +7,87 @@ extern const bclass be_class_Matter_Fabric; /******************************************************************** -** Solidified function: get_device_id_as_int64 +** Solidified function: get_icac ********************************************************************/ -be_local_closure(Matter_Fabric_get_device_id_as_int64, /* name */ - be_nested_proto( - 5, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(int64), - /* K1 */ be_nested_str_weak(frombytes), - /* K2 */ be_nested_str_weak(device_id), - }), - be_str_weak(get_device_id_as_int64), - &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ - 0xB8060000, // 0000 GETNGBL R1 K0 - 0x7C040000, // 0001 CALL R1 0 - 0x8C080301, // 0002 GETMET R2 R1 K1 - 0x88100102, // 0003 GETMBR R4 R0 K2 - 0x7C080400, // 0004 CALL R2 2 - 0x80040200, // 0005 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: fabric_candidate -********************************************************************/ -be_local_closure(Matter_Fabric_fabric_candidate, /* name */ - be_nested_proto( - 4, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(set_expire_in_seconds), - /* K1 */ be_nested_str_weak(assign_fabric_index), - /* K2 */ be_nested_str_weak(_store), - /* K3 */ be_nested_str_weak(add_fabric), - }), - be_str_weak(fabric_candidate), - &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x540E0077, // 0001 LDINT R3 120 - 0x7C040400, // 0002 CALL R1 2 - 0x8C040101, // 0003 GETMET R1 R0 K1 - 0x7C040200, // 0004 CALL R1 1 - 0x88040102, // 0005 GETMBR R1 R0 K2 - 0x8C040303, // 0006 GETMET R1 R1 K3 - 0x5C0C0000, // 0007 MOVE R3 R0 - 0x7C040400, // 0008 CALL R1 2 - 0x80000000, // 0009 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_pk -********************************************************************/ -be_local_closure(Matter_Fabric_set_pk, /* name */ +be_local_closure(Matter_Fabric_get_icac, /* name */ be_nested_proto( 2, /* nstack */ - 2, /* argc */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(icac), + }), + be_str_weak(get_icac), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: before_remove +********************************************************************/ +be_local_closure(Matter_Fabric_before_remove, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(log), + /* K2 */ be_nested_str_weak(MTR_X3A_X20_X2DFabric_X20_X20_X20_X20fab_X3D_X27_X25s_X27_X20_X28removed_X29), + /* K3 */ be_nested_str_weak(get_fabric_id), + /* K4 */ be_nested_str_weak(copy), + /* K5 */ be_nested_str_weak(reverse), + /* K6 */ be_nested_str_weak(tohex), + /* K7 */ be_const_int(3), + }), + be_str_weak(before_remove), + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x600C0018, // 0002 GETGBL R3 G24 + 0x58100002, // 0003 LDCONST R4 K2 + 0x8C140103, // 0004 GETMET R5 R0 K3 + 0x7C140200, // 0005 CALL R5 1 + 0x8C140B04, // 0006 GETMET R5 R5 K4 + 0x7C140200, // 0007 CALL R5 1 + 0x8C140B05, // 0008 GETMET R5 R5 K5 + 0x7C140200, // 0009 CALL R5 1 + 0x8C140B06, // 000A GETMET R5 R5 K6 + 0x7C140200, // 000B CALL R5 1 + 0x7C0C0400, // 000C CALL R3 2 + 0x58100007, // 000D LDCONST R4 K7 + 0x7C040600, // 000E CALL R1 3 + 0x80000000, // 000F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_pk +********************************************************************/ +be_local_closure(Matter_Fabric_get_pk, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -93,11 +97,11 @@ be_local_closure(Matter_Fabric_set_pk, /* name */ ( &(const bvalue[ 1]) { /* constants */ /* K0 */ be_nested_str_weak(no_private_key), }), - be_str_weak(set_pk), + be_str_weak(get_pk), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 }) ) ); @@ -105,102 +109,9 @@ be_local_closure(Matter_Fabric_set_pk, /* name */ /******************************************************************** -** Solidified function: add_session +** Solidified function: get_fabric_compressed ********************************************************************/ -be_local_closure(Matter_Fabric_add_session, /* name */ - be_nested_proto( - 8, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(_sessions), - /* K1 */ be_nested_str_weak(find), - /* K2 */ be_nested_str_weak(_MAX_CASE), - /* K3 */ be_nested_str_weak(get_oldest_session), - /* K4 */ be_nested_str_weak(remove), - /* K5 */ be_nested_str_weak(_store), - /* K6 */ be_nested_str_weak(remove_session), - /* K7 */ be_nested_str_weak(push), - }), - be_str_weak(add_session), - &be_const_str_solidified, - ( &(const binstruction[32]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x5C100200, // 0002 MOVE R4 R1 - 0x7C080400, // 0003 CALL R2 2 - 0x4C0C0000, // 0004 LDNIL R3 - 0x1C080403, // 0005 EQ R2 R2 R3 - 0x780A0017, // 0006 JMPF R2 #001F - 0x6008000C, // 0007 GETGBL R2 G12 - 0x880C0100, // 0008 GETMBR R3 R0 K0 - 0x7C080200, // 0009 CALL R2 1 - 0x880C0102, // 000A GETMBR R3 R0 K2 - 0x28080403, // 000B GE R2 R2 R3 - 0x780A000D, // 000C JMPF R2 #001B - 0x8C080103, // 000D GETMET R2 R0 K3 - 0x7C080200, // 000E CALL R2 1 - 0x880C0100, // 000F GETMBR R3 R0 K0 - 0x8C0C0704, // 0010 GETMET R3 R3 K4 - 0x88140100, // 0011 GETMBR R5 R0 K0 - 0x8C140B01, // 0012 GETMET R5 R5 K1 - 0x5C1C0400, // 0013 MOVE R7 R2 - 0x7C140400, // 0014 CALL R5 2 - 0x7C0C0400, // 0015 CALL R3 2 - 0x880C0105, // 0016 GETMBR R3 R0 K5 - 0x8C0C0706, // 0017 GETMET R3 R3 K6 - 0x5C140400, // 0018 MOVE R5 R2 - 0x7C0C0400, // 0019 CALL R3 2 - 0x7001FFEB, // 001A JMP #0007 - 0x88080100, // 001B GETMBR R2 R0 K0 - 0x8C080507, // 001C GETMET R2 R2 K7 - 0x5C100200, // 001D MOVE R4 R1 - 0x7C080400, // 001E CALL R2 2 - 0x80000000, // 001F RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_oldest_session -********************************************************************/ -be_local_closure(Matter_Fabric_get_oldest_session, /* name */ - be_nested_proto( - 4, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(get_old_recent_session), - }), - be_str_weak(get_oldest_session), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x500C0200, // 0001 LDBOOL R3 1 0 - 0x7C040400, // 0002 CALL R1 2 - 0x80040200, // 0003 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ipk_epoch_key -********************************************************************/ -be_local_closure(Matter_Fabric_get_ipk_epoch_key, /* name */ +be_local_closure(Matter_Fabric_get_fabric_compressed, /* name */ be_nested_proto( 2, /* nstack */ 1, /* argc */ @@ -211,9 +122,92 @@ be_local_closure(Matter_Fabric_get_ipk_epoch_key, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(ipk_epoch_key), + /* K0 */ be_nested_str_weak(fabric_compressed), }), - be_str_weak(get_ipk_epoch_key), + be_str_weak(get_fabric_compressed), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_fabric_id +********************************************************************/ +be_local_closure(Matter_Fabric_get_fabric_id, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(fabric_id), + }), + be_str_weak(get_fabric_id), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_admin_subject_vendor +********************************************************************/ +be_local_closure(Matter_Fabric_set_admin_subject_vendor, /* name */ + be_nested_proto( + 3, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(admin_subject), + /* K1 */ be_nested_str_weak(admin_vendor), + }), + be_str_weak(set_admin_subject_vendor), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_admin_vendor +********************************************************************/ +be_local_closure(Matter_Fabric_get_admin_vendor, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(admin_vendor), + }), + be_str_weak(get_admin_vendor), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 @@ -252,26 +246,117 @@ be_local_closure(Matter_Fabric_get_noc, /* name */ /******************************************************************** -** Solidified function: get_device_id +** Solidified function: fromjson ********************************************************************/ -be_local_closure(Matter_Fabric_get_device_id, /* name */ +be_local_closure(Matter_Fabric_fromjson, /* name */ be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ + 16, /* nstack */ + 2, /* argc */ + 4, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(device_id), + ( &(const bvalue[18]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Fabric), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(introspect), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(Fabric), + /* K5 */ be_nested_str_weak(keys), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(_), + /* K8 */ be_nested_str_weak(find), + /* K9 */ be_nested_str_weak(0x), + /* K10 */ be_nested_str_weak(set), + /* K11 */ be_nested_str_weak(fromhex), + /* K12 */ be_const_int(2), + /* K13 */ be_const_int(2147483647), + /* K14 */ be_nested_str_weak(_X24_X24), + /* K15 */ be_nested_str_weak(fromb64), + /* K16 */ be_nested_str_weak(stop_iteration), + /* K17 */ be_nested_str_weak(hydrate_post), }), - be_str_weak(get_device_id), + be_str_weak(fromjson), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 + ( &(const binstruction[76]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0xA4120400, // 0002 IMPORT R4 K2 + 0xB8160600, // 0003 GETNGBL R5 K3 + 0x8C140B04, // 0004 GETMET R5 R5 K4 + 0x5C1C0000, // 0005 MOVE R7 R0 + 0x7C140400, // 0006 CALL R5 2 + 0x60180010, // 0007 GETGBL R6 G16 + 0x8C1C0305, // 0008 GETMET R7 R1 K5 + 0x7C1C0200, // 0009 CALL R7 1 + 0x7C180200, // 000A CALL R6 1 + 0xA8020039, // 000B EXBLK 0 #0046 + 0x5C1C0C00, // 000C MOVE R7 R6 + 0x7C1C0000, // 000D CALL R7 0 + 0x94200F06, // 000E GETIDX R8 R7 K6 + 0x1C201107, // 000F EQ R8 R8 K7 + 0x78220000, // 0010 JMPF R8 #0012 + 0x7001FFF9, // 0011 JMP #000C + 0x94200207, // 0012 GETIDX R8 R1 R7 + 0x60240004, // 0013 GETGBL R9 G4 + 0x5C281000, // 0014 MOVE R10 R8 + 0x7C240200, // 0015 CALL R9 1 + 0x1C241301, // 0016 EQ R9 R9 K1 + 0x78260027, // 0017 JMPF R9 #0040 + 0x8C240708, // 0018 GETMET R9 R3 K8 + 0x5C2C1000, // 0019 MOVE R11 R8 + 0x58300009, // 001A LDCONST R12 K9 + 0x7C240600, // 001B CALL R9 3 + 0x1C241306, // 001C EQ R9 R9 K6 + 0x7826000A, // 001D JMPF R9 #0029 + 0x8C24090A, // 001E GETMET R9 R4 K10 + 0x5C2C0A00, // 001F MOVE R11 R5 + 0x5C300E00, // 0020 MOVE R12 R7 + 0x60340015, // 0021 GETGBL R13 G21 + 0x7C340000, // 0022 CALL R13 0 + 0x8C341B0B, // 0023 GETMET R13 R13 K11 + 0x403E190D, // 0024 CONNECT R15 K12 K13 + 0x943C100F, // 0025 GETIDX R15 R8 R15 + 0x7C340400, // 0026 CALL R13 2 + 0x7C240800, // 0027 CALL R9 4 + 0x70020015, // 0028 JMP #003F + 0x8C240708, // 0029 GETMET R9 R3 K8 + 0x5C2C1000, // 002A MOVE R11 R8 + 0x5830000E, // 002B LDCONST R12 K14 + 0x7C240600, // 002C CALL R9 3 + 0x1C241306, // 002D EQ R9 R9 K6 + 0x7826000A, // 002E JMPF R9 #003A + 0x8C24090A, // 002F GETMET R9 R4 K10 + 0x5C2C0A00, // 0030 MOVE R11 R5 + 0x5C300E00, // 0031 MOVE R12 R7 + 0x60340015, // 0032 GETGBL R13 G21 + 0x7C340000, // 0033 CALL R13 0 + 0x8C341B0F, // 0034 GETMET R13 R13 K15 + 0x403E190D, // 0035 CONNECT R15 K12 K13 + 0x943C100F, // 0036 GETIDX R15 R8 R15 + 0x7C340400, // 0037 CALL R13 2 + 0x7C240800, // 0038 CALL R9 4 + 0x70020004, // 0039 JMP #003F + 0x8C24090A, // 003A GETMET R9 R4 K10 + 0x5C2C0A00, // 003B MOVE R11 R5 + 0x5C300E00, // 003C MOVE R12 R7 + 0x5C341000, // 003D MOVE R13 R8 + 0x7C240800, // 003E CALL R9 4 + 0x70020004, // 003F JMP #0045 + 0x8C24090A, // 0040 GETMET R9 R4 K10 + 0x5C2C0A00, // 0041 MOVE R11 R5 + 0x5C300E00, // 0042 MOVE R12 R7 + 0x5C341000, // 0043 MOVE R13 R8 + 0x7C240800, // 0044 CALL R9 4 + 0x7001FFC5, // 0045 JMP #000C + 0x58180010, // 0046 LDCONST R6 K16 + 0xAC180200, // 0047 CATCH R6 1 0 + 0xB0080000, // 0048 RAISE 2 R0 R0 + 0x8C180B11, // 0049 GETMET R6 R5 K17 + 0x7C180200, // 004A CALL R6 1 + 0x80040A00, // 004B RET 1 R5 }) ) ); @@ -279,36 +364,9 @@ be_local_closure(Matter_Fabric_get_device_id, /* name */ /******************************************************************** -** Solidified function: get_icac +** Solidified function: set_ca ********************************************************************/ -be_local_closure(Matter_Fabric_get_icac, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(icac), - }), - be_str_weak(get_icac), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_fabric_index -********************************************************************/ -be_local_closure(Matter_Fabric_set_fabric_index, /* name */ +be_local_closure(Matter_Fabric_set_ca, /* name */ be_nested_proto( 2, /* nstack */ 2, /* argc */ @@ -319,9 +377,9 @@ be_local_closure(Matter_Fabric_set_fabric_index, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric_index), + /* K0 */ be_nested_str_weak(root_ca_certificate), }), - be_str_weak(set_fabric_index), + be_str_weak(set_ca), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x90020001, // 0000 SETMBR R0 K0 R1 @@ -332,154 +390,6 @@ be_local_closure(Matter_Fabric_set_fabric_index, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: fabric_completed -********************************************************************/ -be_local_closure(Matter_Fabric_fabric_completed, /* name */ - be_nested_proto( - 4, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(set_no_expiration), - /* K1 */ be_nested_str_weak(set_persist), - /* K2 */ be_nested_str_weak(assign_fabric_index), - /* K3 */ be_nested_str_weak(_store), - /* K4 */ be_nested_str_weak(add_fabric), - }), - be_str_weak(fabric_completed), - &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x7C040200, // 0001 CALL R1 1 - 0x8C040101, // 0002 GETMET R1 R0 K1 - 0x500C0200, // 0003 LDBOOL R3 1 0 - 0x7C040400, // 0004 CALL R1 2 - 0x8C040102, // 0005 GETMET R1 R0 K2 - 0x7C040200, // 0006 CALL R1 1 - 0x88040103, // 0007 GETMBR R1 R0 K3 - 0x8C040304, // 0008 GETMET R1 R1 K4 - 0x5C0C0000, // 0009 MOVE R3 R0 - 0x7C040400, // 000A CALL R1 2 - 0x80000000, // 000B RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_pk -********************************************************************/ -be_local_closure(Matter_Fabric_get_pk, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(no_private_key), - }), - be_str_weak(get_pk), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: log_new_fabric -********************************************************************/ -be_local_closure(Matter_Fabric_log_new_fabric, /* name */ - be_nested_proto( - 8, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(log), - /* K2 */ be_nested_str_weak(MTR_X3A_X20_X2BFabric_X20_X20_X20_X20fab_X3D_X27_X25s_X27_X20vendorid_X3D_X25s), - /* K3 */ be_nested_str_weak(get_fabric_id), - /* K4 */ be_nested_str_weak(copy), - /* K5 */ be_nested_str_weak(reverse), - /* K6 */ be_nested_str_weak(tohex), - /* K7 */ be_nested_str_weak(get_admin_vendor_name), - /* K8 */ be_const_int(3), - }), - be_str_weak(log_new_fabric), - &be_const_str_solidified, - ( &(const binstruction[18]) { /* code */ - 0xB8060000, // 0000 GETNGBL R1 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x600C0018, // 0002 GETGBL R3 G24 - 0x58100002, // 0003 LDCONST R4 K2 - 0x8C140103, // 0004 GETMET R5 R0 K3 - 0x7C140200, // 0005 CALL R5 1 - 0x8C140B04, // 0006 GETMET R5 R5 K4 - 0x7C140200, // 0007 CALL R5 1 - 0x8C140B05, // 0008 GETMET R5 R5 K5 - 0x7C140200, // 0009 CALL R5 1 - 0x8C140B06, // 000A GETMET R5 R5 K6 - 0x7C140200, // 000B CALL R5 1 - 0x8C180107, // 000C GETMET R6 R0 K7 - 0x7C180200, // 000D CALL R6 1 - 0x7C0C0600, // 000E CALL R3 3 - 0x58100008, // 000F LDCONST R4 K8 - 0x7C040600, // 0010 CALL R1 3 - 0x80000000, // 0011 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_newest_session -********************************************************************/ -be_local_closure(Matter_Fabric_get_newest_session, /* name */ - be_nested_proto( - 4, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(get_old_recent_session), - }), - be_str_weak(get_newest_session), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x500C0000, // 0001 LDBOOL R3 0 0 - 0x7C040400, // 0002 CALL R1 2 - 0x80040200, // 0003 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: tojson ********************************************************************/ @@ -651,11 +561,11 @@ be_local_closure(Matter_Fabric_tojson, /* name */ /******************************************************************** -** Solidified function: before_remove +** Solidified function: hydrate_post ********************************************************************/ -be_local_closure(Matter_Fabric_before_remove, /* name */ +be_local_closure(Matter_Fabric_hydrate_post, /* name */ be_nested_proto( - 7, /* nstack */ + 4, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -663,35 +573,34 @@ be_local_closure(Matter_Fabric_before_remove, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(log), - /* K2 */ be_nested_str_weak(MTR_X3A_X20_X2DFabric_X20_X20_X20_X20fab_X3D_X27_X25s_X27_X20_X28removed_X29), - /* K3 */ be_nested_str_weak(get_fabric_id), - /* K4 */ be_nested_str_weak(copy), - /* K5 */ be_nested_str_weak(reverse), - /* K6 */ be_nested_str_weak(tohex), - /* K7 */ be_const_int(3), + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(_counter_group_data_snd_impl), + /* K1 */ be_nested_str_weak(reset), + /* K2 */ be_nested_str_weak(counter_group_data_snd), + /* K3 */ be_nested_str_weak(_counter_group_ctrl_snd_impl), + /* K4 */ be_nested_str_weak(counter_group_ctrl_snd), + /* K5 */ be_nested_str_weak(val), }), - be_str_weak(before_remove), + be_str_weak(hydrate_post), &be_const_str_solidified, - ( &(const binstruction[16]) { /* code */ - 0xB8060000, // 0000 GETNGBL R1 K0 + ( &(const binstruction[17]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x600C0018, // 0002 GETGBL R3 G24 - 0x58100002, // 0003 LDCONST R4 K2 - 0x8C140103, // 0004 GETMET R5 R0 K3 - 0x7C140200, // 0005 CALL R5 1 - 0x8C140B04, // 0006 GETMET R5 R5 K4 - 0x7C140200, // 0007 CALL R5 1 - 0x8C140B05, // 0008 GETMET R5 R5 K5 - 0x7C140200, // 0009 CALL R5 1 - 0x8C140B06, // 000A GETMET R5 R5 K6 - 0x7C140200, // 000B CALL R5 1 - 0x7C0C0400, // 000C CALL R3 2 - 0x58100007, // 000D LDCONST R4 K7 - 0x7C040600, // 000E CALL R1 3 - 0x80000000, // 000F RET 0 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x7C040400, // 0003 CALL R1 2 + 0x88040103, // 0004 GETMBR R1 R0 K3 + 0x8C040301, // 0005 GETMET R1 R1 K1 + 0x880C0104, // 0006 GETMBR R3 R0 K4 + 0x7C040400, // 0007 CALL R1 2 + 0x88040100, // 0008 GETMBR R1 R0 K0 + 0x8C040305, // 0009 GETMET R1 R1 K5 + 0x7C040200, // 000A CALL R1 1 + 0x90020401, // 000B SETMBR R0 K2 R1 + 0x88040103, // 000C GETMBR R1 R0 K3 + 0x8C040305, // 000D GETMET R1 R1 K5 + 0x7C040200, // 000E CALL R1 1 + 0x90020801, // 000F SETMBR R0 K4 R1 + 0x80000000, // 0010 RET 0 }) ) ); @@ -699,146 +608,279 @@ be_local_closure(Matter_Fabric_before_remove, /* name */ /******************************************************************** -** Solidified function: fromjson +** Solidified function: set_ipk_epoch_key ********************************************************************/ -be_local_closure(Matter_Fabric_fromjson, /* name */ +be_local_closure(Matter_Fabric_set_ipk_epoch_key, /* name */ be_nested_proto( - 16, /* nstack */ + 2, /* nstack */ 2, /* argc */ - 4, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[18]) { /* constants */ - /* K0 */ be_const_class(be_class_Matter_Fabric), - /* K1 */ be_nested_str_weak(string), - /* K2 */ be_nested_str_weak(introspect), - /* K3 */ be_nested_str_weak(matter), - /* K4 */ be_nested_str_weak(Fabric), - /* K5 */ be_nested_str_weak(keys), - /* K6 */ be_const_int(0), - /* K7 */ be_nested_str_weak(_), - /* K8 */ be_nested_str_weak(find), - /* K9 */ be_nested_str_weak(0x), - /* K10 */ be_nested_str_weak(set), - /* K11 */ be_nested_str_weak(fromhex), - /* K12 */ be_const_int(2), - /* K13 */ be_const_int(2147483647), - /* K14 */ be_nested_str_weak(_X24_X24), - /* K15 */ be_nested_str_weak(fromb64), - /* K16 */ be_nested_str_weak(stop_iteration), - /* K17 */ be_nested_str_weak(hydrate_post), - }), - be_str_weak(fromjson), - &be_const_str_solidified, - ( &(const binstruction[76]) { /* code */ - 0x58080000, // 0000 LDCONST R2 K0 - 0xA40E0200, // 0001 IMPORT R3 K1 - 0xA4120400, // 0002 IMPORT R4 K2 - 0xB8160600, // 0003 GETNGBL R5 K3 - 0x8C140B04, // 0004 GETMET R5 R5 K4 - 0x5C1C0000, // 0005 MOVE R7 R0 - 0x7C140400, // 0006 CALL R5 2 - 0x60180010, // 0007 GETGBL R6 G16 - 0x8C1C0305, // 0008 GETMET R7 R1 K5 - 0x7C1C0200, // 0009 CALL R7 1 - 0x7C180200, // 000A CALL R6 1 - 0xA8020039, // 000B EXBLK 0 #0046 - 0x5C1C0C00, // 000C MOVE R7 R6 - 0x7C1C0000, // 000D CALL R7 0 - 0x94200F06, // 000E GETIDX R8 R7 K6 - 0x1C201107, // 000F EQ R8 R8 K7 - 0x78220000, // 0010 JMPF R8 #0012 - 0x7001FFF9, // 0011 JMP #000C - 0x94200207, // 0012 GETIDX R8 R1 R7 - 0x60240004, // 0013 GETGBL R9 G4 - 0x5C281000, // 0014 MOVE R10 R8 - 0x7C240200, // 0015 CALL R9 1 - 0x1C241301, // 0016 EQ R9 R9 K1 - 0x78260027, // 0017 JMPF R9 #0040 - 0x8C240708, // 0018 GETMET R9 R3 K8 - 0x5C2C1000, // 0019 MOVE R11 R8 - 0x58300009, // 001A LDCONST R12 K9 - 0x7C240600, // 001B CALL R9 3 - 0x1C241306, // 001C EQ R9 R9 K6 - 0x7826000A, // 001D JMPF R9 #0029 - 0x8C24090A, // 001E GETMET R9 R4 K10 - 0x5C2C0A00, // 001F MOVE R11 R5 - 0x5C300E00, // 0020 MOVE R12 R7 - 0x60340015, // 0021 GETGBL R13 G21 - 0x7C340000, // 0022 CALL R13 0 - 0x8C341B0B, // 0023 GETMET R13 R13 K11 - 0x403E190D, // 0024 CONNECT R15 K12 K13 - 0x943C100F, // 0025 GETIDX R15 R8 R15 - 0x7C340400, // 0026 CALL R13 2 - 0x7C240800, // 0027 CALL R9 4 - 0x70020015, // 0028 JMP #003F - 0x8C240708, // 0029 GETMET R9 R3 K8 - 0x5C2C1000, // 002A MOVE R11 R8 - 0x5830000E, // 002B LDCONST R12 K14 - 0x7C240600, // 002C CALL R9 3 - 0x1C241306, // 002D EQ R9 R9 K6 - 0x7826000A, // 002E JMPF R9 #003A - 0x8C24090A, // 002F GETMET R9 R4 K10 - 0x5C2C0A00, // 0030 MOVE R11 R5 - 0x5C300E00, // 0031 MOVE R12 R7 - 0x60340015, // 0032 GETGBL R13 G21 - 0x7C340000, // 0033 CALL R13 0 - 0x8C341B0F, // 0034 GETMET R13 R13 K15 - 0x403E190D, // 0035 CONNECT R15 K12 K13 - 0x943C100F, // 0036 GETIDX R15 R8 R15 - 0x7C340400, // 0037 CALL R13 2 - 0x7C240800, // 0038 CALL R9 4 - 0x70020004, // 0039 JMP #003F - 0x8C24090A, // 003A GETMET R9 R4 K10 - 0x5C2C0A00, // 003B MOVE R11 R5 - 0x5C300E00, // 003C MOVE R12 R7 - 0x5C341000, // 003D MOVE R13 R8 - 0x7C240800, // 003E CALL R9 4 - 0x70020004, // 003F JMP #0045 - 0x8C24090A, // 0040 GETMET R9 R4 K10 - 0x5C2C0A00, // 0041 MOVE R11 R5 - 0x5C300E00, // 0042 MOVE R12 R7 - 0x5C341000, // 0043 MOVE R13 R8 - 0x7C240800, // 0044 CALL R9 4 - 0x7001FFC5, // 0045 JMP #000C - 0x58180010, // 0046 LDCONST R6 K16 - 0xAC180200, // 0047 CATCH R6 1 0 - 0xB0080000, // 0048 RAISE 2 R0 R0 - 0x8C180B11, // 0049 GETMET R6 R5 K17 - 0x7C180200, // 004A CALL R6 1 - 0x80040A00, // 004B RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_admin_subject_vendor -********************************************************************/ -be_local_closure(Matter_Fabric_set_admin_subject_vendor, /* name */ - be_nested_proto( - 3, /* nstack */ - 3, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(admin_subject), - /* K1 */ be_nested_str_weak(admin_vendor), + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(ipk_epoch_key), }), - be_str_weak(set_admin_subject_vendor), + be_str_weak(set_ipk_epoch_key), &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_fabric_device +********************************************************************/ +be_local_closure(Matter_Fabric_set_fabric_device, /* name */ + be_nested_proto( + 7, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(fabric_id), + /* K1 */ be_nested_str_weak(device_id), + /* K2 */ be_nested_str_weak(fabric_compressed), + /* K3 */ be_nested_str_weak(fabric_parent), + /* K4 */ be_nested_str_weak(get_fabric_index), + }), + be_str_weak(set_fabric_device), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ 0x90020001, // 0000 SETMBR R0 K0 R1 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x80000000, // 0002 RET 0 + 0x90020403, // 0002 SETMBR R0 K2 R3 + 0x4C140000, // 0003 LDNIL R5 + 0x20140805, // 0004 NE R5 R4 R5 + 0x78160002, // 0005 JMPF R5 #0009 + 0x8C140904, // 0006 GETMET R5 R4 K4 + 0x7C140200, // 0007 CALL R5 1 + 0x70020000, // 0008 JMP #000A + 0x4C140000, // 0009 LDNIL R5 + 0x90020605, // 000A SETMBR R0 K3 R5 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_device_id +********************************************************************/ +be_local_closure(Matter_Fabric_get_device_id, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(device_id), + }), + be_str_weak(get_device_id), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_admin_subject +********************************************************************/ +be_local_closure(Matter_Fabric_get_admin_subject, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(admin_subject), + }), + be_str_weak(get_admin_subject), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: is_marked_for_deletion +********************************************************************/ +be_local_closure(Matter_Fabric_is_marked_for_deletion, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(deleted), + }), + be_str_weak(is_marked_for_deletion), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x20040202, // 0002 NE R1 R1 R2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_fabric_id_as_int64 +********************************************************************/ +be_local_closure(Matter_Fabric_get_fabric_id_as_int64, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(int64), + /* K1 */ be_nested_str_weak(frombytes), + /* K2 */ be_nested_str_weak(fabric_id), + }), + be_str_weak(get_fabric_id_as_int64), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x7C040400, // 0003 CALL R1 2 + 0x80040200, // 0004 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ca +********************************************************************/ +be_local_closure(Matter_Fabric_get_ca, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(root_ca_certificate), + }), + be_str_weak(get_ca), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_oldest_session +********************************************************************/ +be_local_closure(Matter_Fabric_get_oldest_session, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(get_old_recent_session), + }), + be_str_weak(get_oldest_session), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x500C0200, // 0001 LDBOOL R3 1 0 + 0x7C040400, // 0002 CALL R1 2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: fabric_completed +********************************************************************/ +be_local_closure(Matter_Fabric_fabric_completed, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(set_no_expiration), + /* K1 */ be_nested_str_weak(set_persist), + /* K2 */ be_nested_str_weak(assign_fabric_index), + /* K3 */ be_nested_str_weak(_store), + /* K4 */ be_nested_str_weak(add_fabric), + }), + be_str_weak(fabric_completed), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x8C040101, // 0002 GETMET R1 R0 K1 + 0x500C0200, // 0003 LDBOOL R3 1 0 + 0x7C040400, // 0004 CALL R1 2 + 0x8C040102, // 0005 GETMET R1 R0 K2 + 0x7C040200, // 0006 CALL R1 1 + 0x88040103, // 0007 GETMBR R1 R0 K3 + 0x8C040304, // 0008 GETMET R1 R1 K4 + 0x5C0C0000, // 0009 MOVE R3 R0 + 0x7C040400, // 000A CALL R1 2 + 0x80000000, // 000B RET 0 }) ) ); @@ -910,67 +952,28 @@ be_local_closure(Matter_Fabric_counter_group_data_snd_next, /* name */ /******************************************************************** -** Solidified function: get_fabric_compressed +** Solidified function: set_noc_icac ********************************************************************/ -be_local_closure(Matter_Fabric_get_fabric_compressed, /* name */ +be_local_closure(Matter_Fabric_set_noc_icac, /* name */ be_nested_proto( - 2, /* nstack */ - 1, /* argc */ + 3, /* nstack */ + 3, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric_compressed), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(noc), + /* K1 */ be_nested_str_weak(icac), }), - be_str_weak(get_fabric_compressed), + be_str_weak(set_noc_icac), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_fabric_device -********************************************************************/ -be_local_closure(Matter_Fabric_set_fabric_device, /* name */ - be_nested_proto( - 7, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric_id), - /* K1 */ be_nested_str_weak(device_id), - /* K2 */ be_nested_str_weak(fabric_compressed), - /* K3 */ be_nested_str_weak(fabric_parent), - /* K4 */ be_nested_str_weak(get_fabric_index), - }), - be_str_weak(set_fabric_device), - &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ + ( &(const binstruction[ 3]) { /* code */ 0x90020001, // 0000 SETMBR R0 K0 R1 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x90020403, // 0002 SETMBR R0 K2 R3 - 0x4C140000, // 0003 LDNIL R5 - 0x20140805, // 0004 NE R5 R4 R5 - 0x78160002, // 0005 JMPF R5 #0009 - 0x8C140904, // 0006 GETMET R5 R4 K4 - 0x7C140200, // 0007 CALL R5 1 - 0x70020000, // 0008 JMP #000A - 0x4C140000, // 0009 LDNIL R5 - 0x90020605, // 000A SETMBR R0 K3 R5 - 0x80000000, // 000B RET 0 + 0x80000000, // 0002 RET 0 }) ) ); @@ -978,9 +981,9 @@ be_local_closure(Matter_Fabric_set_fabric_device, /* name */ /******************************************************************** -** Solidified function: set_ipk_epoch_key +** Solidified function: set_pk ********************************************************************/ -be_local_closure(Matter_Fabric_set_ipk_epoch_key, /* name */ +be_local_closure(Matter_Fabric_set_pk, /* name */ be_nested_proto( 2, /* nstack */ 2, /* argc */ @@ -991,9 +994,9 @@ be_local_closure(Matter_Fabric_set_ipk_epoch_key, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(ipk_epoch_key), + /* K0 */ be_nested_str_weak(no_private_key), }), - be_str_weak(set_ipk_epoch_key), + be_str_weak(set_pk), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x90020001, // 0000 SETMBR R0 K0 R1 @@ -1005,100 +1008,11 @@ be_local_closure(Matter_Fabric_set_ipk_epoch_key, /* name */ /******************************************************************** -** Solidified function: get_ipk_group_key +** Solidified function: get_newest_session ********************************************************************/ -be_local_closure(Matter_Fabric_get_ipk_group_key, /* name */ +be_local_closure(Matter_Fabric_get_newest_session, /* name */ be_nested_proto( - 10, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_nested_str_weak(ipk_epoch_key), - /* K1 */ be_nested_str_weak(fabric_compressed), - /* K2 */ be_nested_str_weak(crypto), - /* K3 */ be_nested_str_weak(HKDF_SHA256), - /* K4 */ be_nested_str_weak(fromstring), - /* K5 */ be_nested_str_weak(_GROUP_KEY), - /* K6 */ be_nested_str_weak(derive), - }), - be_str_weak(get_ipk_group_key), - &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x4C080000, // 0001 LDNIL R2 - 0x1C040202, // 0002 EQ R1 R1 R2 - 0x74060003, // 0003 JMPT R1 #0008 - 0x88040101, // 0004 GETMBR R1 R0 K1 - 0x4C080000, // 0005 LDNIL R2 - 0x1C040202, // 0006 EQ R1 R1 R2 - 0x78060001, // 0007 JMPF R1 #000A - 0x4C040000, // 0008 LDNIL R1 - 0x80040200, // 0009 RET 1 R1 - 0xA4060400, // 000A IMPORT R1 K2 - 0x8C080303, // 000B GETMET R2 R1 K3 - 0x7C080200, // 000C CALL R2 1 - 0x600C0015, // 000D GETGBL R3 G21 - 0x7C0C0000, // 000E CALL R3 0 - 0x8C0C0704, // 000F GETMET R3 R3 K4 - 0x88140105, // 0010 GETMBR R5 R0 K5 - 0x7C0C0400, // 0011 CALL R3 2 - 0x8C100506, // 0012 GETMET R4 R2 K6 - 0x88180100, // 0013 GETMBR R6 R0 K0 - 0x881C0101, // 0014 GETMBR R7 R0 K1 - 0x5C200600, // 0015 MOVE R8 R3 - 0x5426000F, // 0016 LDINT R9 16 - 0x7C100A00, // 0017 CALL R4 5 - 0x80040800, // 0018 RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_fabric_id_as_int64 -********************************************************************/ -be_local_closure(Matter_Fabric_get_fabric_id_as_int64, /* name */ - be_nested_proto( - 5, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(int64), - /* K1 */ be_nested_str_weak(frombytes), - /* K2 */ be_nested_str_weak(fabric_id), - }), - be_str_weak(get_fabric_id_as_int64), - &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ - 0xB8060000, // 0000 GETNGBL R1 K0 - 0x7C040000, // 0001 CALL R1 0 - 0x8C080301, // 0002 GETMET R2 R1 K1 - 0x88100102, // 0003 GETMBR R4 R0 K2 - 0x7C080400, // 0004 CALL R2 2 - 0x80040200, // 0005 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_admin_vendor -********************************************************************/ -be_local_closure(Matter_Fabric_get_admin_vendor, /* name */ - be_nested_proto( - 2, /* nstack */ + 4, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1107,13 +1021,66 @@ be_local_closure(Matter_Fabric_get_admin_vendor, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(admin_vendor), + /* K0 */ be_nested_str_weak(get_old_recent_session), }), - be_str_weak(get_admin_vendor), + be_str_weak(get_newest_session), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x500C0000, // 0001 LDBOOL R3 0 0 + 0x7C040400, // 0002 CALL R1 2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: log_new_fabric +********************************************************************/ +be_local_closure(Matter_Fabric_log_new_fabric, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(log), + /* K2 */ be_nested_str_weak(MTR_X3A_X20_X2BFabric_X20_X20_X20_X20fab_X3D_X27_X25s_X27_X20vendorid_X3D_X25s), + /* K3 */ be_nested_str_weak(get_fabric_id), + /* K4 */ be_nested_str_weak(copy), + /* K5 */ be_nested_str_weak(reverse), + /* K6 */ be_nested_str_weak(tohex), + /* K7 */ be_nested_str_weak(get_admin_vendor_name), + /* K8 */ be_const_int(3), + }), + be_str_weak(log_new_fabric), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x600C0018, // 0002 GETGBL R3 G24 + 0x58100002, // 0003 LDCONST R4 K2 + 0x8C140103, // 0004 GETMET R5 R0 K3 + 0x7C140200, // 0005 CALL R5 1 + 0x8C140B04, // 0006 GETMET R5 R5 K4 + 0x7C140200, // 0007 CALL R5 1 + 0x8C140B05, // 0008 GETMET R5 R5 K5 + 0x7C140200, // 0009 CALL R5 1 + 0x8C140B06, // 000A GETMET R5 R5 K6 + 0x7C140200, // 000B CALL R5 1 + 0x8C180107, // 000C GETMET R6 R0 K7 + 0x7C180200, // 000D CALL R6 1 + 0x7C0C0600, // 000E CALL R3 3 + 0x58100008, // 000F LDCONST R4 K8 + 0x7C040600, // 0010 CALL R1 3 + 0x80000000, // 0011 RET 0 }) ) ); @@ -1162,11 +1129,11 @@ be_local_closure(Matter_Fabric_get_ca_pub, /* name */ /******************************************************************** -** Solidified function: is_marked_for_deletion +** Solidified function: get_fabric_index ********************************************************************/ -be_local_closure(Matter_Fabric_is_marked_for_deletion, /* name */ +be_local_closure(Matter_Fabric_get_fabric_index, /* name */ be_nested_proto( - 3, /* nstack */ + 2, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1175,15 +1142,387 @@ be_local_closure(Matter_Fabric_is_marked_for_deletion, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(deleted), + /* K0 */ be_nested_str_weak(fabric_index), }), - be_str_weak(is_marked_for_deletion), + be_str_weak(get_fabric_index), &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ + ( &(const binstruction[ 2]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x4C080000, // 0001 LDNIL R2 - 0x20040202, // 0002 NE R1 R1 R2 - 0x80040200, // 0003 RET 1 R1 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: writejson +********************************************************************/ +be_local_closure(Matter_Fabric_writejson, /* name */ + be_nested_proto( + 17, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[26]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(introspect), + /* K2 */ be_nested_str_weak(write), + /* K3 */ be_nested_str_weak(_X7B), + /* K4 */ be_nested_str_weak(persist_pre), + /* K5 */ be_nested_str_weak(members), + /* K6 */ be_nested_str_weak(get), + /* K7 */ be_nested_str_weak(function), + /* K8 */ be_const_int(0), + /* K9 */ be_nested_str_weak(_), + /* K10 */ be_nested_str_weak(push), + /* K11 */ be_nested_str_weak(stop_iteration), + /* K12 */ be_nested_str_weak(matter), + /* K13 */ be_nested_str_weak(sort), + /* K14 */ be_nested_str_weak(_X24_X24), + /* K15 */ be_nested_str_weak(tob64), + /* K16 */ be_nested_str_weak(_X2C), + /* K17 */ be_nested_str_weak(_X25s_X3A_X25s), + /* K18 */ be_nested_str_weak(dump), + /* K19 */ be_nested_str_weak(_sessions), + /* K20 */ be_nested_str_weak(persistables), + /* K21 */ be_nested_str_weak(_X2C_X22_sessions_X22_X3A_X5B), + /* K22 */ be_nested_str_weak(tojson), + /* K23 */ be_nested_str_weak(_X5D), + /* K24 */ be_nested_str_weak(persist_post), + /* K25 */ be_nested_str_weak(_X7D), + }), + be_str_weak(writejson), + &be_const_str_solidified, + ( &(const binstruction[125]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0x8C100302, // 0002 GETMET R4 R1 K2 + 0x58180003, // 0003 LDCONST R6 K3 + 0x7C100400, // 0004 CALL R4 2 + 0x8C100104, // 0005 GETMET R4 R0 K4 + 0x7C100200, // 0006 CALL R4 1 + 0x60100012, // 0007 GETGBL R4 G18 + 0x7C100000, // 0008 CALL R4 0 + 0x60140010, // 0009 GETGBL R5 G16 + 0x8C180705, // 000A GETMET R6 R3 K5 + 0x5C200000, // 000B MOVE R8 R0 + 0x7C180400, // 000C CALL R6 2 + 0x7C140200, // 000D CALL R5 1 + 0xA8020011, // 000E EXBLK 0 #0021 + 0x5C180A00, // 000F MOVE R6 R5 + 0x7C180000, // 0010 CALL R6 0 + 0x8C1C0706, // 0011 GETMET R7 R3 K6 + 0x5C240000, // 0012 MOVE R9 R0 + 0x5C280C00, // 0013 MOVE R10 R6 + 0x7C1C0600, // 0014 CALL R7 3 + 0x60200004, // 0015 GETGBL R8 G4 + 0x5C240E00, // 0016 MOVE R9 R7 + 0x7C200200, // 0017 CALL R8 1 + 0x20201107, // 0018 NE R8 R8 K7 + 0x78220005, // 0019 JMPF R8 #0020 + 0x94200D08, // 001A GETIDX R8 R6 K8 + 0x20201109, // 001B NE R8 R8 K9 + 0x78220002, // 001C JMPF R8 #0020 + 0x8C20090A, // 001D GETMET R8 R4 K10 + 0x5C280C00, // 001E MOVE R10 R6 + 0x7C200400, // 001F CALL R8 2 + 0x7001FFED, // 0020 JMP #000F + 0x5814000B, // 0021 LDCONST R5 K11 + 0xAC140200, // 0022 CATCH R5 1 0 + 0xB0080000, // 0023 RAISE 2 R0 R0 + 0xB8161800, // 0024 GETNGBL R5 K12 + 0x8C140B0D, // 0025 GETMET R5 R5 K13 + 0x5C1C0800, // 0026 MOVE R7 R4 + 0x7C140400, // 0027 CALL R5 2 + 0x5C100A00, // 0028 MOVE R4 R5 + 0x50140200, // 0029 LDBOOL R5 1 0 + 0x60180010, // 002A GETGBL R6 G16 + 0x5C1C0800, // 002B MOVE R7 R4 + 0x7C180200, // 002C CALL R6 1 + 0xA8020026, // 002D EXBLK 0 #0055 + 0x5C1C0C00, // 002E MOVE R7 R6 + 0x7C1C0000, // 002F CALL R7 0 + 0x8C200706, // 0030 GETMET R8 R3 K6 + 0x5C280000, // 0031 MOVE R10 R0 + 0x5C2C0E00, // 0032 MOVE R11 R7 + 0x7C200600, // 0033 CALL R8 3 + 0x4C240000, // 0034 LDNIL R9 + 0x1C241009, // 0035 EQ R9 R8 R9 + 0x78260000, // 0036 JMPF R9 #0038 + 0x7001FFF5, // 0037 JMP #002E + 0x6024000F, // 0038 GETGBL R9 G15 + 0x5C281000, // 0039 MOVE R10 R8 + 0x602C0015, // 003A GETGBL R11 G21 + 0x7C240400, // 003B CALL R9 2 + 0x78260003, // 003C JMPF R9 #0041 + 0x8C24110F, // 003D GETMET R9 R8 K15 + 0x7C240200, // 003E CALL R9 1 + 0x00261C09, // 003F ADD R9 K14 R9 + 0x5C201200, // 0040 MOVE R8 R9 + 0x5C240A00, // 0041 MOVE R9 R5 + 0x74260002, // 0042 JMPT R9 #0046 + 0x8C240302, // 0043 GETMET R9 R1 K2 + 0x582C0010, // 0044 LDCONST R11 K16 + 0x7C240400, // 0045 CALL R9 2 + 0x8C240302, // 0046 GETMET R9 R1 K2 + 0x602C0018, // 0047 GETGBL R11 G24 + 0x58300011, // 0048 LDCONST R12 K17 + 0x8C340512, // 0049 GETMET R13 R2 K18 + 0x603C0008, // 004A GETGBL R15 G8 + 0x5C400E00, // 004B MOVE R16 R7 + 0x7C3C0200, // 004C CALL R15 1 + 0x7C340400, // 004D CALL R13 2 + 0x8C380512, // 004E GETMET R14 R2 K18 + 0x5C401000, // 004F MOVE R16 R8 + 0x7C380400, // 0050 CALL R14 2 + 0x7C2C0600, // 0051 CALL R11 3 + 0x7C240400, // 0052 CALL R9 2 + 0x50140000, // 0053 LDBOOL R5 0 0 + 0x7001FFD8, // 0054 JMP #002E + 0x5818000B, // 0055 LDCONST R6 K11 + 0xAC180200, // 0056 CATCH R6 1 0 + 0xB0080000, // 0057 RAISE 2 R0 R0 + 0x50180200, // 0058 LDBOOL R6 1 0 + 0x601C0010, // 0059 GETGBL R7 G16 + 0x88200113, // 005A GETMBR R8 R0 K19 + 0x8C201114, // 005B GETMET R8 R8 K20 + 0x7C200200, // 005C CALL R8 1 + 0x7C1C0200, // 005D CALL R7 1 + 0xA802000F, // 005E EXBLK 0 #006F + 0x5C200E00, // 005F MOVE R8 R7 + 0x7C200000, // 0060 CALL R8 0 + 0x781A0003, // 0061 JMPF R6 #0066 + 0x8C240302, // 0062 GETMET R9 R1 K2 + 0x582C0015, // 0063 LDCONST R11 K21 + 0x7C240400, // 0064 CALL R9 2 + 0x70020002, // 0065 JMP #0069 + 0x8C240302, // 0066 GETMET R9 R1 K2 + 0x582C0010, // 0067 LDCONST R11 K16 + 0x7C240400, // 0068 CALL R9 2 + 0x8C240302, // 0069 GETMET R9 R1 K2 + 0x8C2C1116, // 006A GETMET R11 R8 K22 + 0x7C2C0200, // 006B CALL R11 1 + 0x7C240400, // 006C CALL R9 2 + 0x50180000, // 006D LDBOOL R6 0 0 + 0x7001FFEF, // 006E JMP #005F + 0x581C000B, // 006F LDCONST R7 K11 + 0xAC1C0200, // 0070 CATCH R7 1 0 + 0xB0080000, // 0071 RAISE 2 R0 R0 + 0x5C1C0C00, // 0072 MOVE R7 R6 + 0x741E0002, // 0073 JMPT R7 #0077 + 0x8C1C0302, // 0074 GETMET R7 R1 K2 + 0x58240017, // 0075 LDCONST R9 K23 + 0x7C1C0400, // 0076 CALL R7 2 + 0x8C1C0118, // 0077 GETMET R7 R0 K24 + 0x7C1C0200, // 0078 CALL R7 1 + 0x8C1C0302, // 0079 GETMET R7 R1 K2 + 0x58240019, // 007A LDCONST R9 K25 + 0x7C1C0400, // 007B CALL R7 2 + 0x80000000, // 007C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: counter_group_ctrl_snd_next +********************************************************************/ +be_local_closure(Matter_Fabric_counter_group_ctrl_snd_next, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(_counter_group_ctrl_snd_impl), + /* K1 */ be_nested_str_weak(next), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(log), + /* K4 */ be_nested_str_weak(MTR_X3A_X20_X2E_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20Counter_group_ctrl_snd_X3D_X25i), + /* K5 */ be_const_int(3), + /* K6 */ be_nested_str_weak(matter), + /* K7 */ be_nested_str_weak(Counter), + /* K8 */ be_nested_str_weak(is_greater), + /* K9 */ be_nested_str_weak(counter_group_ctrl_snd), + /* K10 */ be_nested_str_weak(_GROUP_SND_INCR), + /* K11 */ be_nested_str_weak(does_persist), + /* K12 */ be_nested_str_weak(save), + }), + be_str_weak(counter_group_ctrl_snd_next), + &be_const_str_solidified, + ( &(const binstruction[27]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0xB80A0400, // 0003 GETNGBL R2 K2 + 0x8C080503, // 0004 GETMET R2 R2 K3 + 0x60100018, // 0005 GETGBL R4 G24 + 0x58140004, // 0006 LDCONST R5 K4 + 0x5C180200, // 0007 MOVE R6 R1 + 0x7C100400, // 0008 CALL R4 2 + 0x58140005, // 0009 LDCONST R5 K5 + 0x7C080600, // 000A CALL R2 3 + 0xB80A0C00, // 000B GETNGBL R2 K6 + 0x88080507, // 000C GETMBR R2 R2 K7 + 0x8C080508, // 000D GETMET R2 R2 K8 + 0x5C100200, // 000E MOVE R4 R1 + 0x88140109, // 000F GETMBR R5 R0 K9 + 0x7C080600, // 0010 CALL R2 3 + 0x780A0007, // 0011 JMPF R2 #001A + 0x8808010A, // 0012 GETMBR R2 R0 K10 + 0x00080202, // 0013 ADD R2 R1 R2 + 0x90021202, // 0014 SETMBR R0 K9 R2 + 0x8C08010B, // 0015 GETMET R2 R0 K11 + 0x7C080200, // 0016 CALL R2 1 + 0x780A0001, // 0017 JMPF R2 #001A + 0x8C08010C, // 0018 GETMET R2 R0 K12 + 0x7C080200, // 0019 CALL R2 1 + 0x80040200, // 001A RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: fabric_candidate +********************************************************************/ +be_local_closure(Matter_Fabric_fabric_candidate, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(set_expire_in_seconds), + /* K1 */ be_nested_str_weak(assign_fabric_index), + /* K2 */ be_nested_str_weak(_store), + /* K3 */ be_nested_str_weak(add_fabric), + }), + be_str_weak(fabric_candidate), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0077, // 0001 LDINT R3 120 + 0x7C040400, // 0002 CALL R1 2 + 0x8C040101, // 0003 GETMET R1 R0 K1 + 0x7C040200, // 0004 CALL R1 1 + 0x88040102, // 0005 GETMBR R1 R0 K2 + 0x8C040303, // 0006 GETMET R1 R1 K3 + 0x5C0C0000, // 0007 MOVE R3 R0 + 0x7C040400, // 0008 CALL R1 2 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: assign_fabric_index +********************************************************************/ +be_local_closure(Matter_Fabric_assign_fabric_index, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(get_fabric_index), + /* K1 */ be_nested_str_weak(set_fabric_index), + /* K2 */ be_nested_str_weak(_store), + /* K3 */ be_nested_str_weak(next_fabric_idx), + }), + be_str_weak(assign_fabric_index), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x4C080000, // 0002 LDNIL R2 + 0x1C040202, // 0003 EQ R1 R1 R2 + 0x78060004, // 0004 JMPF R1 #000A + 0x8C040101, // 0005 GETMET R1 R0 K1 + 0x880C0102, // 0006 GETMBR R3 R0 K2 + 0x8C0C0703, // 0007 GETMET R3 R3 K3 + 0x7C0C0200, // 0008 CALL R3 1 + 0x7C040400, // 0009 CALL R1 2 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_old_recent_session +********************************************************************/ +be_local_closure(Matter_Fabric_get_old_recent_session, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(_sessions), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(last_used), + /* K3 */ be_const_int(1), + }), + be_str_weak(get_old_recent_session), + &be_const_str_solidified, + ( &(const binstruction[30]) { /* code */ + 0x6008000C, // 0000 GETGBL R2 G12 + 0x880C0100, // 0001 GETMBR R3 R0 K0 + 0x7C080200, // 0002 CALL R2 1 + 0x1C080501, // 0003 EQ R2 R2 K1 + 0x780A0001, // 0004 JMPF R2 #0007 + 0x4C080000, // 0005 LDNIL R2 + 0x80040400, // 0006 RET 1 R2 + 0x88080100, // 0007 GETMBR R2 R0 K0 + 0x94080501, // 0008 GETIDX R2 R2 K1 + 0x880C0502, // 0009 GETMBR R3 R2 K2 + 0x58100003, // 000A LDCONST R4 K3 + 0x6014000C, // 000B GETGBL R5 G12 + 0x88180100, // 000C GETMBR R6 R0 K0 + 0x7C140200, // 000D CALL R5 1 + 0x14140805, // 000E LT R5 R4 R5 + 0x7816000C, // 000F JMPF R5 #001D + 0x88140100, // 0010 GETMBR R5 R0 K0 + 0x94140A04, // 0011 GETIDX R5 R5 R4 + 0x88140B02, // 0012 GETMBR R5 R5 K2 + 0x78060001, // 0013 JMPF R1 #0016 + 0x14180A03, // 0014 LT R6 R5 R3 + 0x70020000, // 0015 JMP #0017 + 0x24180A03, // 0016 GT R6 R5 R3 + 0x781A0002, // 0017 JMPF R6 #001B + 0x88180100, // 0018 GETMBR R6 R0 K0 + 0x94080C04, // 0019 GETIDX R2 R6 R4 + 0x5C0C0A00, // 001A MOVE R3 R5 + 0x00100903, // 001B ADD R4 R4 K3 + 0x7001FFED, // 001C JMP #000B + 0x80040400, // 001D RET 1 R2 }) ) ); @@ -1264,28 +1603,26 @@ be_local_closure(Matter_Fabric_init, /* name */ /******************************************************************** -** Solidified function: set_noc_icac +** Solidified function: get_ipk_epoch_key ********************************************************************/ -be_local_closure(Matter_Fabric_set_noc_icac, /* name */ +be_local_closure(Matter_Fabric_get_ipk_epoch_key, /* name */ be_nested_proto( - 3, /* nstack */ - 3, /* argc */ + 2, /* nstack */ + 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(noc), - /* K1 */ be_nested_str_weak(icac), + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(ipk_epoch_key), }), - be_str_weak(set_noc_icac), + be_str_weak(get_ipk_epoch_key), &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x80000000, // 0002 RET 0 + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 }) ) ); @@ -1293,9 +1630,73 @@ be_local_closure(Matter_Fabric_set_noc_icac, /* name */ /******************************************************************** -** Solidified function: set_ca +** Solidified function: add_session ********************************************************************/ -be_local_closure(Matter_Fabric_set_ca, /* name */ +be_local_closure(Matter_Fabric_add_session, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(_sessions), + /* K1 */ be_nested_str_weak(find), + /* K2 */ be_nested_str_weak(_MAX_CASE), + /* K3 */ be_nested_str_weak(get_oldest_session), + /* K4 */ be_nested_str_weak(remove), + /* K5 */ be_nested_str_weak(_store), + /* K6 */ be_nested_str_weak(remove_session), + /* K7 */ be_nested_str_weak(push), + }), + be_str_weak(add_session), + &be_const_str_solidified, + ( &(const binstruction[32]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C080400, // 0003 CALL R2 2 + 0x4C0C0000, // 0004 LDNIL R3 + 0x1C080403, // 0005 EQ R2 R2 R3 + 0x780A0017, // 0006 JMPF R2 #001F + 0x6008000C, // 0007 GETGBL R2 G12 + 0x880C0100, // 0008 GETMBR R3 R0 K0 + 0x7C080200, // 0009 CALL R2 1 + 0x880C0102, // 000A GETMBR R3 R0 K2 + 0x28080403, // 000B GE R2 R2 R3 + 0x780A000D, // 000C JMPF R2 #001B + 0x8C080103, // 000D GETMET R2 R0 K3 + 0x7C080200, // 000E CALL R2 1 + 0x880C0100, // 000F GETMBR R3 R0 K0 + 0x8C0C0704, // 0010 GETMET R3 R3 K4 + 0x88140100, // 0011 GETMBR R5 R0 K0 + 0x8C140B01, // 0012 GETMET R5 R5 K1 + 0x5C1C0400, // 0013 MOVE R7 R2 + 0x7C140400, // 0014 CALL R5 2 + 0x7C0C0400, // 0015 CALL R3 2 + 0x880C0105, // 0016 GETMBR R3 R0 K5 + 0x8C0C0706, // 0017 GETMET R3 R3 K6 + 0x5C140400, // 0018 MOVE R5 R2 + 0x7C0C0400, // 0019 CALL R3 2 + 0x7001FFEB, // 001A JMP #0007 + 0x88080100, // 001B GETMBR R2 R0 K0 + 0x8C080507, // 001C GETMET R2 R2 K7 + 0x5C100200, // 001D MOVE R4 R1 + 0x7C080400, // 001E CALL R2 2 + 0x80000000, // 001F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_fabric_index +********************************************************************/ +be_local_closure(Matter_Fabric_set_fabric_index, /* name */ be_nested_proto( 2, /* nstack */ 2, /* argc */ @@ -1306,9 +1707,9 @@ be_local_closure(Matter_Fabric_set_ca, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(root_ca_certificate), + /* K0 */ be_nested_str_weak(fabric_index), }), - be_str_weak(set_ca), + be_str_weak(set_fabric_index), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x90020001, // 0000 SETMBR R0 K0 R1 @@ -1319,6 +1720,153 @@ be_local_closure(Matter_Fabric_set_ca, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: get_device_id_as_int64 +********************************************************************/ +be_local_closure(Matter_Fabric_get_device_id_as_int64, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(int64), + /* K1 */ be_nested_str_weak(frombytes), + /* K2 */ be_nested_str_weak(device_id), + }), + be_str_weak(get_device_id_as_int64), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x7C040400, // 0003 CALL R1 2 + 0x80040200, // 0004 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_fabric_label +********************************************************************/ +be_local_closure(Matter_Fabric_get_fabric_label, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(fabric_label), + }), + be_str_weak(get_fabric_label), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ipk_group_key +********************************************************************/ +be_local_closure(Matter_Fabric_get_ipk_group_key, /* name */ + be_nested_proto( + 10, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(ipk_epoch_key), + /* K1 */ be_nested_str_weak(fabric_compressed), + /* K2 */ be_nested_str_weak(crypto), + /* K3 */ be_nested_str_weak(HKDF_SHA256), + /* K4 */ be_nested_str_weak(fromstring), + /* K5 */ be_nested_str_weak(_GROUP_KEY), + /* K6 */ be_nested_str_weak(derive), + }), + be_str_weak(get_ipk_group_key), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x74060003, // 0003 JMPT R1 #0008 + 0x88040101, // 0004 GETMBR R1 R0 K1 + 0x4C080000, // 0005 LDNIL R2 + 0x1C040202, // 0006 EQ R1 R1 R2 + 0x78060001, // 0007 JMPF R1 #000A + 0x4C040000, // 0008 LDNIL R1 + 0x80040200, // 0009 RET 1 R1 + 0xA4060400, // 000A IMPORT R1 K2 + 0x8C080303, // 000B GETMET R2 R1 K3 + 0x7C080200, // 000C CALL R2 1 + 0x600C0015, // 000D GETGBL R3 G21 + 0x7C0C0000, // 000E CALL R3 0 + 0x8C0C0704, // 000F GETMET R3 R3 K4 + 0x88140105, // 0010 GETMBR R5 R0 K5 + 0x7C0C0400, // 0011 CALL R3 2 + 0x8C100506, // 0012 GETMET R4 R2 K6 + 0x88180100, // 0013 GETMBR R6 R0 K0 + 0x881C0101, // 0014 GETMBR R7 R0 K1 + 0x5C200600, // 0015 MOVE R8 R3 + 0x5426000F, // 0016 LDINT R9 16 + 0x7C100A00, // 0017 CALL R4 5 + 0x80040800, // 0018 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: mark_for_deletion +********************************************************************/ +be_local_closure(Matter_Fabric_mark_for_deletion, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(deleted), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(rtc_utc), + }), + be_str_weak(mark_for_deletion), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0xB8060200, // 0000 GETNGBL R1 K1 + 0x8C040302, // 0001 GETMET R1 R1 K2 + 0x7C040200, // 0002 CALL R1 1 + 0x90020001, // 0003 SETMBR R0 K0 R1 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: get_admin_vendor_name ********************************************************************/ @@ -1368,381 +1916,6 @@ be_local_closure(Matter_Fabric_get_admin_vendor_name, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: assign_fabric_index -********************************************************************/ -be_local_closure(Matter_Fabric_assign_fabric_index, /* name */ - be_nested_proto( - 5, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(get_fabric_index), - /* K1 */ be_nested_str_weak(set_fabric_index), - /* K2 */ be_nested_str_weak(_store), - /* K3 */ be_nested_str_weak(next_fabric_idx), - }), - be_str_weak(assign_fabric_index), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x7C040200, // 0001 CALL R1 1 - 0x4C080000, // 0002 LDNIL R2 - 0x1C040202, // 0003 EQ R1 R1 R2 - 0x78060004, // 0004 JMPF R1 #000A - 0x8C040101, // 0005 GETMET R1 R0 K1 - 0x880C0102, // 0006 GETMBR R3 R0 K2 - 0x8C0C0703, // 0007 GETMET R3 R3 K3 - 0x7C0C0200, // 0008 CALL R3 1 - 0x7C040400, // 0009 CALL R1 2 - 0x80000000, // 000A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_admin_subject -********************************************************************/ -be_local_closure(Matter_Fabric_get_admin_subject, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(admin_subject), - }), - be_str_weak(get_admin_subject), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_fabric_label -********************************************************************/ -be_local_closure(Matter_Fabric_get_fabric_label, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric_label), - }), - be_str_weak(get_fabric_label), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_old_recent_session -********************************************************************/ -be_local_closure(Matter_Fabric_get_old_recent_session, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(_sessions), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str_weak(last_used), - /* K3 */ be_const_int(1), - }), - be_str_weak(get_old_recent_session), - &be_const_str_solidified, - ( &(const binstruction[30]) { /* code */ - 0x6008000C, // 0000 GETGBL R2 G12 - 0x880C0100, // 0001 GETMBR R3 R0 K0 - 0x7C080200, // 0002 CALL R2 1 - 0x1C080501, // 0003 EQ R2 R2 K1 - 0x780A0001, // 0004 JMPF R2 #0007 - 0x4C080000, // 0005 LDNIL R2 - 0x80040400, // 0006 RET 1 R2 - 0x88080100, // 0007 GETMBR R2 R0 K0 - 0x94080501, // 0008 GETIDX R2 R2 K1 - 0x880C0502, // 0009 GETMBR R3 R2 K2 - 0x58100003, // 000A LDCONST R4 K3 - 0x6014000C, // 000B GETGBL R5 G12 - 0x88180100, // 000C GETMBR R6 R0 K0 - 0x7C140200, // 000D CALL R5 1 - 0x14140805, // 000E LT R5 R4 R5 - 0x7816000C, // 000F JMPF R5 #001D - 0x88140100, // 0010 GETMBR R5 R0 K0 - 0x94140A04, // 0011 GETIDX R5 R5 R4 - 0x88140B02, // 0012 GETMBR R5 R5 K2 - 0x78060001, // 0013 JMPF R1 #0016 - 0x14180A03, // 0014 LT R6 R5 R3 - 0x70020000, // 0015 JMP #0017 - 0x24180A03, // 0016 GT R6 R5 R3 - 0x781A0002, // 0017 JMPF R6 #001B - 0x88180100, // 0018 GETMBR R6 R0 K0 - 0x94080C04, // 0019 GETIDX R2 R6 R4 - 0x5C0C0A00, // 001A MOVE R3 R5 - 0x00100903, // 001B ADD R4 R4 K3 - 0x7001FFED, // 001C JMP #000B - 0x80040400, // 001D RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ca -********************************************************************/ -be_local_closure(Matter_Fabric_get_ca, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(root_ca_certificate), - }), - be_str_weak(get_ca), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: mark_for_deletion -********************************************************************/ -be_local_closure(Matter_Fabric_mark_for_deletion, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(deleted), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(rtc_utc), - }), - be_str_weak(mark_for_deletion), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0xB8060200, // 0000 GETNGBL R1 K1 - 0x8C040302, // 0001 GETMET R1 R1 K2 - 0x7C040200, // 0002 CALL R1 1 - 0x90020001, // 0003 SETMBR R0 K0 R1 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_fabric_index -********************************************************************/ -be_local_closure(Matter_Fabric_get_fabric_index, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric_index), - }), - be_str_weak(get_fabric_index), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_fabric_id -********************************************************************/ -be_local_closure(Matter_Fabric_get_fabric_id, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric_id), - }), - be_str_weak(get_fabric_id), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: hydrate_post -********************************************************************/ -be_local_closure(Matter_Fabric_hydrate_post, /* name */ - be_nested_proto( - 4, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(_counter_group_data_snd_impl), - /* K1 */ be_nested_str_weak(reset), - /* K2 */ be_nested_str_weak(counter_group_data_snd), - /* K3 */ be_nested_str_weak(_counter_group_ctrl_snd_impl), - /* K4 */ be_nested_str_weak(counter_group_ctrl_snd), - /* K5 */ be_nested_str_weak(val), - }), - be_str_weak(hydrate_post), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x880C0102, // 0002 GETMBR R3 R0 K2 - 0x7C040400, // 0003 CALL R1 2 - 0x88040103, // 0004 GETMBR R1 R0 K3 - 0x8C040301, // 0005 GETMET R1 R1 K1 - 0x880C0104, // 0006 GETMBR R3 R0 K4 - 0x7C040400, // 0007 CALL R1 2 - 0x88040100, // 0008 GETMBR R1 R0 K0 - 0x8C040305, // 0009 GETMET R1 R1 K5 - 0x7C040200, // 000A CALL R1 1 - 0x90020401, // 000B SETMBR R0 K2 R1 - 0x88040103, // 000C GETMBR R1 R0 K3 - 0x8C040305, // 000D GETMET R1 R1 K5 - 0x7C040200, // 000E CALL R1 1 - 0x90020801, // 000F SETMBR R0 K4 R1 - 0x80000000, // 0010 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: counter_group_ctrl_snd_next -********************************************************************/ -be_local_closure(Matter_Fabric_counter_group_ctrl_snd_next, /* name */ - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[13]) { /* constants */ - /* K0 */ be_nested_str_weak(_counter_group_ctrl_snd_impl), - /* K1 */ be_nested_str_weak(next), - /* K2 */ be_nested_str_weak(tasmota), - /* K3 */ be_nested_str_weak(log), - /* K4 */ be_nested_str_weak(MTR_X3A_X20_X2E_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20Counter_group_ctrl_snd_X3D_X25i), - /* K5 */ be_const_int(3), - /* K6 */ be_nested_str_weak(matter), - /* K7 */ be_nested_str_weak(Counter), - /* K8 */ be_nested_str_weak(is_greater), - /* K9 */ be_nested_str_weak(counter_group_ctrl_snd), - /* K10 */ be_nested_str_weak(_GROUP_SND_INCR), - /* K11 */ be_nested_str_weak(does_persist), - /* K12 */ be_nested_str_weak(save), - }), - be_str_weak(counter_group_ctrl_snd_next), - &be_const_str_solidified, - ( &(const binstruction[27]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x7C040200, // 0002 CALL R1 1 - 0xB80A0400, // 0003 GETNGBL R2 K2 - 0x8C080503, // 0004 GETMET R2 R2 K3 - 0x60100018, // 0005 GETGBL R4 G24 - 0x58140004, // 0006 LDCONST R5 K4 - 0x5C180200, // 0007 MOVE R6 R1 - 0x7C100400, // 0008 CALL R4 2 - 0x58140005, // 0009 LDCONST R5 K5 - 0x7C080600, // 000A CALL R2 3 - 0xB80A0C00, // 000B GETNGBL R2 K6 - 0x88080507, // 000C GETMBR R2 R2 K7 - 0x8C080508, // 000D GETMET R2 R2 K8 - 0x5C100200, // 000E MOVE R4 R1 - 0x88140109, // 000F GETMBR R5 R0 K9 - 0x7C080600, // 0010 CALL R2 3 - 0x780A0007, // 0011 JMPF R2 #001A - 0x8808010A, // 0012 GETMBR R2 R0 K10 - 0x00080202, // 0013 ADD R2 R1 R2 - 0x90021202, // 0014 SETMBR R0 K9 R2 - 0x8C08010B, // 0015 GETMET R2 R0 K11 - 0x7C080200, // 0016 CALL R2 1 - 0x780A0001, // 0017 JMPF R2 #001A - 0x8C08010C, // 0018 GETMET R2 R0 K12 - 0x7C080200, // 0019 CALL R2 1 - 0x80040200, // 001A RET 1 R1 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Matter_Fabric ********************************************************************/ @@ -1750,73 +1923,74 @@ extern const bclass be_class_Matter_Expirable; be_local_class(Matter_Fabric, 21, &be_class_Matter_Expirable, - be_nested_map(65, + be_nested_map(66, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(get_device_id_as_int64, -1), be_const_closure(Matter_Fabric_get_device_id_as_int64_closure) }, - { be_const_key_weak(admin_vendor, -1), be_const_var(20) }, - { be_const_key_weak(counter_group_ctrl_snd_next, -1), be_const_closure(Matter_Fabric_counter_group_ctrl_snd_next_closure) }, - { be_const_key_weak(hydrate_post, 12), be_const_closure(Matter_Fabric_hydrate_post_closure) }, - { be_const_key_weak(admin_subject, 63), be_const_var(19) }, - { be_const_key_weak(fabric_compressed, 36), be_const_var(12) }, - { be_const_key_weak(noc, -1), be_const_var(8) }, - { be_const_key_weak(add_session, -1), be_const_closure(Matter_Fabric_add_session_closure) }, - { be_const_key_weak(get_oldest_session, 22), be_const_closure(Matter_Fabric_get_oldest_session_closure) }, - { be_const_key_weak(get_ipk_epoch_key, -1), be_const_closure(Matter_Fabric_get_ipk_epoch_key_closure) }, - { be_const_key_weak(log_new_fabric, -1), be_const_closure(Matter_Fabric_log_new_fabric_closure) }, - { be_const_key_weak(fromjson, 64), be_const_static_closure(Matter_Fabric_fromjson_closure) }, - { be_const_key_weak(get_fabric_index, -1), be_const_closure(Matter_Fabric_get_fabric_index_closure) }, { be_const_key_weak(get_icac, -1), be_const_closure(Matter_Fabric_get_icac_closure) }, - { be_const_key_weak(set_fabric_index, -1), be_const_closure(Matter_Fabric_set_fabric_index_closure) }, - { be_const_key_weak(counter_group_ctrl_snd, -1), be_const_var(16) }, - { be_const_key_weak(get_noc, 4), be_const_closure(Matter_Fabric_get_noc_closure) }, - { be_const_key_weak(_counter_group_data_snd_impl, -1), be_const_var(17) }, - { be_const_key_weak(fabric_completed, -1), be_const_closure(Matter_Fabric_fabric_completed_closure) }, - { be_const_key_weak(_sessions, -1), be_const_var(5) }, - { be_const_key_weak(get_pk, -1), be_const_closure(Matter_Fabric_get_pk_closure) }, - { be_const_key_weak(mark_for_deletion, -1), be_const_closure(Matter_Fabric_mark_for_deletion_closure) }, - { be_const_key_weak(_store, 47), be_const_var(0) }, - { be_const_key_weak(get_newest_session, 58), be_const_closure(Matter_Fabric_get_newest_session_closure) }, + { be_const_key_weak(_counter_group_ctrl_snd_impl, 2), be_const_var(18) }, { be_const_key_weak(get_fabric_compressed, -1), be_const_closure(Matter_Fabric_get_fabric_compressed_closure) }, - { be_const_key_weak(before_remove, -1), be_const_closure(Matter_Fabric_before_remove_closure) }, - { be_const_key_weak(set_pk, 11), be_const_closure(Matter_Fabric_set_pk_closure) }, - { be_const_key_weak(root_ca_certificate, 37), be_const_var(7) }, - { be_const_key_weak(set_admin_subject_vendor, 29), be_const_closure(Matter_Fabric_set_admin_subject_vendor_closure) }, - { be_const_key_weak(get_old_recent_session, 42), be_const_closure(Matter_Fabric_get_old_recent_session_closure) }, - { be_const_key_weak(get_fabric_label, 10), be_const_closure(Matter_Fabric_get_fabric_label_closure) }, - { be_const_key_weak(tojson, 57), be_const_closure(Matter_Fabric_tojson_closure) }, - { be_const_key_weak(fabric_id, -1), be_const_var(11) }, - { be_const_key_weak(device_id, 24), be_const_var(13) }, - { be_const_key_weak(_counter_group_ctrl_snd_impl, -1), be_const_var(18) }, - { be_const_key_weak(_GROUP_KEY, -1), be_nested_str_weak(GroupKey_X20v1_X2E0) }, + { be_const_key_weak(get_pk, -1), be_const_closure(Matter_Fabric_get_pk_closure) }, + { be_const_key_weak(get_admin_vendor_name, 8), be_const_closure(Matter_Fabric_get_admin_vendor_name_closure) }, + { be_const_key_weak(get_fabric_id, -1), be_const_closure(Matter_Fabric_get_fabric_id_closure) }, + { be_const_key_weak(deleted, 49), be_const_var(2) }, + { be_const_key_weak(set_admin_subject_vendor, -1), be_const_closure(Matter_Fabric_set_admin_subject_vendor_closure) }, { be_const_key_weak(set_ipk_epoch_key, -1), be_const_closure(Matter_Fabric_set_ipk_epoch_key_closure) }, - { be_const_key_weak(fabric_label, -1), be_const_var(14) }, - { be_const_key_weak(get_ipk_group_key, 2), be_const_closure(Matter_Fabric_get_ipk_group_key_closure) }, - { be_const_key_weak(get_fabric_id_as_int64, -1), be_const_closure(Matter_Fabric_get_fabric_id_as_int64_closure) }, - { be_const_key_weak(no_private_key, -1), be_const_var(6) }, - { be_const_key_weak(get_admin_vendor, -1), be_const_closure(Matter_Fabric_get_admin_vendor_closure) }, - { be_const_key_weak(_MAX_CASE, -1), be_const_int(5) }, - { be_const_key_weak(is_marked_for_deletion, -1), be_const_closure(Matter_Fabric_is_marked_for_deletion_closure) }, - { be_const_key_weak(fabric_index, -1), be_const_var(3) }, - { be_const_key_weak(init, 21), be_const_closure(Matter_Fabric_init_closure) }, - { be_const_key_weak(get_admin_vendor_name, -1), be_const_closure(Matter_Fabric_get_admin_vendor_name_closure) }, - { be_const_key_weak(set_noc_icac, 55), be_const_closure(Matter_Fabric_set_noc_icac_closure) }, + { be_const_key_weak(fabric_parent, 45), be_const_var(4) }, + { be_const_key_weak(get_ipk_group_key, 18), be_const_closure(Matter_Fabric_get_ipk_group_key_closure) }, + { be_const_key_weak(fromjson, -1), be_const_static_closure(Matter_Fabric_fromjson_closure) }, { be_const_key_weak(set_ca, -1), be_const_closure(Matter_Fabric_set_ca_closure) }, - { be_const_key_weak(fabric_parent, -1), be_const_var(4) }, - { be_const_key_weak(fabric_candidate, 46), be_const_closure(Matter_Fabric_fabric_candidate_closure) }, - { be_const_key_weak(counter_group_data_snd, -1), be_const_var(15) }, - { be_const_key_weak(assign_fabric_index, -1), be_const_closure(Matter_Fabric_assign_fabric_index_closure) }, + { be_const_key_weak(counter_group_ctrl_snd, -1), be_const_var(16) }, + { be_const_key_weak(tojson, -1), be_const_closure(Matter_Fabric_tojson_closure) }, + { be_const_key_weak(hydrate_post, 53), be_const_closure(Matter_Fabric_hydrate_post_closure) }, + { be_const_key_weak(no_private_key, 58), be_const_var(6) }, + { be_const_key_weak(_sessions, -1), be_const_var(5) }, + { be_const_key_weak(fabric_compressed, -1), be_const_var(12) }, + { be_const_key_weak(device_id, -1), be_const_var(13) }, + { be_const_key_weak(get_noc, 25), be_const_closure(Matter_Fabric_get_noc_closure) }, + { be_const_key_weak(get_fabric_label, -1), be_const_closure(Matter_Fabric_get_fabric_label_closure) }, { be_const_key_weak(get_admin_subject, -1), be_const_closure(Matter_Fabric_get_admin_subject_closure) }, - { be_const_key_weak(created, 30), be_const_var(1) }, + { be_const_key_weak(before_remove, 28), be_const_closure(Matter_Fabric_before_remove_closure) }, + { be_const_key_weak(get_fabric_id_as_int64, -1), be_const_closure(Matter_Fabric_get_fabric_id_as_int64_closure) }, { be_const_key_weak(set_fabric_device, -1), be_const_closure(Matter_Fabric_set_fabric_device_closure) }, { be_const_key_weak(get_ca, -1), be_const_closure(Matter_Fabric_get_ca_closure) }, - { be_const_key_weak(counter_group_data_snd_next, -1), be_const_closure(Matter_Fabric_counter_group_data_snd_next_closure) }, { be_const_key_weak(ipk_epoch_key, -1), be_const_var(10) }, - { be_const_key_weak(get_ca_pub, 3), be_const_closure(Matter_Fabric_get_ca_pub_closure) }, + { be_const_key_weak(fabric_index, 48), be_const_var(3) }, + { be_const_key_weak(set_pk, -1), be_const_closure(Matter_Fabric_set_pk_closure) }, + { be_const_key_weak(fabric_completed, -1), be_const_closure(Matter_Fabric_fabric_completed_closure) }, + { be_const_key_weak(created, -1), be_const_var(1) }, + { be_const_key_weak(counter_group_data_snd_next, -1), be_const_closure(Matter_Fabric_counter_group_data_snd_next_closure) }, + { be_const_key_weak(set_noc_icac, -1), be_const_closure(Matter_Fabric_set_noc_icac_closure) }, { be_const_key_weak(_GROUP_SND_INCR, -1), be_const_int(32) }, - { be_const_key_weak(deleted, -1), be_const_var(2) }, - { be_const_key_weak(get_fabric_id, -1), be_const_closure(Matter_Fabric_get_fabric_id_closure) }, - { be_const_key_weak(get_device_id, -1), be_const_closure(Matter_Fabric_get_device_id_closure) }, + { be_const_key_weak(admin_vendor, 29), be_const_var(20) }, + { be_const_key_weak(fabric_id, -1), be_const_var(11) }, + { be_const_key_weak(fabric_label, -1), be_const_var(14) }, + { be_const_key_weak(log_new_fabric, -1), be_const_closure(Matter_Fabric_log_new_fabric_closure) }, + { be_const_key_weak(noc, -1), be_const_var(8) }, + { be_const_key_weak(_counter_group_data_snd_impl, -1), be_const_var(17) }, + { be_const_key_weak(get_newest_session, 37), be_const_closure(Matter_Fabric_get_newest_session_closure) }, + { be_const_key_weak(get_ca_pub, -1), be_const_closure(Matter_Fabric_get_ca_pub_closure) }, + { be_const_key_weak(add_session, -1), be_const_closure(Matter_Fabric_add_session_closure) }, + { be_const_key_weak(get_ipk_epoch_key, -1), be_const_closure(Matter_Fabric_get_ipk_epoch_key_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Fabric_init_closure) }, + { be_const_key_weak(writejson, -1), be_const_closure(Matter_Fabric_writejson_closure) }, + { be_const_key_weak(counter_group_ctrl_snd_next, -1), be_const_closure(Matter_Fabric_counter_group_ctrl_snd_next_closure) }, + { be_const_key_weak(_store, 61), be_const_var(0) }, + { be_const_key_weak(fabric_candidate, -1), be_const_closure(Matter_Fabric_fabric_candidate_closure) }, + { be_const_key_weak(counter_group_data_snd, -1), be_const_var(15) }, + { be_const_key_weak(assign_fabric_index, -1), be_const_closure(Matter_Fabric_assign_fabric_index_closure) }, + { be_const_key_weak(get_old_recent_session, -1), be_const_closure(Matter_Fabric_get_old_recent_session_closure) }, + { be_const_key_weak(admin_subject, -1), be_const_var(19) }, + { be_const_key_weak(get_fabric_index, 44), be_const_closure(Matter_Fabric_get_fabric_index_closure) }, + { be_const_key_weak(_GROUP_KEY, 43), be_nested_str_weak(GroupKey_X20v1_X2E0) }, + { be_const_key_weak(set_fabric_index, -1), be_const_closure(Matter_Fabric_set_fabric_index_closure) }, { be_const_key_weak(icac, -1), be_const_var(9) }, + { be_const_key_weak(root_ca_certificate, -1), be_const_var(7) }, + { be_const_key_weak(get_device_id_as_int64, -1), be_const_closure(Matter_Fabric_get_device_id_as_int64_closure) }, + { be_const_key_weak(get_device_id, 21), be_const_closure(Matter_Fabric_get_device_id_closure) }, + { be_const_key_weak(is_marked_for_deletion, -1), be_const_closure(Matter_Fabric_is_marked_for_deletion_closure) }, + { be_const_key_weak(get_oldest_session, 10), be_const_closure(Matter_Fabric_get_oldest_session_closure) }, + { be_const_key_weak(mark_for_deletion, -1), be_const_closure(Matter_Fabric_mark_for_deletion_closure) }, + { be_const_key_weak(get_admin_vendor, 4), be_const_closure(Matter_Fabric_get_admin_vendor_closure) }, + { be_const_key_weak(_MAX_CASE, -1), be_const_int(5) }, })), be_str_weak(Matter_Fabric) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h index ffcbba55c..97a993663 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h @@ -2223,25 +2223,25 @@ be_local_closure(Matter_IM__inner_process_read_request, /* name */ /* K5 */ be_nested_str_weak(_X20_X28), /* K6 */ be_nested_str_weak(_X29), /* K7 */ be_nested_str_weak(), - /* K8 */ be_nested_str_weak(read_attribute), - /* K9 */ be_nested_str_weak(tlv_solo), - /* K10 */ be_nested_str_weak(to_str_val), - /* K11 */ be_nested_str_weak(is_list), - /* K12 */ be_nested_str_weak(is_array), - /* K13 */ be_nested_str_weak(encode_len), - /* K14 */ be_nested_str_weak(IM_ReportData), - /* K15 */ be_nested_str_weak(MAX_MESSAGE), - /* K16 */ be_nested_str_weak(Matter_TLV_array), - /* K17 */ be_nested_str_weak(attributedata2raw), - /* K18 */ be_nested_str_weak(push), - /* K19 */ be_nested_str_weak(val), - /* K20 */ be_nested_str_weak(stop_iteration), - /* K21 */ be_nested_str_weak(tasmota), - /* K22 */ be_nested_str_weak(log), - /* K23 */ be_nested_str_weak(MTR_X3A_X20_X3ERead_Attr_X20_X28_X256i_X29_X20_X25s_X25s_X20_X2D_X20_X25s), - /* K24 */ be_nested_str_weak(local_session_id), - /* K25 */ be_const_int(3), - /* K26 */ be_nested_str_weak(status), + /* K8 */ be_nested_str_weak(status), + /* K9 */ be_nested_str_weak(read_attribute), + /* K10 */ be_nested_str_weak(tlv_solo), + /* K11 */ be_nested_str_weak(to_str_val), + /* K12 */ be_nested_str_weak(is_list), + /* K13 */ be_nested_str_weak(is_array), + /* K14 */ be_nested_str_weak(encode_len), + /* K15 */ be_nested_str_weak(IM_ReportData), + /* K16 */ be_nested_str_weak(MAX_MESSAGE), + /* K17 */ be_nested_str_weak(Matter_TLV_array), + /* K18 */ be_nested_str_weak(attributedata2raw), + /* K19 */ be_nested_str_weak(push), + /* K20 */ be_nested_str_weak(val), + /* K21 */ be_nested_str_weak(stop_iteration), + /* K22 */ be_nested_str_weak(tasmota), + /* K23 */ be_nested_str_weak(log), + /* K24 */ be_nested_str_weak(MTR_X3A_X20_X3ERead_Attr_X20_X28_X256i_X29_X20_X25s_X25s_X20_X2D_X20_X25s), + /* K25 */ be_nested_str_weak(local_session_id), + /* K26 */ be_const_int(3), /* K27 */ be_nested_str_weak(attributestatus2raw), /* K28 */ be_nested_str_weak(loglevel), /* K29 */ be_nested_str_weak(MTR_X3A_X20_X3ERead_Attr_X20_X28_X256i_X29_X20_X25s_X25s_X20_X2D_X20STATUS_X3A_X200x_X2502X_X20_X25s), @@ -2253,7 +2253,7 @@ be_local_closure(Matter_IM__inner_process_read_request, /* name */ }), be_str_weak(read_single_attribute), &be_const_str_solidified, - ( &(const binstruction[233]) { /* code */ + ( &(const binstruction[238]) { /* code */ 0xB8120000, // 0000 GETNGBL R4 K0 0x88100901, // 0001 GETMBR R4 R4 K1 0xB8160000, // 0002 GETNGBL R5 K0 @@ -2268,225 +2268,230 @@ be_local_closure(Matter_IM__inner_process_read_request, /* name */ 0x58180007, // 000B LDCONST R6 K7 0x5C140C00, // 000C MOVE R5 R6 0x4C180000, // 000D LDNIL R6 - 0x20180206, // 000E NE R6 R1 R6 - 0x781A0006, // 000F JMPF R6 #0017 - 0x8C180308, // 0010 GETMET R6 R1 K8 - 0x68200000, // 0011 GETUPV R8 U0 - 0x5C240400, // 0012 MOVE R9 R2 - 0x68280001, // 0013 GETUPV R10 U1 - 0x88281509, // 0014 GETMBR R10 R10 K9 - 0x7C180800, // 0015 CALL R6 4 - 0x70020000, // 0016 JMP #0018 - 0x4C180000, // 0017 LDNIL R6 - 0x501C0200, // 0018 LDBOOL R7 1 0 - 0x4C200000, // 0019 LDNIL R8 - 0x4C240000, // 001A LDNIL R9 - 0x20240C09, // 001B NE R9 R6 R9 - 0x78260054, // 001C JMPF R9 #0072 - 0x58240007, // 001D LDCONST R9 K7 - 0x68280002, // 001E GETUPV R10 U2 - 0x742A0002, // 001F JMPT R10 #0023 - 0x8C280D0A, // 0020 GETMET R10 R6 K10 - 0x7C280200, // 0021 CALL R10 1 - 0x5C241400, // 0022 MOVE R9 R10 - 0x88280D0B, // 0023 GETMBR R10 R6 K11 - 0x742A0001, // 0024 JMPT R10 #0027 + 0x900A1006, // 000E SETMBR R2 K8 R6 + 0x4C180000, // 000F LDNIL R6 + 0x20180206, // 0010 NE R6 R1 R6 + 0x781A0006, // 0011 JMPF R6 #0019 + 0x8C180309, // 0012 GETMET R6 R1 K9 + 0x68200000, // 0013 GETUPV R8 U0 + 0x5C240400, // 0014 MOVE R9 R2 + 0x68280001, // 0015 GETUPV R10 U1 + 0x8828150A, // 0016 GETMBR R10 R10 K10 + 0x7C180800, // 0017 CALL R6 4 + 0x70020000, // 0018 JMP #001A + 0x4C180000, // 0019 LDNIL R6 + 0x501C0200, // 001A LDBOOL R7 1 0 + 0x4C200000, // 001B LDNIL R8 + 0x4C240000, // 001C LDNIL R9 + 0x20240C09, // 001D NE R9 R6 R9 + 0x78260054, // 001E JMPF R9 #0074 + 0x58240007, // 001F LDCONST R9 K7 + 0x68280002, // 0020 GETUPV R10 U2 + 0x742A0002, // 0021 JMPT R10 #0025 + 0x8C280D0B, // 0022 GETMET R10 R6 K11 + 0x7C280200, // 0023 CALL R10 1 + 0x5C241400, // 0024 MOVE R9 R10 0x88280D0C, // 0025 GETMBR R10 R6 K12 - 0x782A0031, // 0026 JMPF R10 #0059 - 0x8C280D0D, // 0027 GETMET R10 R6 K13 - 0x7C280200, // 0028 CALL R10 1 - 0xB82E0000, // 0029 GETNGBL R11 K0 - 0x882C170E, // 002A GETMBR R11 R11 K14 - 0x882C170F, // 002B GETMBR R11 R11 K15 - 0x2428140B, // 002C GT R10 R10 R11 - 0x782A002A, // 002D JMPF R10 #0059 - 0x60280012, // 002E GETGBL R10 G18 - 0x7C280000, // 002F CALL R10 0 - 0x5C201400, // 0030 MOVE R8 R10 - 0x60280015, // 0031 GETGBL R10 G21 - 0x542E002F, // 0032 LDINT R11 48 - 0x7C280200, // 0033 CALL R10 1 - 0x8C2C0910, // 0034 GETMET R11 R4 K16 - 0x7C2C0200, // 0035 CALL R11 1 - 0x68300001, // 0036 GETUPV R12 U1 - 0x8C301911, // 0037 GETMET R12 R12 K17 - 0x5C381400, // 0038 MOVE R14 R10 - 0x5C3C0400, // 0039 MOVE R15 R2 - 0x5C401600, // 003A MOVE R16 R11 - 0x50440000, // 003B LDBOOL R17 0 0 - 0x7C300A00, // 003C CALL R12 5 - 0x8C301112, // 003D GETMET R12 R8 K18 - 0x5C381400, // 003E MOVE R14 R10 - 0x7C300400, // 003F CALL R12 2 - 0x60300010, // 0040 GETGBL R12 G16 - 0x88340D13, // 0041 GETMBR R13 R6 K19 - 0x7C300200, // 0042 CALL R12 1 - 0xA8020010, // 0043 EXBLK 0 #0055 - 0x5C341800, // 0044 MOVE R13 R12 - 0x7C340000, // 0045 CALL R13 0 - 0x60380015, // 0046 GETGBL R14 G21 - 0x543E002F, // 0047 LDINT R15 48 - 0x7C380200, // 0048 CALL R14 1 - 0x5C281C00, // 0049 MOVE R10 R14 - 0x68380001, // 004A GETUPV R14 U1 - 0x8C381D11, // 004B GETMET R14 R14 K17 - 0x5C401400, // 004C MOVE R16 R10 - 0x5C440400, // 004D MOVE R17 R2 - 0x5C481A00, // 004E MOVE R18 R13 - 0x504C0200, // 004F LDBOOL R19 1 0 - 0x7C380A00, // 0050 CALL R14 5 - 0x8C381112, // 0051 GETMET R14 R8 K18 - 0x5C401400, // 0052 MOVE R16 R10 - 0x7C380400, // 0053 CALL R14 2 - 0x7001FFEE, // 0054 JMP #0044 - 0x58300014, // 0055 LDCONST R12 K20 - 0xAC300200, // 0056 CATCH R12 1 0 - 0xB0080000, // 0057 RAISE 2 R0 R0 - 0x70020009, // 0058 JMP #0063 - 0x60280015, // 0059 GETGBL R10 G21 - 0x542E002F, // 005A LDINT R11 48 - 0x7C280200, // 005B CALL R10 1 - 0x5C201400, // 005C MOVE R8 R10 - 0x68280001, // 005D GETUPV R10 U1 - 0x8C281511, // 005E GETMET R10 R10 K17 - 0x5C301000, // 005F MOVE R12 R8 - 0x5C340400, // 0060 MOVE R13 R2 - 0x5C380C00, // 0061 MOVE R14 R6 - 0x7C280800, // 0062 CALL R10 4 - 0x68280002, // 0063 GETUPV R10 U2 - 0x742A000B, // 0064 JMPT R10 #0071 - 0xB82A2A00, // 0065 GETNGBL R10 K21 - 0x8C281516, // 0066 GETMET R10 R10 K22 - 0x60300018, // 0067 GETGBL R12 G24 - 0x58340017, // 0068 LDCONST R13 K23 - 0x68380000, // 0069 GETUPV R14 U0 - 0x88381D18, // 006A GETMBR R14 R14 K24 - 0x5C3C0400, // 006B MOVE R15 R2 - 0x5C400A00, // 006C MOVE R16 R5 - 0x5C441200, // 006D MOVE R17 R9 - 0x7C300A00, // 006E CALL R12 5 - 0x58340019, // 006F LDCONST R13 K25 - 0x7C280600, // 0070 CALL R10 3 - 0x70020038, // 0071 JMP #00AB - 0x8824051A, // 0072 GETMBR R9 R2 K26 - 0x4C280000, // 0073 LDNIL R10 - 0x2024120A, // 0074 NE R9 R9 R10 - 0x78260026, // 0075 JMPF R9 #009D - 0x780E0024, // 0076 JMPF R3 #009C - 0x60240015, // 0077 GETGBL R9 G21 - 0x542A002F, // 0078 LDINT R10 48 - 0x7C240200, // 0079 CALL R9 1 - 0x5C201200, // 007A MOVE R8 R9 - 0x68240001, // 007B GETUPV R9 U1 - 0x8C24131B, // 007C GETMET R9 R9 K27 - 0x5C2C1000, // 007D MOVE R11 R8 - 0x5C300400, // 007E MOVE R12 R2 - 0x8834051A, // 007F GETMBR R13 R2 K26 - 0x7C240800, // 0080 CALL R9 4 - 0xB8262A00, // 0081 GETNGBL R9 K21 - 0x8C24131C, // 0082 GETMET R9 R9 K28 - 0x582C0019, // 0083 LDCONST R11 K25 - 0x7C240400, // 0084 CALL R9 2 - 0x78260015, // 0085 JMPF R9 #009C - 0xB8262A00, // 0086 GETNGBL R9 K21 - 0x8C241316, // 0087 GETMET R9 R9 K22 - 0x602C0018, // 0088 GETGBL R11 G24 - 0x5830001D, // 0089 LDCONST R12 K29 - 0x68340000, // 008A GETUPV R13 U0 - 0x88341B18, // 008B GETMBR R13 R13 K24 - 0x60380008, // 008C GETGBL R14 G8 - 0x5C3C0400, // 008D MOVE R15 R2 - 0x7C380200, // 008E CALL R14 1 - 0x5C3C0A00, // 008F MOVE R15 R5 - 0x8840051A, // 0090 GETMBR R16 R2 K26 - 0x8844051A, // 0091 GETMBR R17 R2 K26 - 0xB84A0000, // 0092 GETNGBL R18 K0 - 0x8848251E, // 0093 GETMBR R18 R18 K30 - 0x1C442212, // 0094 EQ R17 R17 R18 - 0x78460001, // 0095 JMPF R17 #0098 - 0x5844001E, // 0096 LDCONST R17 K30 - 0x70020000, // 0097 JMP #0099 - 0x58440007, // 0098 LDCONST R17 K7 - 0x7C2C0C00, // 0099 CALL R11 6 - 0x58300019, // 009A LDCONST R12 K25 - 0x7C240600, // 009B CALL R9 3 - 0x7002000D, // 009C JMP #00AB - 0xB8262A00, // 009D GETNGBL R9 K21 - 0x8C241316, // 009E GETMET R9 R9 K22 - 0x602C0018, // 009F GETGBL R11 G24 - 0x5830001F, // 00A0 LDCONST R12 K31 - 0x68340000, // 00A1 GETUPV R13 U0 - 0x88341B18, // 00A2 GETMBR R13 R13 K24 - 0x60380008, // 00A3 GETGBL R14 G8 - 0x5C3C0400, // 00A4 MOVE R15 R2 - 0x7C380200, // 00A5 CALL R14 1 - 0x5C3C0A00, // 00A6 MOVE R15 R5 - 0x7C2C0800, // 00A7 CALL R11 4 - 0x58300019, // 00A8 LDCONST R12 K25 - 0x7C240600, // 00A9 CALL R9 3 - 0x501C0000, // 00AA LDBOOL R7 0 0 - 0x6024000F, // 00AB GETGBL R9 G15 - 0x5C281000, // 00AC MOVE R10 R8 - 0x602C0012, // 00AD GETGBL R11 G18 - 0x7C240400, // 00AE CALL R9 2 - 0x78260001, // 00AF JMPF R9 #00B2 - 0x58240020, // 00B0 LDCONST R9 K32 - 0x70020000, // 00B1 JMP #00B3 - 0x4C240000, // 00B2 LDNIL R9 - 0x4C280000, // 00B3 LDNIL R10 - 0x2028100A, // 00B4 NE R10 R8 R10 - 0x782A0031, // 00B5 JMPF R10 #00E8 - 0x4C280000, // 00B6 LDNIL R10 - 0x1C28120A, // 00B7 EQ R10 R9 R10 - 0x782A0001, // 00B8 JMPF R10 #00BB - 0x5C281000, // 00B9 MOVE R10 R8 - 0x70020000, // 00BA JMP #00BC - 0x94281009, // 00BB GETIDX R10 R8 R9 - 0x602C000C, // 00BC GETGBL R11 G12 - 0x88300121, // 00BD GETMBR R12 R0 K33 - 0x7C2C0200, // 00BE CALL R11 1 - 0x1C2C1720, // 00BF EQ R11 R11 K32 - 0x782E0004, // 00C0 JMPF R11 #00C6 - 0x882C0121, // 00C1 GETMBR R11 R0 K33 - 0x8C2C1712, // 00C2 GETMET R11 R11 K18 - 0x5C341400, // 00C3 MOVE R13 R10 - 0x7C2C0400, // 00C4 CALL R11 2 - 0x70020014, // 00C5 JMP #00DB + 0x742A0001, // 0026 JMPT R10 #0029 + 0x88280D0D, // 0027 GETMBR R10 R6 K13 + 0x782A0031, // 0028 JMPF R10 #005B + 0x8C280D0E, // 0029 GETMET R10 R6 K14 + 0x7C280200, // 002A CALL R10 1 + 0xB82E0000, // 002B GETNGBL R11 K0 + 0x882C170F, // 002C GETMBR R11 R11 K15 + 0x882C1710, // 002D GETMBR R11 R11 K16 + 0x2428140B, // 002E GT R10 R10 R11 + 0x782A002A, // 002F JMPF R10 #005B + 0x60280012, // 0030 GETGBL R10 G18 + 0x7C280000, // 0031 CALL R10 0 + 0x5C201400, // 0032 MOVE R8 R10 + 0x60280015, // 0033 GETGBL R10 G21 + 0x542E002F, // 0034 LDINT R11 48 + 0x7C280200, // 0035 CALL R10 1 + 0x8C2C0911, // 0036 GETMET R11 R4 K17 + 0x7C2C0200, // 0037 CALL R11 1 + 0x68300001, // 0038 GETUPV R12 U1 + 0x8C301912, // 0039 GETMET R12 R12 K18 + 0x5C381400, // 003A MOVE R14 R10 + 0x5C3C0400, // 003B MOVE R15 R2 + 0x5C401600, // 003C MOVE R16 R11 + 0x50440000, // 003D LDBOOL R17 0 0 + 0x7C300A00, // 003E CALL R12 5 + 0x8C301113, // 003F GETMET R12 R8 K19 + 0x5C381400, // 0040 MOVE R14 R10 + 0x7C300400, // 0041 CALL R12 2 + 0x60300010, // 0042 GETGBL R12 G16 + 0x88340D14, // 0043 GETMBR R13 R6 K20 + 0x7C300200, // 0044 CALL R12 1 + 0xA8020010, // 0045 EXBLK 0 #0057 + 0x5C341800, // 0046 MOVE R13 R12 + 0x7C340000, // 0047 CALL R13 0 + 0x60380015, // 0048 GETGBL R14 G21 + 0x543E002F, // 0049 LDINT R15 48 + 0x7C380200, // 004A CALL R14 1 + 0x5C281C00, // 004B MOVE R10 R14 + 0x68380001, // 004C GETUPV R14 U1 + 0x8C381D12, // 004D GETMET R14 R14 K18 + 0x5C401400, // 004E MOVE R16 R10 + 0x5C440400, // 004F MOVE R17 R2 + 0x5C481A00, // 0050 MOVE R18 R13 + 0x504C0200, // 0051 LDBOOL R19 1 0 + 0x7C380A00, // 0052 CALL R14 5 + 0x8C381113, // 0053 GETMET R14 R8 K19 + 0x5C401400, // 0054 MOVE R16 R10 + 0x7C380400, // 0055 CALL R14 2 + 0x7001FFEE, // 0056 JMP #0046 + 0x58300015, // 0057 LDCONST R12 K21 + 0xAC300200, // 0058 CATCH R12 1 0 + 0xB0080000, // 0059 RAISE 2 R0 R0 + 0x70020009, // 005A JMP #0065 + 0x60280015, // 005B GETGBL R10 G21 + 0x542E002F, // 005C LDINT R11 48 + 0x7C280200, // 005D CALL R10 1 + 0x5C201400, // 005E MOVE R8 R10 + 0x68280001, // 005F GETUPV R10 U1 + 0x8C281512, // 0060 GETMET R10 R10 K18 + 0x5C301000, // 0061 MOVE R12 R8 + 0x5C340400, // 0062 MOVE R13 R2 + 0x5C380C00, // 0063 MOVE R14 R6 + 0x7C280800, // 0064 CALL R10 4 + 0x68280002, // 0065 GETUPV R10 U2 + 0x742A000B, // 0066 JMPT R10 #0073 + 0xB82A2C00, // 0067 GETNGBL R10 K22 + 0x8C281517, // 0068 GETMET R10 R10 K23 + 0x60300018, // 0069 GETGBL R12 G24 + 0x58340018, // 006A LDCONST R13 K24 + 0x68380000, // 006B GETUPV R14 U0 + 0x88381D19, // 006C GETMBR R14 R14 K25 + 0x5C3C0400, // 006D MOVE R15 R2 + 0x5C400A00, // 006E MOVE R16 R5 + 0x5C441200, // 006F MOVE R17 R9 + 0x7C300A00, // 0070 CALL R12 5 + 0x5834001A, // 0071 LDCONST R13 K26 + 0x7C280600, // 0072 CALL R10 3 + 0x7002003B, // 0073 JMP #00B0 + 0x88240508, // 0074 GETMBR R9 R2 K8 + 0x4C280000, // 0075 LDNIL R10 + 0x2024120A, // 0076 NE R9 R9 R10 + 0x78260026, // 0077 JMPF R9 #009F + 0x780E0024, // 0078 JMPF R3 #009E + 0x60240015, // 0079 GETGBL R9 G21 + 0x542A002F, // 007A LDINT R10 48 + 0x7C240200, // 007B CALL R9 1 + 0x5C201200, // 007C MOVE R8 R9 + 0x68240001, // 007D GETUPV R9 U1 + 0x8C24131B, // 007E GETMET R9 R9 K27 + 0x5C2C1000, // 007F MOVE R11 R8 + 0x5C300400, // 0080 MOVE R12 R2 + 0x88340508, // 0081 GETMBR R13 R2 K8 + 0x7C240800, // 0082 CALL R9 4 + 0xB8262C00, // 0083 GETNGBL R9 K22 + 0x8C24131C, // 0084 GETMET R9 R9 K28 + 0x582C001A, // 0085 LDCONST R11 K26 + 0x7C240400, // 0086 CALL R9 2 + 0x78260015, // 0087 JMPF R9 #009E + 0xB8262C00, // 0088 GETNGBL R9 K22 + 0x8C241317, // 0089 GETMET R9 R9 K23 + 0x602C0018, // 008A GETGBL R11 G24 + 0x5830001D, // 008B LDCONST R12 K29 + 0x68340000, // 008C GETUPV R13 U0 + 0x88341B19, // 008D GETMBR R13 R13 K25 + 0x60380008, // 008E GETGBL R14 G8 + 0x5C3C0400, // 008F MOVE R15 R2 + 0x7C380200, // 0090 CALL R14 1 + 0x5C3C0A00, // 0091 MOVE R15 R5 + 0x88400508, // 0092 GETMBR R16 R2 K8 + 0x88440508, // 0093 GETMBR R17 R2 K8 + 0xB84A0000, // 0094 GETNGBL R18 K0 + 0x8848251E, // 0095 GETMBR R18 R18 K30 + 0x1C442212, // 0096 EQ R17 R17 R18 + 0x78460001, // 0097 JMPF R17 #009A + 0x5844001E, // 0098 LDCONST R17 K30 + 0x70020000, // 0099 JMP #009B + 0x58440007, // 009A LDCONST R17 K7 + 0x7C2C0C00, // 009B CALL R11 6 + 0x5830001A, // 009C LDCONST R12 K26 + 0x7C240600, // 009D CALL R9 3 + 0x70020010, // 009E JMP #00B0 + 0x68240002, // 009F GETUPV R9 U2 + 0x7426000C, // 00A0 JMPT R9 #00AE + 0xB8262C00, // 00A1 GETNGBL R9 K22 + 0x8C241317, // 00A2 GETMET R9 R9 K23 + 0x602C0018, // 00A3 GETGBL R11 G24 + 0x5830001F, // 00A4 LDCONST R12 K31 + 0x68340000, // 00A5 GETUPV R13 U0 + 0x88341B19, // 00A6 GETMBR R13 R13 K25 + 0x60380008, // 00A7 GETGBL R14 G8 + 0x5C3C0400, // 00A8 MOVE R15 R2 + 0x7C380200, // 00A9 CALL R14 1 + 0x5C3C0A00, // 00AA MOVE R15 R5 + 0x7C2C0800, // 00AB CALL R11 4 + 0x5830001A, // 00AC LDCONST R12 K26 + 0x7C240600, // 00AD CALL R9 3 + 0x780E0000, // 00AE JMPF R3 #00B0 + 0x501C0000, // 00AF LDBOOL R7 0 0 + 0x6024000F, // 00B0 GETGBL R9 G15 + 0x5C281000, // 00B1 MOVE R10 R8 + 0x602C0012, // 00B2 GETGBL R11 G18 + 0x7C240400, // 00B3 CALL R9 2 + 0x78260001, // 00B4 JMPF R9 #00B7 + 0x58240020, // 00B5 LDCONST R9 K32 + 0x70020000, // 00B6 JMP #00B8 + 0x4C240000, // 00B7 LDNIL R9 + 0x4C280000, // 00B8 LDNIL R10 + 0x2028100A, // 00B9 NE R10 R8 R10 + 0x782A0031, // 00BA JMPF R10 #00ED + 0x4C280000, // 00BB LDNIL R10 + 0x1C28120A, // 00BC EQ R10 R9 R10 + 0x782A0001, // 00BD JMPF R10 #00C0 + 0x5C281000, // 00BE MOVE R10 R8 + 0x70020000, // 00BF JMP #00C1 + 0x94281009, // 00C0 GETIDX R10 R8 R9 + 0x602C000C, // 00C1 GETGBL R11 G12 + 0x88300121, // 00C2 GETMBR R12 R0 K33 + 0x7C2C0200, // 00C3 CALL R11 1 + 0x1C2C1720, // 00C4 EQ R11 R11 K32 + 0x782E0004, // 00C5 JMPF R11 #00CB 0x882C0121, // 00C6 GETMBR R11 R0 K33 - 0x5431FFFE, // 00C7 LDINT R12 -1 - 0x942C160C, // 00C8 GETIDX R11 R11 R12 - 0x6030000C, // 00C9 GETGBL R12 G12 - 0x5C341600, // 00CA MOVE R13 R11 - 0x7C300200, // 00CB CALL R12 1 - 0x6034000C, // 00CC GETGBL R13 G12 - 0x5C381400, // 00CD MOVE R14 R10 - 0x7C340200, // 00CE CALL R13 1 - 0x0030180D, // 00CF ADD R12 R12 R13 - 0xB8360000, // 00D0 GETNGBL R13 K0 - 0x88341B0E, // 00D1 GETMBR R13 R13 K14 - 0x88341B0F, // 00D2 GETMBR R13 R13 K15 - 0x1830180D, // 00D3 LE R12 R12 R13 - 0x78320001, // 00D4 JMPF R12 #00D7 - 0x4030160A, // 00D5 CONNECT R12 R11 R10 - 0x70020003, // 00D6 JMP #00DB - 0x88300121, // 00D7 GETMBR R12 R0 K33 - 0x8C301912, // 00D8 GETMET R12 R12 K18 - 0x5C381400, // 00D9 MOVE R14 R10 - 0x7C300400, // 00DA CALL R12 2 - 0x4C2C0000, // 00DB LDNIL R11 - 0x1C2C120B, // 00DC EQ R11 R9 R11 - 0x782E0001, // 00DD JMPF R11 #00E0 - 0x4C200000, // 00DE LDNIL R8 - 0x70020006, // 00DF JMP #00E7 - 0x00241322, // 00E0 ADD R9 R9 K34 - 0x602C000C, // 00E1 GETGBL R11 G12 - 0x5C301000, // 00E2 MOVE R12 R8 - 0x7C2C0200, // 00E3 CALL R11 1 - 0x282C120B, // 00E4 GE R11 R9 R11 - 0x782E0000, // 00E5 JMPF R11 #00E7 - 0x4C200000, // 00E6 LDNIL R8 - 0x7001FFCA, // 00E7 JMP #00B3 - 0x80040E00, // 00E8 RET 1 R7 + 0x8C2C1713, // 00C7 GETMET R11 R11 K19 + 0x5C341400, // 00C8 MOVE R13 R10 + 0x7C2C0400, // 00C9 CALL R11 2 + 0x70020014, // 00CA JMP #00E0 + 0x882C0121, // 00CB GETMBR R11 R0 K33 + 0x5431FFFE, // 00CC LDINT R12 -1 + 0x942C160C, // 00CD GETIDX R11 R11 R12 + 0x6030000C, // 00CE GETGBL R12 G12 + 0x5C341600, // 00CF MOVE R13 R11 + 0x7C300200, // 00D0 CALL R12 1 + 0x6034000C, // 00D1 GETGBL R13 G12 + 0x5C381400, // 00D2 MOVE R14 R10 + 0x7C340200, // 00D3 CALL R13 1 + 0x0030180D, // 00D4 ADD R12 R12 R13 + 0xB8360000, // 00D5 GETNGBL R13 K0 + 0x88341B0F, // 00D6 GETMBR R13 R13 K15 + 0x88341B10, // 00D7 GETMBR R13 R13 K16 + 0x1830180D, // 00D8 LE R12 R12 R13 + 0x78320001, // 00D9 JMPF R12 #00DC + 0x4030160A, // 00DA CONNECT R12 R11 R10 + 0x70020003, // 00DB JMP #00E0 + 0x88300121, // 00DC GETMBR R12 R0 K33 + 0x8C301913, // 00DD GETMET R12 R12 K19 + 0x5C381400, // 00DE MOVE R14 R10 + 0x7C300400, // 00DF CALL R12 2 + 0x4C2C0000, // 00E0 LDNIL R11 + 0x1C2C120B, // 00E1 EQ R11 R9 R11 + 0x782E0001, // 00E2 JMPF R11 #00E5 + 0x4C200000, // 00E3 LDNIL R8 + 0x70020006, // 00E4 JMP #00EC + 0x00241322, // 00E5 ADD R9 R9 K34 + 0x602C000C, // 00E6 GETGBL R11 G12 + 0x5C301000, // 00E7 MOVE R12 R8 + 0x7C2C0200, // 00E8 CALL R11 1 + 0x282C120B, // 00E9 GE R11 R9 R11 + 0x782E0000, // 00EA JMPF R11 #00EC + 0x4C200000, // 00EB LDNIL R8 + 0x7001FFCA, // 00EC JMP #00B8 + 0x80040E00, // 00ED RET 1 R7 }) ), be_nested_proto( diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h index 08f9cf707..43e1ef88a 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h @@ -1068,7 +1068,7 @@ be_local_closure(Matter_Frame_decrypt, /* name */ }), be_str_weak(decrypt), &be_const_str_solidified, - ( &(const binstruction[116]) { /* code */ + ( &(const binstruction[117]) { /* code */ 0xA4060000, // 0000 IMPORT R1 K0 0x88080101, // 0001 GETMBR R2 R0 K1 0x880C0102, // 0002 GETMBR R3 R0 K2 @@ -1136,55 +1136,56 @@ be_local_closure(Matter_Frame_decrypt, /* name */ 0x542E0003, // 0040 LDINT R11 4 0x7C200600, // 0041 CALL R8 3 0x88200118, // 0042 GETMBR R8 R0 K24 - 0x78220001, // 0043 JMPF R8 #0046 - 0x40200F0B, // 0044 CONNECT R8 R7 K11 - 0x70020006, // 0045 JMP #004D - 0x88200519, // 0046 GETMBR R8 R2 K25 - 0x78220001, // 0047 JMPF R8 #004A - 0x88200519, // 0048 GETMBR R8 R2 K25 - 0x40200E08, // 0049 CONNECT R8 R7 R8 - 0x8C200F1A, // 004A GETMET R8 R7 K26 - 0x542A000C, // 004B LDINT R10 13 - 0x7C200400, // 004C CALL R8 2 - 0x8820031B, // 004D GETMBR R8 R1 K27 - 0x8C20111C, // 004E GETMET R8 R8 K28 - 0x5C280C00, // 004F MOVE R10 R6 - 0x5C2C0E00, // 0050 MOVE R11 R7 - 0x58300011, // 0051 LDCONST R12 K17 - 0x6034000C, // 0052 GETGBL R13 G12 - 0x5C380E00, // 0053 MOVE R14 R7 - 0x7C340200, // 0054 CALL R13 1 - 0x5C380600, // 0055 MOVE R14 R3 - 0x583C0011, // 0056 LDCONST R15 K17 - 0x5C400800, // 0057 MOVE R16 R4 - 0x5C440600, // 0058 MOVE R17 R3 - 0x5C480800, // 0059 MOVE R18 R4 - 0x604C000C, // 005A GETGBL R19 G12 - 0x5C500600, // 005B MOVE R20 R3 - 0x7C4C0200, // 005C CALL R19 1 - 0x044C2604, // 005D SUB R19 R19 R4 - 0x044C2605, // 005E SUB R19 R19 R5 - 0x5C500600, // 005F MOVE R20 R3 - 0x6054000C, // 0060 GETGBL R21 G12 - 0x5C580600, // 0061 MOVE R22 R3 - 0x7C540200, // 0062 CALL R21 1 - 0x04542A05, // 0063 SUB R21 R21 R5 - 0x5C580A00, // 0064 MOVE R22 R5 - 0x7C201C00, // 0065 CALL R8 14 - 0x78220006, // 0066 JMPF R8 #006E - 0x8C24071A, // 0067 GETMET R9 R3 K26 - 0x602C000C, // 0068 GETGBL R11 G12 - 0x5C300600, // 0069 MOVE R12 R3 - 0x7C2C0200, // 006A CALL R11 1 - 0x042C1605, // 006B SUB R11 R11 R5 - 0x7C240400, // 006C CALL R9 2 - 0x70020004, // 006D JMP #0073 - 0xB8260C00, // 006E GETNGBL R9 K6 - 0x8C241307, // 006F GETMET R9 R9 K7 - 0x582C001D, // 0070 LDCONST R11 K29 - 0x58300012, // 0071 LDCONST R12 K18 - 0x7C240600, // 0072 CALL R9 3 - 0x80041000, // 0073 RET 1 R8 + 0x78220002, // 0043 JMPF R8 #0047 + 0x88200118, // 0044 GETMBR R8 R0 K24 + 0x40200E08, // 0045 CONNECT R8 R7 R8 + 0x70020006, // 0046 JMP #004E + 0x88200519, // 0047 GETMBR R8 R2 K25 + 0x78220001, // 0048 JMPF R8 #004B + 0x88200519, // 0049 GETMBR R8 R2 K25 + 0x40200E08, // 004A CONNECT R8 R7 R8 + 0x8C200F1A, // 004B GETMET R8 R7 K26 + 0x542A000C, // 004C LDINT R10 13 + 0x7C200400, // 004D CALL R8 2 + 0x8820031B, // 004E GETMBR R8 R1 K27 + 0x8C20111C, // 004F GETMET R8 R8 K28 + 0x5C280C00, // 0050 MOVE R10 R6 + 0x5C2C0E00, // 0051 MOVE R11 R7 + 0x58300011, // 0052 LDCONST R12 K17 + 0x6034000C, // 0053 GETGBL R13 G12 + 0x5C380E00, // 0054 MOVE R14 R7 + 0x7C340200, // 0055 CALL R13 1 + 0x5C380600, // 0056 MOVE R14 R3 + 0x583C0011, // 0057 LDCONST R15 K17 + 0x5C400800, // 0058 MOVE R16 R4 + 0x5C440600, // 0059 MOVE R17 R3 + 0x5C480800, // 005A MOVE R18 R4 + 0x604C000C, // 005B GETGBL R19 G12 + 0x5C500600, // 005C MOVE R20 R3 + 0x7C4C0200, // 005D CALL R19 1 + 0x044C2604, // 005E SUB R19 R19 R4 + 0x044C2605, // 005F SUB R19 R19 R5 + 0x5C500600, // 0060 MOVE R20 R3 + 0x6054000C, // 0061 GETGBL R21 G12 + 0x5C580600, // 0062 MOVE R22 R3 + 0x7C540200, // 0063 CALL R21 1 + 0x04542A05, // 0064 SUB R21 R21 R5 + 0x5C580A00, // 0065 MOVE R22 R5 + 0x7C201C00, // 0066 CALL R8 14 + 0x78220006, // 0067 JMPF R8 #006F + 0x8C24071A, // 0068 GETMET R9 R3 K26 + 0x602C000C, // 0069 GETGBL R11 G12 + 0x5C300600, // 006A MOVE R12 R3 + 0x7C2C0200, // 006B CALL R11 1 + 0x042C1605, // 006C SUB R11 R11 R5 + 0x7C240400, // 006D CALL R9 2 + 0x70020004, // 006E JMP #0074 + 0xB8260C00, // 006F GETNGBL R9 K6 + 0x8C241307, // 0070 GETMET R9 R9 K7 + 0x582C001D, // 0071 LDCONST R11 K29 + 0x58300012, // 0072 LDCONST R12 K18 + 0x7C240600, // 0073 CALL R9 3 + 0x80041000, // 0074 RET 1 R8 }) ) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Path.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Path_0.h similarity index 99% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Path.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Path_0.h index bab7d9909..597ec9c15 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Path.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Path_0.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Path.h */ +/* Solidification of Matter_Path_0.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Path_1_Generator.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Path_1_Generator.h new file mode 100644 index 000000000..37e84b088 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Path_1_Generator.h @@ -0,0 +1,535 @@ +/* Solidification of Matter_Path_1_Generator.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_PathGenerator; + +/******************************************************************** +** Solidified function: next +********************************************************************/ +be_local_closure(Matter_PathGenerator_next, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[14]) { /* constants */ + /* K0 */ be_nested_str_weak(path_in), + /* K1 */ be_nested_str_weak(pi), + /* K2 */ be_nested_str_weak(cluster), + /* K3 */ be_nested_str_weak(_next_endpoint), + /* K4 */ be_nested_str_weak(endpoint_found), + /* K5 */ be_nested_str_weak(attribute), + /* K6 */ be_nested_str_weak(_next_cluster), + /* K7 */ be_nested_str_weak(cluster_found), + /* K8 */ be_nested_str_weak(_next_attribute), + /* K9 */ be_nested_str_weak(attribute_found), + /* K10 */ be_nested_str_weak(path_concrete), + /* K11 */ be_nested_str_weak(reset), + /* K12 */ be_nested_str_weak(endpoint), + /* K13 */ be_nested_str_weak(get_endpoint), + }), + be_str_weak(next), + &be_const_str_solidified, + ( &(const binstruction[62]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x78060001, // 0003 JMPF R1 #0006 + 0x4C040000, // 0004 LDNIL R1 + 0x80040200, // 0005 RET 1 R1 + 0x88040101, // 0006 GETMBR R1 R0 K1 + 0x50080000, // 0007 LDBOOL R2 0 0 + 0x20040202, // 0008 NE R1 R1 R2 + 0x7806002F, // 0009 JMPF R1 #003A + 0x88040101, // 000A GETMBR R1 R0 K1 + 0x4C080000, // 000B LDNIL R2 + 0x1C040202, // 000C EQ R1 R1 R2 + 0x74060003, // 000D JMPT R1 #0012 + 0x88040102, // 000E GETMBR R1 R0 K2 + 0x50080000, // 000F LDBOOL R2 0 0 + 0x1C040202, // 0010 EQ R1 R1 R2 + 0x78060002, // 0011 JMPF R1 #0015 + 0x8C040103, // 0012 GETMET R1 R0 K3 + 0x7C040200, // 0013 CALL R1 1 + 0x7001FFF0, // 0014 JMP #0006 + 0x50040200, // 0015 LDBOOL R1 1 0 + 0x90020801, // 0016 SETMBR R0 K4 R1 + 0x88040102, // 0017 GETMBR R1 R0 K2 + 0x4C080000, // 0018 LDNIL R2 + 0x1C040202, // 0019 EQ R1 R1 R2 + 0x74060003, // 001A JMPT R1 #001F + 0x88040105, // 001B GETMBR R1 R0 K5 + 0x50080000, // 001C LDBOOL R2 0 0 + 0x1C040202, // 001D EQ R1 R1 R2 + 0x78060002, // 001E JMPF R1 #0022 + 0x8C040106, // 001F GETMET R1 R0 K6 + 0x7C040200, // 0020 CALL R1 1 + 0x7001FFE3, // 0021 JMP #0006 + 0x50040200, // 0022 LDBOOL R1 1 0 + 0x90020E01, // 0023 SETMBR R0 K7 R1 + 0x8C040108, // 0024 GETMET R1 R0 K8 + 0x7C040200, // 0025 CALL R1 1 + 0x88040105, // 0026 GETMBR R1 R0 K5 + 0x50080000, // 0027 LDBOOL R2 0 0 + 0x1C040202, // 0028 EQ R1 R1 R2 + 0x78060000, // 0029 JMPF R1 #002B + 0x7001FFDA, // 002A JMP #0006 + 0x50040200, // 002B LDBOOL R1 1 0 + 0x90021201, // 002C SETMBR R0 K9 R1 + 0x8804010A, // 002D GETMBR R1 R0 K10 + 0x8C08030B, // 002E GETMET R2 R1 K11 + 0x7C080200, // 002F CALL R2 1 + 0x88080101, // 0030 GETMBR R2 R0 K1 + 0x8C08050D, // 0031 GETMET R2 R2 K13 + 0x7C080200, // 0032 CALL R2 1 + 0x90061802, // 0033 SETMBR R1 K12 R2 + 0x88080102, // 0034 GETMBR R2 R0 K2 + 0x90060402, // 0035 SETMBR R1 K2 R2 + 0x88080105, // 0036 GETMBR R2 R0 K5 + 0x90060A02, // 0037 SETMBR R1 K5 R2 + 0x80040200, // 0038 RET 1 R1 + 0x7001FFCB, // 0039 JMP #0006 + 0x8C04010B, // 003A GETMET R1 R0 K11 + 0x7C040200, // 003B CALL R1 1 + 0x4C040000, // 003C LDNIL R1 + 0x80040200, // 003D RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _next_cluster +********************************************************************/ +be_local_closure(Matter_PathGenerator__next_cluster, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(cluster), + /* K1 */ be_nested_str_weak(clusters), + /* K2 */ be_nested_str_weak(path_in), + /* K3 */ be_nested_str_weak(attribute), + /* K4 */ be_nested_str_weak(find), + /* K5 */ be_const_int(1), + }), + be_str_weak(_next_cluster), + &be_const_str_solidified, + ( &(const binstruction[45]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x50080000, // 0001 LDBOOL R2 0 0 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x78060001, // 0003 JMPF R1 #0006 + 0x50040000, // 0004 LDBOOL R1 0 0 + 0x80040200, // 0005 RET 1 R1 + 0x88040101, // 0006 GETMBR R1 R0 K1 + 0x88080102, // 0007 GETMBR R2 R0 K2 + 0x88080500, // 0008 GETMBR R2 R2 K0 + 0x4C0C0000, // 0009 LDNIL R3 + 0x90020603, // 000A SETMBR R0 K3 R3 + 0x540DFFFE, // 000B LDINT R3 -1 + 0x88100100, // 000C GETMBR R4 R0 K0 + 0x4C140000, // 000D LDNIL R5 + 0x20100805, // 000E NE R4 R4 R5 + 0x78120003, // 000F JMPF R4 #0014 + 0x8C100304, // 0010 GETMET R4 R1 K4 + 0x88180100, // 0011 GETMBR R6 R0 K0 + 0x7C100400, // 0012 CALL R4 2 + 0x5C0C0800, // 0013 MOVE R3 R4 + 0x4C100000, // 0014 LDNIL R4 + 0x20100604, // 0015 NE R4 R3 R4 + 0x78120011, // 0016 JMPF R4 #0029 + 0x00100705, // 0017 ADD R4 R3 K5 + 0x6014000C, // 0018 GETGBL R5 G12 + 0x5C180200, // 0019 MOVE R6 R1 + 0x7C140200, // 001A CALL R5 1 + 0x14100805, // 001B LT R4 R4 R5 + 0x7812000B, // 001C JMPF R4 #0029 + 0x000C0705, // 001D ADD R3 R3 K5 + 0x94100203, // 001E GETIDX R4 R1 R3 + 0x90020004, // 001F SETMBR R0 K0 R4 + 0x4C100000, // 0020 LDNIL R4 + 0x1C100404, // 0021 EQ R4 R2 R4 + 0x74120002, // 0022 JMPT R4 #0026 + 0x88100100, // 0023 GETMBR R4 R0 K0 + 0x1C100404, // 0024 EQ R4 R2 R4 + 0x78120001, // 0025 JMPF R4 #0028 + 0x88100100, // 0026 GETMBR R4 R0 K0 + 0x80040800, // 0027 RET 1 R4 + 0x7001FFED, // 0028 JMP #0017 + 0x50100000, // 0029 LDBOOL R4 0 0 + 0x90020004, // 002A SETMBR R0 K0 R4 + 0x50100000, // 002B LDBOOL R4 0 0 + 0x80040800, // 002C RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start +********************************************************************/ +be_local_closure(Matter_PathGenerator_start, /* name */ + be_nested_proto( + 5, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(path_concrete), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(Path), + /* K3 */ be_nested_str_weak(reset), + /* K4 */ be_nested_str_weak(path_in), + /* K5 */ be_nested_str_weak(session), + /* K6 */ be_nested_str_weak(endpoint_found), + /* K7 */ be_nested_str_weak(cluster_found), + /* K8 */ be_nested_str_weak(attribute_found), + }), + be_str_weak(start), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0xB80E0200, // 0000 GETNGBL R3 K1 + 0x8C0C0702, // 0001 GETMET R3 R3 K2 + 0x7C0C0200, // 0002 CALL R3 1 + 0x90020003, // 0003 SETMBR R0 K0 R3 + 0x8C0C0103, // 0004 GETMET R3 R0 K3 + 0x7C0C0200, // 0005 CALL R3 1 + 0x90020801, // 0006 SETMBR R0 K4 R1 + 0x90020A02, // 0007 SETMBR R0 K5 R2 + 0x500C0000, // 0008 LDBOOL R3 0 0 + 0x90020C03, // 0009 SETMBR R0 K6 R3 + 0x500C0000, // 000A LDBOOL R3 0 0 + 0x90020E03, // 000B SETMBR R0 K7 R3 + 0x500C0000, // 000C LDBOOL R3 0 0 + 0x90021003, // 000D SETMBR R0 K8 R3 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_pi +********************************************************************/ +be_local_closure(Matter_PathGenerator_get_pi, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(pi), + }), + be_str_weak(get_pi), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_PathGenerator_init, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: reset +********************************************************************/ +be_local_closure(Matter_PathGenerator_reset, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(path_in), + /* K1 */ be_nested_str_weak(session), + /* K2 */ be_nested_str_weak(path_concrete), + /* K3 */ be_nested_str_weak(reset), + /* K4 */ be_nested_str_weak(pi), + /* K5 */ be_nested_str_weak(cluster), + /* K6 */ be_nested_str_weak(attribute), + /* K7 */ be_nested_str_weak(clusters), + }), + be_str_weak(reset), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x4C040000, // 0000 LDNIL R1 + 0x90020001, // 0001 SETMBR R0 K0 R1 + 0x90020201, // 0002 SETMBR R0 K1 R1 + 0x88080102, // 0003 GETMBR R2 R0 K2 + 0x8C080503, // 0004 GETMET R2 R2 K3 + 0x7C080200, // 0005 CALL R2 1 + 0x90020801, // 0006 SETMBR R0 K4 R1 + 0x90020A01, // 0007 SETMBR R0 K5 R1 + 0x90020C01, // 0008 SETMBR R0 K6 R1 + 0x90020E01, // 0009 SETMBR R0 K7 R1 + 0x90020E01, // 000A SETMBR R0 K7 R1 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _next_endpoint +********************************************************************/ +be_local_closure(Matter_PathGenerator__next_endpoint, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str_weak(pi), + /* K1 */ be_nested_str_weak(device), + /* K2 */ be_nested_str_weak(plugins), + /* K3 */ be_nested_str_weak(path_in), + /* K4 */ be_nested_str_weak(endpoint), + /* K5 */ be_nested_str_weak(cluster), + /* K6 */ be_nested_str_weak(attribute), + /* K7 */ be_nested_str_weak(find), + /* K8 */ be_const_int(1), + /* K9 */ be_nested_str_weak(get_endpoint), + /* K10 */ be_nested_str_weak(clusters), + /* K11 */ be_nested_str_weak(get_cluster_list_sorted), + }), + be_str_weak(_next_endpoint), + &be_const_str_solidified, + ( &(const binstruction[54]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x50080000, // 0001 LDBOOL R2 0 0 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x78060001, // 0003 JMPF R1 #0006 + 0x50040000, // 0004 LDBOOL R1 0 0 + 0x80040200, // 0005 RET 1 R1 + 0x88040101, // 0006 GETMBR R1 R0 K1 + 0x88040302, // 0007 GETMBR R1 R1 K2 + 0x88080103, // 0008 GETMBR R2 R0 K3 + 0x88080504, // 0009 GETMBR R2 R2 K4 + 0x4C0C0000, // 000A LDNIL R3 + 0x90020A03, // 000B SETMBR R0 K5 R3 + 0x4C0C0000, // 000C LDNIL R3 + 0x90020C03, // 000D SETMBR R0 K6 R3 + 0x540DFFFE, // 000E LDINT R3 -1 + 0x88100100, // 000F GETMBR R4 R0 K0 + 0x4C140000, // 0010 LDNIL R5 + 0x20100805, // 0011 NE R4 R4 R5 + 0x78120003, // 0012 JMPF R4 #0017 + 0x8C100307, // 0013 GETMET R4 R1 K7 + 0x88180100, // 0014 GETMBR R6 R0 K0 + 0x7C100400, // 0015 CALL R4 2 + 0x5C0C0800, // 0016 MOVE R3 R4 + 0x4C100000, // 0017 LDNIL R4 + 0x20100604, // 0018 NE R4 R3 R4 + 0x78120017, // 0019 JMPF R4 #0032 + 0x00100708, // 001A ADD R4 R3 K8 + 0x6014000C, // 001B GETGBL R5 G12 + 0x5C180200, // 001C MOVE R6 R1 + 0x7C140200, // 001D CALL R5 1 + 0x14100805, // 001E LT R4 R4 R5 + 0x78120011, // 001F JMPF R4 #0032 + 0x000C0708, // 0020 ADD R3 R3 K8 + 0x94100203, // 0021 GETIDX R4 R1 R3 + 0x90020004, // 0022 SETMBR R0 K0 R4 + 0x4C100000, // 0023 LDNIL R4 + 0x1C100404, // 0024 EQ R4 R2 R4 + 0x74120004, // 0025 JMPT R4 #002B + 0x88100100, // 0026 GETMBR R4 R0 K0 + 0x8C100909, // 0027 GETMET R4 R4 K9 + 0x7C100200, // 0028 CALL R4 1 + 0x1C100404, // 0029 EQ R4 R2 R4 + 0x78120005, // 002A JMPF R4 #0031 + 0x88100100, // 002B GETMBR R4 R0 K0 + 0x8C10090B, // 002C GETMET R4 R4 K11 + 0x7C100200, // 002D CALL R4 1 + 0x90021404, // 002E SETMBR R0 K10 R4 + 0x88100100, // 002F GETMBR R4 R0 K0 + 0x80040800, // 0030 RET 1 R4 + 0x7001FFE7, // 0031 JMP #001A + 0x50100000, // 0032 LDBOOL R4 0 0 + 0x90020004, // 0033 SETMBR R0 K0 R4 + 0x50100000, // 0034 LDBOOL R4 0 0 + 0x80040800, // 0035 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _next_attribute +********************************************************************/ +be_local_closure(Matter_PathGenerator__next_attribute, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(attribute), + /* K1 */ be_nested_str_weak(pi), + /* K2 */ be_nested_str_weak(get_attribute_list), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(path_in), + /* K5 */ be_nested_str_weak(find), + /* K6 */ be_const_int(1), + }), + be_str_weak(_next_attribute), + &be_const_str_solidified, + ( &(const binstruction[46]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x50080000, // 0001 LDBOOL R2 0 0 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x78060001, // 0003 JMPF R1 #0006 + 0x50040000, // 0004 LDBOOL R1 0 0 + 0x80040200, // 0005 RET 1 R1 + 0x88040101, // 0006 GETMBR R1 R0 K1 + 0x8C040302, // 0007 GETMET R1 R1 K2 + 0x880C0103, // 0008 GETMBR R3 R0 K3 + 0x7C040400, // 0009 CALL R1 2 + 0x88080104, // 000A GETMBR R2 R0 K4 + 0x88080500, // 000B GETMBR R2 R2 K0 + 0x540DFFFE, // 000C LDINT R3 -1 + 0x88100100, // 000D GETMBR R4 R0 K0 + 0x4C140000, // 000E LDNIL R5 + 0x20100805, // 000F NE R4 R4 R5 + 0x78120003, // 0010 JMPF R4 #0015 + 0x8C100305, // 0011 GETMET R4 R1 K5 + 0x88180100, // 0012 GETMBR R6 R0 K0 + 0x7C100400, // 0013 CALL R4 2 + 0x5C0C0800, // 0014 MOVE R3 R4 + 0x4C100000, // 0015 LDNIL R4 + 0x20100604, // 0016 NE R4 R3 R4 + 0x78120011, // 0017 JMPF R4 #002A + 0x00100706, // 0018 ADD R4 R3 K6 + 0x6014000C, // 0019 GETGBL R5 G12 + 0x5C180200, // 001A MOVE R6 R1 + 0x7C140200, // 001B CALL R5 1 + 0x14100805, // 001C LT R4 R4 R5 + 0x7812000B, // 001D JMPF R4 #002A + 0x000C0706, // 001E ADD R3 R3 K6 + 0x94100203, // 001F GETIDX R4 R1 R3 + 0x90020004, // 0020 SETMBR R0 K0 R4 + 0x4C100000, // 0021 LDNIL R4 + 0x1C100404, // 0022 EQ R4 R2 R4 + 0x74120002, // 0023 JMPT R4 #0027 + 0x88100100, // 0024 GETMBR R4 R0 K0 + 0x1C100404, // 0025 EQ R4 R2 R4 + 0x78120001, // 0026 JMPF R4 #0029 + 0x88100100, // 0027 GETMBR R4 R0 K0 + 0x80040800, // 0028 RET 1 R4 + 0x7001FFED, // 0029 JMP #0018 + 0x50100000, // 002A LDBOOL R4 0 0 + 0x90020004, // 002B SETMBR R0 K0 R4 + 0x50100000, // 002C LDBOOL R4 0 0 + 0x80040800, // 002D RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_PathGenerator +********************************************************************/ +be_local_class(Matter_PathGenerator, + 11, + NULL, + be_nested_map(19, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(_next_cluster, -1), be_const_closure(Matter_PathGenerator__next_cluster_closure) }, + { be_const_key_weak(_next_endpoint, -1), be_const_closure(Matter_PathGenerator__next_endpoint_closure) }, + { be_const_key_weak(endpoint_found, 0), be_const_var(7) }, + { be_const_key_weak(start, -1), be_const_closure(Matter_PathGenerator_start_closure) }, + { be_const_key_weak(session, -1), be_const_var(2) }, + { be_const_key_weak(get_pi, 12), be_const_closure(Matter_PathGenerator_get_pi_closure) }, + { be_const_key_weak(pi, -1), be_const_var(3) }, + { be_const_key_weak(attribute, 10), be_const_var(5) }, + { be_const_key_weak(cluster_found, 14), be_const_var(8) }, + { be_const_key_weak(device, -1), be_const_var(0) }, + { be_const_key_weak(attribute_found, -1), be_const_var(9) }, + { be_const_key_weak(clusters, -1), be_const_var(6) }, + { be_const_key_weak(path_in, -1), be_const_var(1) }, + { be_const_key_weak(init, 11), be_const_closure(Matter_PathGenerator_init_closure) }, + { be_const_key_weak(path_concrete, -1), be_const_var(10) }, + { be_const_key_weak(next, 9), be_const_closure(Matter_PathGenerator_next_closure) }, + { be_const_key_weak(cluster, 4), be_const_var(4) }, + { be_const_key_weak(reset, 1), be_const_closure(Matter_PathGenerator_reset_closure) }, + { be_const_key_weak(_next_attribute, -1), be_const_closure(Matter_PathGenerator__next_attribute_closure) }, + })), + be_str_weak(Matter_PathGenerator) +); +/*******************************************************************/ + +void be_load_Matter_PathGenerator_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_PathGenerator); + be_setglobal(vm, "Matter_PathGenerator"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_0.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_0.h index 6969dce2d..6366601bd 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_0.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_0.h @@ -69,26 +69,23 @@ be_local_closure(Matter_Plugin_every_250ms, /* name */ /******************************************************************** -** Solidified function: consolidate_clusters +** Solidified function: parse_configuration ********************************************************************/ -be_local_closure(Matter_Plugin_consolidate_clusters, /* name */ +be_local_closure(Matter_Plugin_parse_configuration, /* name */ be_nested_proto( 2, /* nstack */ - 1, /* argc */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(CLUSTERS), - }), - be_str_weak(consolidate_clusters), + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(parse_configuration), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 }) ) ); @@ -228,26 +225,23 @@ be_local_closure(Matter_Plugin_subscribe_event, /* name */ /******************************************************************** -** Solidified function: get_name +** Solidified function: parse_sensors ********************************************************************/ -be_local_closure(Matter_Plugin_get_name, /* name */ +be_local_closure(Matter_Plugin_parse_sensors, /* name */ be_nested_proto( 2, /* nstack */ - 1, /* argc */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(node_label), - }), - be_str_weak(get_name), + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(parse_sensors), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 }) ) ); @@ -333,46 +327,6 @@ be_local_closure(Matter_Plugin_publish_command, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: ui_conf_to_string -********************************************************************/ -be_local_closure(Matter_Plugin_ui_conf_to_string, /* name */ - be_nested_proto( - 9, /* nstack */ - 2, /* argc */ - 4, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_const_class(be_class_Matter_Plugin), - /* K1 */ be_nested_str_weak(ARG), - /* K2 */ be_nested_str_weak(find), - /* K3 */ be_nested_str_weak(), - }), - be_str_weak(ui_conf_to_string), - &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ - 0x58080000, // 0000 LDCONST R2 K0 - 0x880C0101, // 0001 GETMBR R3 R0 K1 - 0x780E0006, // 0002 JMPF R3 #000A - 0x60100008, // 0003 GETGBL R4 G8 - 0x8C140302, // 0004 GETMET R5 R1 K2 - 0x5C1C0600, // 0005 MOVE R7 R3 - 0x58200003, // 0006 LDCONST R8 K3 - 0x7C140600, // 0007 CALL R5 3 - 0x7C100200, // 0008 CALL R4 1 - 0x70020000, // 0009 JMP #000B - 0x58100003, // 000A LDCONST R4 K3 - 0x80040800, // 000B RET 1 R4 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -400,7 +354,7 @@ be_local_closure(Matter_Plugin_read_attribute, /* name */ /* K10 */ be_nested_str_weak(U2), /* K11 */ be_const_int(1), /* K12 */ be_nested_str_weak(stop_iteration), - /* K13 */ be_nested_str_weak(get_cluster_list), + /* K13 */ be_nested_str_weak(get_cluster_list_sorted), /* K14 */ be_nested_str_weak(U4), /* K15 */ be_const_int(2), /* K16 */ be_const_int(3), @@ -412,7 +366,7 @@ be_local_closure(Matter_Plugin_read_attribute, /* name */ }), be_str_weak(read_attribute), &be_const_str_solidified, - ( &(const binstruction[160]) { /* code */ + ( &(const binstruction[161]) { /* code */ 0xB8120000, // 0000 GETNGBL R4 K0 0x88100901, // 0001 GETMBR R4 R4 K1 0x88140502, // 0002 GETMBR R5 R2 K2 @@ -572,7 +526,8 @@ be_local_closure(Matter_Plugin_read_attribute, /* name */ 0x5C2C0E00, // 009C MOVE R11 R7 0x7C200600, // 009D CALL R8 3 0x80041000, // 009E RET 1 R8 - 0x80000000, // 009F RET 0 + 0x4C1C0000, // 009F LDNIL R7 + 0x80040E00, // 00A0 RET 1 R7 }) ) ); @@ -580,41 +535,64 @@ be_local_closure(Matter_Plugin_read_attribute, /* name */ /******************************************************************** -** Solidified function: ack_request +** Solidified function: ui_conf_to_string ********************************************************************/ -be_local_closure(Matter_Plugin_ack_request, /* name */ +be_local_closure(Matter_Plugin_ui_conf_to_string, /* name */ be_nested_proto( - 6, /* nstack */ + 9, /* nstack */ 2, /* argc */ - 2, /* varg */ + 4, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(msg), - /* K1 */ be_nested_str_weak(device), - /* K2 */ be_nested_str_weak(message_handler), - /* K3 */ be_nested_str_weak(im), - /* K4 */ be_nested_str_weak(send_ack_now), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Plugin), + /* K1 */ be_nested_str_weak(ARG), + /* K2 */ be_nested_str_weak(find), + /* K3 */ be_nested_str_weak(), }), - be_str_weak(ack_request), + be_str_weak(ui_conf_to_string), &be_const_str_solidified, - ( &(const binstruction[13]) { /* code */ - 0x88080300, // 0000 GETMBR R2 R1 K0 - 0x4C0C0000, // 0001 LDNIL R3 - 0x200C0403, // 0002 NE R3 R2 R3 - 0x780E0005, // 0003 JMPF R3 #000A - 0x880C0101, // 0004 GETMBR R3 R0 K1 - 0x880C0702, // 0005 GETMBR R3 R3 K2 - 0x880C0703, // 0006 GETMBR R3 R3 K3 - 0x8C0C0704, // 0007 GETMET R3 R3 K4 - 0x5C140400, // 0008 MOVE R5 R2 - 0x7C0C0400, // 0009 CALL R3 2 - 0x4C0C0000, // 000A LDNIL R3 - 0x90060003, // 000B SETMBR R1 K0 R3 - 0x80000000, // 000C RET 0 + ( &(const binstruction[12]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0x880C0101, // 0001 GETMBR R3 R0 K1 + 0x780E0006, // 0002 JMPF R3 #000A + 0x60100008, // 0003 GETGBL R4 G8 + 0x8C140302, // 0004 GETMET R5 R1 K2 + 0x5C1C0600, // 0005 MOVE R7 R3 + 0x58200003, // 0006 LDCONST R8 K3 + 0x7C140600, // 0007 CALL R5 3 + 0x7C100200, // 0008 CALL R4 1 + 0x70020000, // 0009 JMP #000B + 0x58100003, // 000A LDCONST R4 K3 + 0x80040800, // 000B RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: write_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_write_attribute, /* name */ + be_nested_proto( + 5, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(write_attribute), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C100000, // 0000 LDNIL R4 + 0x80040800, // 0001 RET 1 R4 }) ) ); @@ -680,23 +658,41 @@ be_local_closure(Matter_Plugin_read_event, /* name */ /******************************************************************** -** Solidified function: parse_configuration +** Solidified function: ack_request ********************************************************************/ -be_local_closure(Matter_Plugin_parse_configuration, /* name */ +be_local_closure(Matter_Plugin_ack_request, /* name */ be_nested_proto( - 2, /* nstack */ + 6, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(parse_configuration), + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(msg), + /* K1 */ be_nested_str_weak(device), + /* K2 */ be_nested_str_weak(message_handler), + /* K3 */ be_nested_str_weak(im), + /* K4 */ be_nested_str_weak(send_ack_now), + }), + be_str_weak(ack_request), &be_const_str_solidified, - ( &(const binstruction[ 1]) { /* code */ - 0x80000000, // 0000 RET 0 + ( &(const binstruction[13]) { /* code */ + 0x88080300, // 0000 GETMBR R2 R1 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x200C0403, // 0002 NE R3 R2 R3 + 0x780E0005, // 0003 JMPF R3 #000A + 0x880C0101, // 0004 GETMBR R3 R0 K1 + 0x880C0702, // 0005 GETMBR R3 R3 K2 + 0x880C0703, // 0006 GETMBR R3 R3 K3 + 0x8C0C0704, // 0007 GETMET R3 R3 K4 + 0x5C140400, // 0008 MOVE R5 R2 + 0x7C0C0400, // 0009 CALL R3 2 + 0x4C0C0000, // 000A LDNIL R3 + 0x90060003, // 000B SETMBR R1 K0 R3 + 0x80000000, // 000C RET 0 }) ) ); @@ -704,11 +700,11 @@ be_local_closure(Matter_Plugin_parse_configuration, /* name */ /******************************************************************** -** Solidified function: consolidate_update_commands +** Solidified function: get_cluster_list_sorted ********************************************************************/ -be_local_closure(Matter_Plugin_consolidate_update_commands, /* name */ +be_local_closure(Matter_Plugin_get_cluster_list_sorted, /* name */ be_nested_proto( - 2, /* nstack */ + 4, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -716,14 +712,19 @@ be_local_closure(Matter_Plugin_consolidate_update_commands, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(UPDATE_COMMANDS), + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(k2l), + /* K2 */ be_nested_str_weak(clusters), }), - be_str_weak(consolidate_update_commands), + be_str_weak(get_cluster_list_sorted), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ + ( &(const binstruction[ 5]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x7C040400, // 0003 CALL R1 2 + 0x80040200, // 0004 RET 1 R1 }) ) ); @@ -817,6 +818,89 @@ be_local_closure(Matter_Plugin_get_endpoint, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: update_shadow +********************************************************************/ +be_local_closure(Matter_Plugin_update_shadow, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(tick), + /* K1 */ be_nested_str_weak(device), + }), + be_str_weak(update_shadow), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x88040101, // 0000 GETMBR R1 R0 K1 + 0x88040300, // 0001 GETMBR R1 R1 K0 + 0x90020001, // 0002 SETMBR R0 K0 R1 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: consolidate_update_commands +********************************************************************/ +be_local_closure(Matter_Plugin_consolidate_update_commands, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(UPDATE_COMMANDS), + }), + be_str_weak(consolidate_update_commands), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: append_state_json +********************************************************************/ +be_local_closure(Matter_Plugin_append_state_json, /* name */ + be_nested_proto( + 1, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(), + }), + be_str_weak(append_state_json), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80060000, // 0000 RET 1 K0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: state_json ********************************************************************/ @@ -874,61 +958,6 @@ be_local_closure(Matter_Plugin_state_json, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: update_shadow -********************************************************************/ -be_local_closure(Matter_Plugin_update_shadow, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(tick), - /* K1 */ be_nested_str_weak(device), - }), - be_str_weak(update_shadow), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x88040101, // 0000 GETMBR R1 R0 K1 - 0x88040300, // 0001 GETMBR R1 R1 K0 - 0x90020001, // 0002 SETMBR R0 K0 R1 - 0x80000000, // 0003 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: write_attribute -********************************************************************/ -be_local_closure(Matter_Plugin_write_attribute, /* name */ - be_nested_proto( - 5, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(write_attribute), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x4C100000, // 0000 LDNIL R4 - 0x80040800, // 0001 RET 1 R4 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: has ********************************************************************/ @@ -1060,11 +1089,11 @@ be_local_closure(Matter_Plugin_update_virtual, /* name */ /******************************************************************** -** Solidified function: append_state_json +** Solidified function: consolidate_clusters ********************************************************************/ -be_local_closure(Matter_Plugin_append_state_json, /* name */ +be_local_closure(Matter_Plugin_consolidate_clusters, /* name */ be_nested_proto( - 1, /* nstack */ + 2, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1073,12 +1102,13 @@ be_local_closure(Matter_Plugin_append_state_json, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(), + /* K0 */ be_nested_str_weak(CLUSTERS), }), - be_str_weak(append_state_json), + be_str_weak(consolidate_clusters), &be_const_str_solidified, - ( &(const binstruction[ 1]) { /* code */ - 0x80060000, // 0000 RET 1 K0 + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 }) ) ); @@ -1136,23 +1166,26 @@ be_local_closure(Matter_Plugin_contains_attribute, /* name */ /******************************************************************** -** Solidified function: parse_sensors +** Solidified function: get_name ********************************************************************/ -be_local_closure(Matter_Plugin_parse_sensors, /* name */ +be_local_closure(Matter_Plugin_get_name, /* name */ be_nested_proto( 2, /* nstack */ - 2, /* argc */ + 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(parse_sensors), + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(node_label), + }), + be_str_weak(get_name), &be_const_str_solidified, - ( &(const binstruction[ 1]) { /* code */ - 0x80000000, // 0000 RET 0 + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 }) ) ); @@ -1242,52 +1275,6 @@ be_local_closure(Matter_Plugin_is_local_device, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: get_cluster_list -********************************************************************/ -be_local_closure(Matter_Plugin_get_cluster_list, /* name */ - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(clusters), - /* K1 */ be_nested_str_weak(keys), - /* K2 */ be_nested_str_weak(push), - /* K3 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(get_cluster_list), - &be_const_str_solidified, - ( &(const binstruction[18]) { /* code */ - 0x60040012, // 0000 GETGBL R1 G18 - 0x7C040000, // 0001 CALL R1 0 - 0x60080010, // 0002 GETGBL R2 G16 - 0x880C0100, // 0003 GETMBR R3 R0 K0 - 0x8C0C0701, // 0004 GETMET R3 R3 K1 - 0x7C0C0200, // 0005 CALL R3 1 - 0x7C080200, // 0006 CALL R2 1 - 0xA8020005, // 0007 EXBLK 0 #000E - 0x5C0C0400, // 0008 MOVE R3 R2 - 0x7C0C0000, // 0009 CALL R3 0 - 0x8C100302, // 000A GETMET R4 R1 K2 - 0x5C180600, // 000B MOVE R6 R3 - 0x7C100400, // 000C CALL R4 2 - 0x7001FFF9, // 000D JMP #0008 - 0x58080003, // 000E LDCONST R2 K3 - 0xAC080200, // 000F CATCH R2 1 0 - 0xB0080000, // 0010 RAISE 2 R0 R0 - 0x80040200, // 0011 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: ui_string_to_conf ********************************************************************/ @@ -1342,10 +1329,14 @@ be_local_class(Matter_Plugin, { be_const_key_int(49, -1), be_const_int(4) }, })) ) } )) }, { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_read_attribute_closure) }, - { be_const_key_weak(subscribe_attribute, 31), be_const_closure(Matter_Plugin_subscribe_attribute_closure) }, + { be_const_key_weak(subscribe_attribute, 33), be_const_closure(Matter_Plugin_subscribe_attribute_closure) }, { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_init_closure) }, { be_const_key_weak(UPDATE_TIME, -1), be_const_int(5000) }, - { be_const_key_weak(set_name, 36), be_const_closure(Matter_Plugin_set_name_closure) }, + { be_const_key_weak(COMMANDS, 21), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(29, -1), be_const_nil() }, + })) ) } )) }, { be_const_key_weak(endpoint, -1), be_const_var(2) }, { be_const_key_weak(UPDATE_COMMANDS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(0, @@ -1354,9 +1345,9 @@ be_local_class(Matter_Plugin, { be_const_key_weak(VIRTUAL, -1), be_const_bool(0) }, { be_const_key_weak(device, -1), be_const_var(1) }, { be_const_key_weak(subscribe_event, 3), be_const_closure(Matter_Plugin_subscribe_event_closure) }, - { be_const_key_weak(read_event, -1), be_const_closure(Matter_Plugin_read_event_closure) }, + { be_const_key_weak(clusters, -1), be_const_var(3) }, { be_const_key_weak(publish_command, -1), be_const_closure(Matter_Plugin_publish_command_closure) }, - { be_const_key_weak(is_local_device, 21), be_const_closure(Matter_Plugin_is_local_device_closure) }, + { be_const_key_weak(is_local_device, 29), be_const_closure(Matter_Plugin_is_local_device_closure) }, { be_const_key_weak(CLUSTER_REVISIONS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(25, ( (struct bmapnode*) &(const bmapnode[]) { @@ -1387,12 +1378,12 @@ be_local_class(Matter_Plugin, { be_const_key_int(1024, -1), be_const_int(3) }, })) ) } )) }, { be_const_key_weak(contains_cluster, -1), be_const_closure(Matter_Plugin_contains_cluster_closure) }, - { be_const_key_weak(parse_configuration, -1), be_const_closure(Matter_Plugin_parse_configuration_closure) }, - { be_const_key_weak(get_attribute_list, 33), be_const_closure(Matter_Plugin_get_attribute_list_closure) }, - { be_const_key_weak(consolidate_clusters, 13), be_const_closure(Matter_Plugin_consolidate_clusters_closure) }, - { be_const_key_weak(parse_sensors, 23), be_const_closure(Matter_Plugin_parse_sensors_closure) }, - { be_const_key_weak(contains_attribute, 29), be_const_closure(Matter_Plugin_contains_attribute_closure) }, - { be_const_key_weak(append_state_json, -1), be_const_closure(Matter_Plugin_append_state_json_closure) }, + { be_const_key_weak(ack_request, -1), be_const_closure(Matter_Plugin_ack_request_closure) }, + { be_const_key_weak(parse_configuration, 34), be_const_closure(Matter_Plugin_parse_configuration_closure) }, + { be_const_key_weak(read_event, 28), be_const_closure(Matter_Plugin_read_event_closure) }, + { be_const_key_weak(get_name, 43), be_const_closure(Matter_Plugin_get_name_closure) }, + { be_const_key_weak(contains_attribute, 31), be_const_closure(Matter_Plugin_contains_attribute_closure) }, + { be_const_key_weak(get_cluster_list_sorted, -1), be_const_closure(Matter_Plugin_get_cluster_list_sorted_closure) }, { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { @@ -1412,32 +1403,28 @@ be_local_class(Matter_Plugin, })) ) } )) }, })) ) } )) }, { be_const_key_weak(attribute_updated, -1), be_const_closure(Matter_Plugin_attribute_updated_closure) }, - { be_const_key_weak(timed_request, 41), be_const_closure(Matter_Plugin_timed_request_closure) }, + { be_const_key_weak(timed_request, 13), be_const_closure(Matter_Plugin_timed_request_closure) }, { be_const_key_weak(get_endpoint, -1), be_const_closure(Matter_Plugin_get_endpoint_closure) }, - { be_const_key_weak(update_next, 43), be_const_var(0) }, + { be_const_key_weak(consolidate_clusters, -1), be_const_closure(Matter_Plugin_consolidate_clusters_closure) }, + { be_const_key_weak(append_state_json, 18), be_const_closure(Matter_Plugin_append_state_json_closure) }, + { be_const_key_weak(ui_conf_to_string, 41), be_const_static_closure(Matter_Plugin_ui_conf_to_string_closure) }, { be_const_key_weak(TYPE, 32), be_nested_str_weak() }, - { be_const_key_weak(ui_conf_to_string, 28), be_const_static_closure(Matter_Plugin_ui_conf_to_string_closure) }, + { be_const_key_weak(state_json, -1), be_const_closure(Matter_Plugin_state_json_closure) }, { be_const_key_weak(tick, -1), be_const_var(4) }, - { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_update_shadow_closure) }, - { be_const_key_weak(ARG, 18), be_nested_str_weak() }, + { be_const_key_weak(ARG, 47), be_nested_str_weak() }, + { be_const_key_weak(write_attribute, 36), be_const_closure(Matter_Plugin_write_attribute_closure) }, { be_const_key_weak(has, -1), be_const_closure(Matter_Plugin_has_closure) }, - { be_const_key_weak(write_attribute, 34), be_const_closure(Matter_Plugin_write_attribute_closure) }, - { be_const_key_weak(COMMANDS, 42), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(29, -1), be_const_nil() }, - })) ) } )) }, { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_invoke_request_closure) }, { be_const_key_weak(update_shadow_lazy, -1), be_const_closure(Matter_Plugin_update_shadow_lazy_closure) }, - { be_const_key_weak(state_json, 22), be_const_closure(Matter_Plugin_state_json_closure) }, + { be_const_key_weak(update_shadow, 22), be_const_closure(Matter_Plugin_update_shadow_closure) }, { be_const_key_weak(update_virtual, -1), be_const_closure(Matter_Plugin_update_virtual_closure) }, - { be_const_key_weak(clusters, -1), be_const_var(3) }, - { be_const_key_weak(get_name, -1), be_const_closure(Matter_Plugin_get_name_closure) }, - { be_const_key_weak(node_label, -1), be_const_var(5) }, + { be_const_key_weak(node_label, 42), be_const_var(5) }, + { be_const_key_weak(update_next, -1), be_const_var(0) }, + { be_const_key_weak(set_name, -1), be_const_closure(Matter_Plugin_set_name_closure) }, { be_const_key_weak(ARG_TYPE, -1), be_const_static_closure(Matter_Plugin__X3Clambda_X3E_closure) }, { be_const_key_weak(ARG_HINT, 17), be_nested_str_weak(_Not_X20used_) }, - { be_const_key_weak(ack_request, 15), be_const_closure(Matter_Plugin_ack_request_closure) }, - { be_const_key_weak(get_cluster_list, -1), be_const_closure(Matter_Plugin_get_cluster_list_closure) }, + { be_const_key_weak(parse_sensors, 15), be_const_closure(Matter_Plugin_parse_sensors_closure) }, + { be_const_key_weak(get_attribute_list, -1), be_const_closure(Matter_Plugin_get_attribute_list_closure) }, { be_const_key_weak(ui_string_to_conf, -1), be_const_static_closure(Matter_Plugin_ui_string_to_conf_closure) }, { be_const_key_weak(consolidate_update_commands, 2), be_const_closure(Matter_Plugin_consolidate_update_commands_closure) }, })), diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_1_Root.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_1_Root.h index 81040d471..8c616f0c6 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_1_Root.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_1_Root.h @@ -81,43 +81,43 @@ be_local_closure(Matter_Plugin_Root_read_attribute, /* name */ /* K58 */ be_nested_str_weak(B2), /* K59 */ be_nested_str_weak(get_noc), /* K60 */ be_nested_str_weak(get_icac), - /* K61 */ be_nested_str_weak(AGGREGATOR_ENDPOINT), - /* K62 */ be_nested_str_weak(get_fabric_index), - /* K63 */ be_nested_str_weak(stop_iteration), - /* K64 */ be_nested_str_weak(parse), - /* K65 */ be_nested_str_weak(get_ca), - /* K66 */ be_nested_str_weak(findsubval), - /* K67 */ be_nested_str_weak(get_admin_vendor), - /* K68 */ be_nested_str_weak(get_fabric_id_as_int64), - /* K69 */ be_nested_str_weak(get_device_id_as_int64), - /* K70 */ be_nested_str_weak(get_fabric_label), - /* K71 */ be_nested_str_weak(Fabric), - /* K72 */ be_nested_str_weak(_MAX_CASE), - /* K73 */ be_nested_str_weak(count_active_fabrics), - /* K74 */ be_nested_str_weak(_fabric), - /* K75 */ be_nested_str_weak(is_commissioning_open), - /* K76 */ be_nested_str_weak(is_root_commissioning_open), - /* K77 */ be_nested_str_weak(commissioning_admin_fabric), - /* K78 */ be_nested_str_weak(Tasmota), - /* K79 */ be_nested_str_weak(vendorid), - /* K80 */ be_nested_str_weak(DeviceName), - /* K81 */ be_nested_str_weak(FriendlyName), - /* K82 */ be_nested_str_weak(FriendlyName1), - /* K83 */ be_nested_str_weak(XX), - /* K84 */ be_nested_str_weak(Status_X202), - /* K85 */ be_nested_str_weak(StatusFWR), - /* K86 */ be_nested_str_weak(Hardware), - /* K87 */ be_nested_str_weak(Version), - /* K88 */ be_nested_str_weak(_X28), - /* K89 */ be_nested_str_weak(locale), - /* K90 */ be_nested_str_weak(create_TLV), - /* K91 */ be_nested_str_weak(get_active_endpoints), - /* K92 */ be_nested_str_weak(disable_bridge_mode), + /* K61 */ be_nested_str_weak(get_fabric_index), + /* K62 */ be_nested_str_weak(stop_iteration), + /* K63 */ be_nested_str_weak(parse), + /* K64 */ be_nested_str_weak(get_ca), + /* K65 */ be_nested_str_weak(findsubval), + /* K66 */ be_nested_str_weak(get_admin_vendor), + /* K67 */ be_nested_str_weak(get_fabric_id_as_int64), + /* K68 */ be_nested_str_weak(get_device_id_as_int64), + /* K69 */ be_nested_str_weak(get_fabric_label), + /* K70 */ be_nested_str_weak(Fabric), + /* K71 */ be_nested_str_weak(_MAX_CASE), + /* K72 */ be_nested_str_weak(count_active_fabrics), + /* K73 */ be_nested_str_weak(_fabric), + /* K74 */ be_nested_str_weak(is_commissioning_open), + /* K75 */ be_nested_str_weak(is_root_commissioning_open), + /* K76 */ be_nested_str_weak(commissioning_admin_fabric), + /* K77 */ be_nested_str_weak(Tasmota), + /* K78 */ be_nested_str_weak(vendorid), + /* K79 */ be_nested_str_weak(DeviceName), + /* K80 */ be_nested_str_weak(FriendlyName), + /* K81 */ be_nested_str_weak(FriendlyName1), + /* K82 */ be_nested_str_weak(XX), + /* K83 */ be_nested_str_weak(Status_X202), + /* K84 */ be_nested_str_weak(StatusFWR), + /* K85 */ be_nested_str_weak(Hardware), + /* K86 */ be_nested_str_weak(Version), + /* K87 */ be_nested_str_weak(_X28), + /* K88 */ be_nested_str_weak(locale), + /* K89 */ be_nested_str_weak(create_TLV), + /* K90 */ be_nested_str_weak(get_active_endpoints), + /* K91 */ be_nested_str_weak(disable_bridge_mode), + /* K92 */ be_nested_str_weak(AGGREGATOR_ENDPOINT), /* K93 */ be_nested_str_weak(read_attribute), }), be_str_weak(read_attribute), &be_const_str_solidified, - ( &(const binstruction[937]) { /* code */ + ( &(const binstruction[936]) { /* code */ 0xA4120000, // 0000 IMPORT R4 K0 0xB8160200, // 0001 GETNGBL R5 K1 0x88140B02, // 0002 GETMBR R5 R5 K2 @@ -174,11 +174,11 @@ be_local_closure(Matter_Plugin_Root_read_attribute, /* name */ 0x502C0000, // 0035 LDBOOL R11 0 0 0x7C200600, // 0036 CALL R8 3 0x80041000, // 0037 RET 1 R8 - 0x70020366, // 0038 JMP #03A0 + 0x70020365, // 0038 JMP #039F 0x54220031, // 0039 LDINT R8 50 0x1C200C08, // 003A EQ R8 R6 R8 0x78220000, // 003B JMPF R8 #003D - 0x70020362, // 003C JMP #03A0 + 0x70020361, // 003C JMP #039F 0x54220032, // 003D LDINT R8 51 0x1C200C08, // 003E EQ R8 R6 R8 0x782200DC, // 003F JMPF R8 #011D @@ -402,11 +402,11 @@ be_local_closure(Matter_Plugin_Root_read_attribute, /* name */ 0x502C0000, // 0119 LDBOOL R11 0 0 0x7C200600, // 011A CALL R8 3 0x80041000, // 011B RET 1 R8 - 0x70020282, // 011C JMP #03A0 + 0x70020281, // 011C JMP #039F 0x54220033, // 011D LDINT R8 52 0x1C200C08, // 011E EQ R8 R6 R8 0x78220000, // 011F JMPF R8 #0121 - 0x7002027E, // 0120 JMP #03A0 + 0x7002027D, // 0120 JMP #039F 0x54220037, // 0121 LDINT R8 56 0x1C200C08, // 0122 EQ R8 R6 R8 0x7822002B, // 0123 JMPF R8 #0150 @@ -453,15 +453,15 @@ be_local_closure(Matter_Plugin_Root_read_attribute, /* name */ 0x5C301000, // 014C MOVE R12 R8 0x7C240600, // 014D CALL R9 3 0x80041200, // 014E RET 1 R9 - 0x7002024F, // 014F JMP #03A0 + 0x7002024E, // 014F JMP #039F 0x5422003D, // 0150 LDINT R8 62 0x1C200C08, // 0151 EQ R8 R6 R8 - 0x782200B6, // 0152 JMPF R8 #020A + 0x782200B5, // 0152 JMPF R8 #0209 0x8C200133, // 0153 GETMET R8 R0 K51 0x5C280400, // 0154 MOVE R10 R2 0x7C200400, // 0155 CALL R8 2 0x1C200F05, // 0156 EQ R8 R7 K5 - 0x78220037, // 0157 JMPF R8 #0190 + 0x78220036, // 0157 JMPF R8 #018F 0x8C200B11, // 0158 GETMET R8 R5 K17 0x7C200200, // 0159 CALL R8 1 0x88240534, // 015A GETMBR R9 R2 K52 @@ -479,7 +479,7 @@ be_local_closure(Matter_Plugin_Root_read_attribute, /* name */ 0x60280010, // 0166 GETGBL R10 G16 0x5C2C1200, // 0167 MOVE R11 R9 0x7C280200, // 0168 CALL R10 1 - 0xA8020020, // 0169 EXBLK 0 #018B + 0xA802001F, // 0169 EXBLK 0 #018A 0x5C2C1400, // 016A MOVE R11 R10 0x7C2C0000, // 016B CALL R11 0 0x8C301739, // 016C GETMET R12 R11 K57 @@ -506,555 +506,554 @@ be_local_closure(Matter_Plugin_Root_read_attribute, /* name */ 0x7C440200, // 0181 CALL R17 1 0x7C340800, // 0182 CALL R13 4 0x8C34190B, // 0183 GETMET R13 R12 K11 - 0xB83E0200, // 0184 GETNGBL R15 K1 - 0x883C1F3D, // 0185 GETMBR R15 R15 K61 - 0x88400B0C, // 0186 GETMBR R16 R5 K12 - 0x8C44173E, // 0187 GETMET R17 R11 K62 - 0x7C440200, // 0188 CALL R17 1 - 0x7C340800, // 0189 CALL R13 4 - 0x7001FFDE, // 018A JMP #016A - 0x5828003F, // 018B LDCONST R10 K63 - 0xAC280200, // 018C CATCH R10 1 0 - 0xB0080000, // 018D RAISE 2 R0 R0 - 0x80041000, // 018E RET 1 R8 - 0x70020078, // 018F JMP #0209 - 0x1C200F09, // 0190 EQ R8 R7 K9 - 0x7822004D, // 0191 JMPF R8 #01E0 - 0x8C200B11, // 0192 GETMET R8 R5 K17 - 0x7C200200, // 0193 CALL R8 1 - 0x88240534, // 0194 GETMBR R9 R2 K52 - 0x78260005, // 0195 JMPF R9 #019C - 0x60240012, // 0196 GETGBL R9 G18 - 0x7C240000, // 0197 CALL R9 0 - 0x8C280335, // 0198 GETMET R10 R1 K53 - 0x7C280200, // 0199 CALL R10 1 - 0x4028120A, // 019A CONNECT R10 R9 R10 - 0x70020003, // 019B JMP #01A0 - 0x88240136, // 019C GETMBR R9 R0 K54 - 0x88241337, // 019D GETMBR R9 R9 K55 - 0x8C241338, // 019E GETMET R9 R9 K56 - 0x7C240200, // 019F CALL R9 1 - 0x60280010, // 01A0 GETGBL R10 G16 - 0x5C2C1200, // 01A1 MOVE R11 R9 - 0x7C280200, // 01A2 CALL R10 1 - 0xA8020036, // 01A3 EXBLK 0 #01DB - 0x5C2C1400, // 01A4 MOVE R11 R10 - 0x7C2C0000, // 01A5 CALL R11 0 - 0x4C300000, // 01A6 LDNIL R12 - 0x1C30160C, // 01A7 EQ R12 R11 R12 - 0x78320000, // 01A8 JMPF R12 #01AA - 0x7001FFF9, // 01A9 JMP #01A4 - 0x8C301739, // 01AA GETMET R12 R11 K57 - 0x7C300200, // 01AB CALL R12 1 - 0x78320000, // 01AC JMPF R12 #01AE - 0x7001FFF5, // 01AD JMP #01A4 - 0x8C300B40, // 01AE GETMET R12 R5 K64 - 0x8C381741, // 01AF GETMET R14 R11 K65 - 0x7C380200, // 01B0 CALL R14 1 - 0x7C300400, // 01B1 CALL R12 2 - 0x8C341115, // 01B2 GETMET R13 R8 K21 - 0x4C3C0000, // 01B3 LDNIL R15 - 0x7C340400, // 01B4 CALL R13 2 - 0x8C381B0B, // 01B5 GETMET R14 R13 K11 - 0x58400009, // 01B6 LDCONST R16 K9 - 0x88440B3A, // 01B7 GETMBR R17 R5 K58 - 0x8C481942, // 01B8 GETMET R18 R12 K66 - 0x54520008, // 01B9 LDINT R20 9 - 0x7C480400, // 01BA CALL R18 2 - 0x7C380800, // 01BB CALL R14 4 - 0x8C381B0B, // 01BC GETMET R14 R13 K11 - 0x5840000D, // 01BD LDCONST R16 K13 - 0x88440B0C, // 01BE GETMBR R17 R5 K12 - 0x8C481743, // 01BF GETMET R18 R11 K67 - 0x7C480200, // 01C0 CALL R18 1 - 0x7C380800, // 01C1 CALL R14 4 - 0x8C381B0B, // 01C2 GETMET R14 R13 K11 - 0x5840000F, // 01C3 LDCONST R16 K15 - 0x88440B07, // 01C4 GETMBR R17 R5 K7 - 0x8C481744, // 01C5 GETMET R18 R11 K68 - 0x7C480200, // 01C6 CALL R18 1 - 0x7C380800, // 01C7 CALL R14 4 - 0x8C381B0B, // 01C8 GETMET R14 R13 K11 - 0x54420003, // 01C9 LDINT R16 4 - 0x88440B07, // 01CA GETMBR R17 R5 K7 - 0x8C481745, // 01CB GETMET R18 R11 K69 - 0x7C480200, // 01CC CALL R18 1 - 0x7C380800, // 01CD CALL R14 4 - 0x8C381B0B, // 01CE GETMET R14 R13 K11 - 0x54420004, // 01CF LDINT R16 5 - 0x88440B16, // 01D0 GETMBR R17 R5 K22 - 0x8C481746, // 01D1 GETMET R18 R11 K70 - 0x7C480200, // 01D2 CALL R18 1 - 0x7C380800, // 01D3 CALL R14 4 - 0x8C381B0B, // 01D4 GETMET R14 R13 K11 - 0x544200FD, // 01D5 LDINT R16 254 - 0x88440B0C, // 01D6 GETMBR R17 R5 K12 - 0x8C48173E, // 01D7 GETMET R18 R11 K62 - 0x7C480200, // 01D8 CALL R18 1 - 0x7C380800, // 01D9 CALL R14 4 - 0x7001FFC8, // 01DA JMP #01A4 - 0x5828003F, // 01DB LDCONST R10 K63 - 0xAC280200, // 01DC CATCH R10 1 0 - 0xB0080000, // 01DD RAISE 2 R0 R0 - 0x80041000, // 01DE RET 1 R8 - 0x70020028, // 01DF JMP #0209 - 0x1C200F0D, // 01E0 EQ R8 R7 K13 - 0x78220007, // 01E1 JMPF R8 #01EA - 0x8C200706, // 01E2 GETMET R8 R3 K6 - 0x88280B0E, // 01E3 GETMBR R10 R5 K14 - 0xB82E0200, // 01E4 GETNGBL R11 K1 + 0x543E00FD, // 0184 LDINT R15 254 + 0x88400B0C, // 0185 GETMBR R16 R5 K12 + 0x8C44173D, // 0186 GETMET R17 R11 K61 + 0x7C440200, // 0187 CALL R17 1 + 0x7C340800, // 0188 CALL R13 4 + 0x7001FFDF, // 0189 JMP #016A + 0x5828003E, // 018A LDCONST R10 K62 + 0xAC280200, // 018B CATCH R10 1 0 + 0xB0080000, // 018C RAISE 2 R0 R0 + 0x80041000, // 018D RET 1 R8 + 0x70020078, // 018E JMP #0208 + 0x1C200F09, // 018F EQ R8 R7 K9 + 0x7822004D, // 0190 JMPF R8 #01DF + 0x8C200B11, // 0191 GETMET R8 R5 K17 + 0x7C200200, // 0192 CALL R8 1 + 0x88240534, // 0193 GETMBR R9 R2 K52 + 0x78260005, // 0194 JMPF R9 #019B + 0x60240012, // 0195 GETGBL R9 G18 + 0x7C240000, // 0196 CALL R9 0 + 0x8C280335, // 0197 GETMET R10 R1 K53 + 0x7C280200, // 0198 CALL R10 1 + 0x4028120A, // 0199 CONNECT R10 R9 R10 + 0x70020003, // 019A JMP #019F + 0x88240136, // 019B GETMBR R9 R0 K54 + 0x88241337, // 019C GETMBR R9 R9 K55 + 0x8C241338, // 019D GETMET R9 R9 K56 + 0x7C240200, // 019E CALL R9 1 + 0x60280010, // 019F GETGBL R10 G16 + 0x5C2C1200, // 01A0 MOVE R11 R9 + 0x7C280200, // 01A1 CALL R10 1 + 0xA8020036, // 01A2 EXBLK 0 #01DA + 0x5C2C1400, // 01A3 MOVE R11 R10 + 0x7C2C0000, // 01A4 CALL R11 0 + 0x4C300000, // 01A5 LDNIL R12 + 0x1C30160C, // 01A6 EQ R12 R11 R12 + 0x78320000, // 01A7 JMPF R12 #01A9 + 0x7001FFF9, // 01A8 JMP #01A3 + 0x8C301739, // 01A9 GETMET R12 R11 K57 + 0x7C300200, // 01AA CALL R12 1 + 0x78320000, // 01AB JMPF R12 #01AD + 0x7001FFF5, // 01AC JMP #01A3 + 0x8C300B3F, // 01AD GETMET R12 R5 K63 + 0x8C381740, // 01AE GETMET R14 R11 K64 + 0x7C380200, // 01AF CALL R14 1 + 0x7C300400, // 01B0 CALL R12 2 + 0x8C341115, // 01B1 GETMET R13 R8 K21 + 0x4C3C0000, // 01B2 LDNIL R15 + 0x7C340400, // 01B3 CALL R13 2 + 0x8C381B0B, // 01B4 GETMET R14 R13 K11 + 0x58400009, // 01B5 LDCONST R16 K9 + 0x88440B3A, // 01B6 GETMBR R17 R5 K58 + 0x8C481941, // 01B7 GETMET R18 R12 K65 + 0x54520008, // 01B8 LDINT R20 9 + 0x7C480400, // 01B9 CALL R18 2 + 0x7C380800, // 01BA CALL R14 4 + 0x8C381B0B, // 01BB GETMET R14 R13 K11 + 0x5840000D, // 01BC LDCONST R16 K13 + 0x88440B0C, // 01BD GETMBR R17 R5 K12 + 0x8C481742, // 01BE GETMET R18 R11 K66 + 0x7C480200, // 01BF CALL R18 1 + 0x7C380800, // 01C0 CALL R14 4 + 0x8C381B0B, // 01C1 GETMET R14 R13 K11 + 0x5840000F, // 01C2 LDCONST R16 K15 + 0x88440B07, // 01C3 GETMBR R17 R5 K7 + 0x8C481743, // 01C4 GETMET R18 R11 K67 + 0x7C480200, // 01C5 CALL R18 1 + 0x7C380800, // 01C6 CALL R14 4 + 0x8C381B0B, // 01C7 GETMET R14 R13 K11 + 0x54420003, // 01C8 LDINT R16 4 + 0x88440B07, // 01C9 GETMBR R17 R5 K7 + 0x8C481744, // 01CA GETMET R18 R11 K68 + 0x7C480200, // 01CB CALL R18 1 + 0x7C380800, // 01CC CALL R14 4 + 0x8C381B0B, // 01CD GETMET R14 R13 K11 + 0x54420004, // 01CE LDINT R16 5 + 0x88440B16, // 01CF GETMBR R17 R5 K22 + 0x8C481745, // 01D0 GETMET R18 R11 K69 + 0x7C480200, // 01D1 CALL R18 1 + 0x7C380800, // 01D2 CALL R14 4 + 0x8C381B0B, // 01D3 GETMET R14 R13 K11 + 0x544200FD, // 01D4 LDINT R16 254 + 0x88440B0C, // 01D5 GETMBR R17 R5 K12 + 0x8C48173D, // 01D6 GETMET R18 R11 K61 + 0x7C480200, // 01D7 CALL R18 1 + 0x7C380800, // 01D8 CALL R14 4 + 0x7001FFC8, // 01D9 JMP #01A3 + 0x5828003E, // 01DA LDCONST R10 K62 + 0xAC280200, // 01DB CATCH R10 1 0 + 0xB0080000, // 01DC RAISE 2 R0 R0 + 0x80041000, // 01DD RET 1 R8 + 0x70020028, // 01DE JMP #0208 + 0x1C200F0D, // 01DF EQ R8 R7 K13 + 0x78220007, // 01E0 JMPF R8 #01E9 + 0x8C200706, // 01E1 GETMET R8 R3 K6 + 0x88280B0E, // 01E2 GETMBR R10 R5 K14 + 0xB82E0200, // 01E3 GETNGBL R11 K1 + 0x882C1746, // 01E4 GETMBR R11 R11 K70 0x882C1747, // 01E5 GETMBR R11 R11 K71 - 0x882C1748, // 01E6 GETMBR R11 R11 K72 - 0x7C200600, // 01E7 CALL R8 3 - 0x80041000, // 01E8 RET 1 R8 - 0x7002001E, // 01E9 JMP #0209 - 0x1C200F0F, // 01EA EQ R8 R7 K15 - 0x78220009, // 01EB JMPF R8 #01F6 - 0x88200136, // 01EC GETMBR R8 R0 K54 - 0x88201137, // 01ED GETMBR R8 R8 K55 - 0x8C201149, // 01EE GETMET R8 R8 K73 - 0x7C200200, // 01EF CALL R8 1 - 0x8C240706, // 01F0 GETMET R9 R3 K6 - 0x882C0B0E, // 01F1 GETMBR R11 R5 K14 - 0x5C301000, // 01F2 MOVE R12 R8 - 0x7C240600, // 01F3 CALL R9 3 - 0x80041200, // 01F4 RET 1 R9 - 0x70020012, // 01F5 JMP #0209 - 0x54220003, // 01F6 LDINT R8 4 - 0x1C200E08, // 01F7 EQ R8 R7 R8 - 0x78220000, // 01F8 JMPF R8 #01FA - 0x7002000E, // 01F9 JMP #0209 - 0x54220004, // 01FA LDINT R8 5 - 0x1C200E08, // 01FB EQ R8 R7 R8 - 0x7822000B, // 01FC JMPF R8 #0209 - 0x8820034A, // 01FD GETMBR R8 R1 K74 - 0x8C20113E, // 01FE GETMET R8 R8 K62 - 0x7C200200, // 01FF CALL R8 1 - 0x4C240000, // 0200 LDNIL R9 - 0x1C241009, // 0201 EQ R9 R8 R9 - 0x78260000, // 0202 JMPF R9 #0204 - 0x58200005, // 0203 LDCONST R8 K5 - 0x8C240706, // 0204 GETMET R9 R3 K6 - 0x882C0B0E, // 0205 GETMBR R11 R5 K14 - 0x5C301000, // 0206 MOVE R12 R8 - 0x7C240600, // 0207 CALL R9 3 - 0x80041200, // 0208 RET 1 R9 - 0x70020195, // 0209 JMP #03A0 - 0x5422003B, // 020A LDINT R8 60 - 0x1C200C08, // 020B EQ R8 R6 R8 - 0x7822003C, // 020C JMPF R8 #024A - 0x1C200F05, // 020D EQ R8 R7 K5 - 0x78220012, // 020E JMPF R8 #0222 - 0x88200136, // 020F GETMBR R8 R0 K54 - 0x8C20114B, // 0210 GETMET R8 R8 K75 - 0x7C200200, // 0211 CALL R8 1 - 0x88240136, // 0212 GETMBR R9 R0 K54 - 0x8C24134C, // 0213 GETMET R9 R9 K76 - 0x7C240200, // 0214 CALL R9 1 - 0x78220004, // 0215 JMPF R8 #021B - 0x78260001, // 0216 JMPF R9 #0219 - 0x5828000D, // 0217 LDCONST R10 K13 - 0x70020000, // 0218 JMP #021A - 0x58280009, // 0219 LDCONST R10 K9 - 0x70020000, // 021A JMP #021C - 0x58280005, // 021B LDCONST R10 K5 - 0x8C2C0706, // 021C GETMET R11 R3 K6 - 0x88340B0E, // 021D GETMBR R13 R5 K14 - 0x5C381400, // 021E MOVE R14 R10 - 0x7C2C0600, // 021F CALL R11 3 - 0x80041600, // 0220 RET 1 R11 - 0x70020026, // 0221 JMP #0249 - 0x1C200F09, // 0222 EQ R8 R7 K9 - 0x78220011, // 0223 JMPF R8 #0236 - 0x88200136, // 0224 GETMBR R8 R0 K54 - 0x8820114D, // 0225 GETMBR R8 R8 K77 - 0x4C240000, // 0226 LDNIL R9 - 0x20241009, // 0227 NE R9 R8 R9 - 0x78260006, // 0228 JMPF R9 #0230 - 0x8C240706, // 0229 GETMET R9 R3 K6 - 0x882C0B0C, // 022A GETMBR R11 R5 K12 - 0x8C30113E, // 022B GETMET R12 R8 K62 - 0x7C300200, // 022C CALL R12 1 - 0x7C240600, // 022D CALL R9 3 - 0x80041200, // 022E RET 1 R9 - 0x70020004, // 022F JMP #0235 - 0x8C240706, // 0230 GETMET R9 R3 K6 - 0x882C0B18, // 0231 GETMBR R11 R5 K24 - 0x4C300000, // 0232 LDNIL R12 - 0x7C240600, // 0233 CALL R9 3 - 0x80041200, // 0234 RET 1 R9 - 0x70020012, // 0235 JMP #0249 - 0x1C200F0D, // 0236 EQ R8 R7 K13 - 0x78220010, // 0237 JMPF R8 #0249 - 0x88200136, // 0238 GETMBR R8 R0 K54 - 0x8820114D, // 0239 GETMBR R8 R8 K77 - 0x4C240000, // 023A LDNIL R9 - 0x20241009, // 023B NE R9 R8 R9 - 0x78260006, // 023C JMPF R9 #0244 - 0x8C240706, // 023D GETMET R9 R3 K6 - 0x882C0B0C, // 023E GETMBR R11 R5 K12 - 0x8C301143, // 023F GETMET R12 R8 K67 - 0x7C300200, // 0240 CALL R12 1 - 0x7C240600, // 0241 CALL R9 3 - 0x80041200, // 0242 RET 1 R9 - 0x70020004, // 0243 JMP #0249 - 0x8C240706, // 0244 GETMET R9 R3 K6 - 0x882C0B18, // 0245 GETMBR R11 R5 K24 - 0x4C300000, // 0246 LDNIL R12 - 0x7C240600, // 0247 CALL R9 3 - 0x80041200, // 0248 RET 1 R9 - 0x70020155, // 0249 JMP #03A0 - 0x54220027, // 024A LDINT R8 40 - 0x1C200C08, // 024B EQ R8 R6 R8 - 0x782200BA, // 024C JMPF R8 #0308 - 0x8C200133, // 024D GETMET R8 R0 K51 - 0x5C280400, // 024E MOVE R10 R2 - 0x7C200400, // 024F CALL R8 2 - 0x1C200F05, // 0250 EQ R8 R7 K5 - 0x78220005, // 0251 JMPF R8 #0258 - 0x8C200706, // 0252 GETMET R8 R3 K6 - 0x88280B0C, // 0253 GETMBR R10 R5 K12 - 0x582C0009, // 0254 LDCONST R11 K9 - 0x7C200600, // 0255 CALL R8 3 - 0x80041000, // 0256 RET 1 R8 - 0x700200AE, // 0257 JMP #0307 - 0x1C200F09, // 0258 EQ R8 R7 K9 - 0x78220005, // 0259 JMPF R8 #0260 - 0x8C200706, // 025A GETMET R8 R3 K6 - 0x88280B16, // 025B GETMBR R10 R5 K22 - 0x582C004E, // 025C LDCONST R11 K78 - 0x7C200600, // 025D CALL R8 3 - 0x80041000, // 025E RET 1 R8 - 0x700200A6, // 025F JMP #0307 - 0x1C200F0D, // 0260 EQ R8 R7 K13 - 0x78220006, // 0261 JMPF R8 #0269 - 0x8C200706, // 0262 GETMET R8 R3 K6 - 0x88280B0C, // 0263 GETMBR R10 R5 K12 - 0x882C0136, // 0264 GETMBR R11 R0 K54 - 0x882C174F, // 0265 GETMBR R11 R11 K79 - 0x7C200600, // 0266 CALL R8 3 - 0x80041000, // 0267 RET 1 R8 - 0x7002009D, // 0268 JMP #0307 - 0x1C200F0F, // 0269 EQ R8 R7 K15 - 0x7822000A, // 026A JMPF R8 #0276 - 0x8C200706, // 026B GETMET R8 R3 K6 - 0x88280B16, // 026C GETMBR R10 R5 K22 - 0xB82E2400, // 026D GETNGBL R11 K18 - 0x8C2C1726, // 026E GETMET R11 R11 K38 - 0x58340050, // 026F LDCONST R13 K80 - 0x50380200, // 0270 LDBOOL R14 1 0 - 0x7C2C0600, // 0271 CALL R11 3 - 0x942C1750, // 0272 GETIDX R11 R11 K80 - 0x7C200600, // 0273 CALL R8 3 - 0x80041000, // 0274 RET 1 R8 - 0x70020090, // 0275 JMP #0307 - 0x54220003, // 0276 LDINT R8 4 - 0x1C200E08, // 0277 EQ R8 R7 R8 - 0x78220005, // 0278 JMPF R8 #027F - 0x8C200706, // 0279 GETMET R8 R3 K6 - 0x88280B0C, // 027A GETMBR R10 R5 K12 - 0x542E7FFF, // 027B LDINT R11 32768 - 0x7C200600, // 027C CALL R8 3 - 0x80041000, // 027D RET 1 R8 - 0x70020087, // 027E JMP #0307 - 0x54220004, // 027F LDINT R8 5 - 0x1C200E08, // 0280 EQ R8 R7 R8 - 0x7822000A, // 0281 JMPF R8 #028D - 0x8C200706, // 0282 GETMET R8 R3 K6 - 0x88280B16, // 0283 GETMBR R10 R5 K22 - 0xB82E2400, // 0284 GETNGBL R11 K18 - 0x8C2C1726, // 0285 GETMET R11 R11 K38 - 0x58340051, // 0286 LDCONST R13 K81 - 0x50380200, // 0287 LDBOOL R14 1 0 - 0x7C2C0600, // 0288 CALL R11 3 - 0x942C1752, // 0289 GETIDX R11 R11 K82 - 0x7C200600, // 028A CALL R8 3 - 0x80041000, // 028B RET 1 R8 - 0x70020079, // 028C JMP #0307 - 0x54220005, // 028D LDINT R8 6 - 0x1C200E08, // 028E EQ R8 R7 R8 - 0x78220005, // 028F JMPF R8 #0296 - 0x8C200706, // 0290 GETMET R8 R3 K6 - 0x88280B16, // 0291 GETMBR R10 R5 K22 - 0x582C0053, // 0292 LDCONST R11 K83 - 0x7C200600, // 0293 CALL R8 3 - 0x80041000, // 0294 RET 1 R8 - 0x70020070, // 0295 JMP #0307 - 0x54220006, // 0296 LDINT R8 7 - 0x1C200E08, // 0297 EQ R8 R7 R8 - 0x78220005, // 0298 JMPF R8 #029F - 0x8C200706, // 0299 GETMET R8 R3 K6 - 0x88280B0C, // 029A GETMBR R10 R5 K12 - 0x582C0005, // 029B LDCONST R11 K5 - 0x7C200600, // 029C CALL R8 3 - 0x80041000, // 029D RET 1 R8 - 0x70020067, // 029E JMP #0307 - 0x54220007, // 029F LDINT R8 8 - 0x1C200E08, // 02A0 EQ R8 R7 R8 - 0x7822000B, // 02A1 JMPF R8 #02AE - 0x8C200706, // 02A2 GETMET R8 R3 K6 - 0x88280B16, // 02A3 GETMBR R10 R5 K22 - 0xB82E2400, // 02A4 GETNGBL R11 K18 - 0x8C2C1726, // 02A5 GETMET R11 R11 K38 - 0x58340054, // 02A6 LDCONST R13 K84 - 0x50380200, // 02A7 LDBOOL R14 1 0 - 0x7C2C0600, // 02A8 CALL R11 3 + 0x7C200600, // 01E6 CALL R8 3 + 0x80041000, // 01E7 RET 1 R8 + 0x7002001E, // 01E8 JMP #0208 + 0x1C200F0F, // 01E9 EQ R8 R7 K15 + 0x78220009, // 01EA JMPF R8 #01F5 + 0x88200136, // 01EB GETMBR R8 R0 K54 + 0x88201137, // 01EC GETMBR R8 R8 K55 + 0x8C201148, // 01ED GETMET R8 R8 K72 + 0x7C200200, // 01EE CALL R8 1 + 0x8C240706, // 01EF GETMET R9 R3 K6 + 0x882C0B0E, // 01F0 GETMBR R11 R5 K14 + 0x5C301000, // 01F1 MOVE R12 R8 + 0x7C240600, // 01F2 CALL R9 3 + 0x80041200, // 01F3 RET 1 R9 + 0x70020012, // 01F4 JMP #0208 + 0x54220003, // 01F5 LDINT R8 4 + 0x1C200E08, // 01F6 EQ R8 R7 R8 + 0x78220000, // 01F7 JMPF R8 #01F9 + 0x7002000E, // 01F8 JMP #0208 + 0x54220004, // 01F9 LDINT R8 5 + 0x1C200E08, // 01FA EQ R8 R7 R8 + 0x7822000B, // 01FB JMPF R8 #0208 + 0x88200349, // 01FC GETMBR R8 R1 K73 + 0x8C20113D, // 01FD GETMET R8 R8 K61 + 0x7C200200, // 01FE CALL R8 1 + 0x4C240000, // 01FF LDNIL R9 + 0x1C241009, // 0200 EQ R9 R8 R9 + 0x78260000, // 0201 JMPF R9 #0203 + 0x58200005, // 0202 LDCONST R8 K5 + 0x8C240706, // 0203 GETMET R9 R3 K6 + 0x882C0B0E, // 0204 GETMBR R11 R5 K14 + 0x5C301000, // 0205 MOVE R12 R8 + 0x7C240600, // 0206 CALL R9 3 + 0x80041200, // 0207 RET 1 R9 + 0x70020195, // 0208 JMP #039F + 0x5422003B, // 0209 LDINT R8 60 + 0x1C200C08, // 020A EQ R8 R6 R8 + 0x7822003C, // 020B JMPF R8 #0249 + 0x1C200F05, // 020C EQ R8 R7 K5 + 0x78220012, // 020D JMPF R8 #0221 + 0x88200136, // 020E GETMBR R8 R0 K54 + 0x8C20114A, // 020F GETMET R8 R8 K74 + 0x7C200200, // 0210 CALL R8 1 + 0x88240136, // 0211 GETMBR R9 R0 K54 + 0x8C24134B, // 0212 GETMET R9 R9 K75 + 0x7C240200, // 0213 CALL R9 1 + 0x78220004, // 0214 JMPF R8 #021A + 0x78260001, // 0215 JMPF R9 #0218 + 0x5828000D, // 0216 LDCONST R10 K13 + 0x70020000, // 0217 JMP #0219 + 0x58280009, // 0218 LDCONST R10 K9 + 0x70020000, // 0219 JMP #021B + 0x58280005, // 021A LDCONST R10 K5 + 0x8C2C0706, // 021B GETMET R11 R3 K6 + 0x88340B0E, // 021C GETMBR R13 R5 K14 + 0x5C381400, // 021D MOVE R14 R10 + 0x7C2C0600, // 021E CALL R11 3 + 0x80041600, // 021F RET 1 R11 + 0x70020026, // 0220 JMP #0248 + 0x1C200F09, // 0221 EQ R8 R7 K9 + 0x78220011, // 0222 JMPF R8 #0235 + 0x88200136, // 0223 GETMBR R8 R0 K54 + 0x8820114C, // 0224 GETMBR R8 R8 K76 + 0x4C240000, // 0225 LDNIL R9 + 0x20241009, // 0226 NE R9 R8 R9 + 0x78260006, // 0227 JMPF R9 #022F + 0x8C240706, // 0228 GETMET R9 R3 K6 + 0x882C0B0C, // 0229 GETMBR R11 R5 K12 + 0x8C30113D, // 022A GETMET R12 R8 K61 + 0x7C300200, // 022B CALL R12 1 + 0x7C240600, // 022C CALL R9 3 + 0x80041200, // 022D RET 1 R9 + 0x70020004, // 022E JMP #0234 + 0x8C240706, // 022F GETMET R9 R3 K6 + 0x882C0B18, // 0230 GETMBR R11 R5 K24 + 0x4C300000, // 0231 LDNIL R12 + 0x7C240600, // 0232 CALL R9 3 + 0x80041200, // 0233 RET 1 R9 + 0x70020012, // 0234 JMP #0248 + 0x1C200F0D, // 0235 EQ R8 R7 K13 + 0x78220010, // 0236 JMPF R8 #0248 + 0x88200136, // 0237 GETMBR R8 R0 K54 + 0x8820114C, // 0238 GETMBR R8 R8 K76 + 0x4C240000, // 0239 LDNIL R9 + 0x20241009, // 023A NE R9 R8 R9 + 0x78260006, // 023B JMPF R9 #0243 + 0x8C240706, // 023C GETMET R9 R3 K6 + 0x882C0B0C, // 023D GETMBR R11 R5 K12 + 0x8C301142, // 023E GETMET R12 R8 K66 + 0x7C300200, // 023F CALL R12 1 + 0x7C240600, // 0240 CALL R9 3 + 0x80041200, // 0241 RET 1 R9 + 0x70020004, // 0242 JMP #0248 + 0x8C240706, // 0243 GETMET R9 R3 K6 + 0x882C0B18, // 0244 GETMBR R11 R5 K24 + 0x4C300000, // 0245 LDNIL R12 + 0x7C240600, // 0246 CALL R9 3 + 0x80041200, // 0247 RET 1 R9 + 0x70020155, // 0248 JMP #039F + 0x54220027, // 0249 LDINT R8 40 + 0x1C200C08, // 024A EQ R8 R6 R8 + 0x782200BA, // 024B JMPF R8 #0307 + 0x8C200133, // 024C GETMET R8 R0 K51 + 0x5C280400, // 024D MOVE R10 R2 + 0x7C200400, // 024E CALL R8 2 + 0x1C200F05, // 024F EQ R8 R7 K5 + 0x78220005, // 0250 JMPF R8 #0257 + 0x8C200706, // 0251 GETMET R8 R3 K6 + 0x88280B0C, // 0252 GETMBR R10 R5 K12 + 0x582C0009, // 0253 LDCONST R11 K9 + 0x7C200600, // 0254 CALL R8 3 + 0x80041000, // 0255 RET 1 R8 + 0x700200AE, // 0256 JMP #0306 + 0x1C200F09, // 0257 EQ R8 R7 K9 + 0x78220005, // 0258 JMPF R8 #025F + 0x8C200706, // 0259 GETMET R8 R3 K6 + 0x88280B16, // 025A GETMBR R10 R5 K22 + 0x582C004D, // 025B LDCONST R11 K77 + 0x7C200600, // 025C CALL R8 3 + 0x80041000, // 025D RET 1 R8 + 0x700200A6, // 025E JMP #0306 + 0x1C200F0D, // 025F EQ R8 R7 K13 + 0x78220006, // 0260 JMPF R8 #0268 + 0x8C200706, // 0261 GETMET R8 R3 K6 + 0x88280B0C, // 0262 GETMBR R10 R5 K12 + 0x882C0136, // 0263 GETMBR R11 R0 K54 + 0x882C174E, // 0264 GETMBR R11 R11 K78 + 0x7C200600, // 0265 CALL R8 3 + 0x80041000, // 0266 RET 1 R8 + 0x7002009D, // 0267 JMP #0306 + 0x1C200F0F, // 0268 EQ R8 R7 K15 + 0x7822000A, // 0269 JMPF R8 #0275 + 0x8C200706, // 026A GETMET R8 R3 K6 + 0x88280B16, // 026B GETMBR R10 R5 K22 + 0xB82E2400, // 026C GETNGBL R11 K18 + 0x8C2C1726, // 026D GETMET R11 R11 K38 + 0x5834004F, // 026E LDCONST R13 K79 + 0x50380200, // 026F LDBOOL R14 1 0 + 0x7C2C0600, // 0270 CALL R11 3 + 0x942C174F, // 0271 GETIDX R11 R11 K79 + 0x7C200600, // 0272 CALL R8 3 + 0x80041000, // 0273 RET 1 R8 + 0x70020090, // 0274 JMP #0306 + 0x54220003, // 0275 LDINT R8 4 + 0x1C200E08, // 0276 EQ R8 R7 R8 + 0x78220005, // 0277 JMPF R8 #027E + 0x8C200706, // 0278 GETMET R8 R3 K6 + 0x88280B0C, // 0279 GETMBR R10 R5 K12 + 0x542E7FFF, // 027A LDINT R11 32768 + 0x7C200600, // 027B CALL R8 3 + 0x80041000, // 027C RET 1 R8 + 0x70020087, // 027D JMP #0306 + 0x54220004, // 027E LDINT R8 5 + 0x1C200E08, // 027F EQ R8 R7 R8 + 0x7822000A, // 0280 JMPF R8 #028C + 0x8C200706, // 0281 GETMET R8 R3 K6 + 0x88280B16, // 0282 GETMBR R10 R5 K22 + 0xB82E2400, // 0283 GETNGBL R11 K18 + 0x8C2C1726, // 0284 GETMET R11 R11 K38 + 0x58340050, // 0285 LDCONST R13 K80 + 0x50380200, // 0286 LDBOOL R14 1 0 + 0x7C2C0600, // 0287 CALL R11 3 + 0x942C1751, // 0288 GETIDX R11 R11 K81 + 0x7C200600, // 0289 CALL R8 3 + 0x80041000, // 028A RET 1 R8 + 0x70020079, // 028B JMP #0306 + 0x54220005, // 028C LDINT R8 6 + 0x1C200E08, // 028D EQ R8 R7 R8 + 0x78220005, // 028E JMPF R8 #0295 + 0x8C200706, // 028F GETMET R8 R3 K6 + 0x88280B16, // 0290 GETMBR R10 R5 K22 + 0x582C0052, // 0291 LDCONST R11 K82 + 0x7C200600, // 0292 CALL R8 3 + 0x80041000, // 0293 RET 1 R8 + 0x70020070, // 0294 JMP #0306 + 0x54220006, // 0295 LDINT R8 7 + 0x1C200E08, // 0296 EQ R8 R7 R8 + 0x78220005, // 0297 JMPF R8 #029E + 0x8C200706, // 0298 GETMET R8 R3 K6 + 0x88280B0C, // 0299 GETMBR R10 R5 K12 + 0x582C0005, // 029A LDCONST R11 K5 + 0x7C200600, // 029B CALL R8 3 + 0x80041000, // 029C RET 1 R8 + 0x70020067, // 029D JMP #0306 + 0x54220007, // 029E LDINT R8 8 + 0x1C200E08, // 029F EQ R8 R7 R8 + 0x7822000B, // 02A0 JMPF R8 #02AD + 0x8C200706, // 02A1 GETMET R8 R3 K6 + 0x88280B16, // 02A2 GETMBR R10 R5 K22 + 0xB82E2400, // 02A3 GETNGBL R11 K18 + 0x8C2C1726, // 02A4 GETMET R11 R11 K38 + 0x58340053, // 02A5 LDCONST R13 K83 + 0x50380200, // 02A6 LDBOOL R14 1 0 + 0x7C2C0600, // 02A7 CALL R11 3 + 0x942C1754, // 02A8 GETIDX R11 R11 K84 0x942C1755, // 02A9 GETIDX R11 R11 K85 - 0x942C1756, // 02AA GETIDX R11 R11 K86 - 0x7C200600, // 02AB CALL R8 3 - 0x80041000, // 02AC RET 1 R8 - 0x70020058, // 02AD JMP #0307 - 0x54220008, // 02AE LDINT R8 9 - 0x1C200E08, // 02AF EQ R8 R7 R8 - 0x78220005, // 02B0 JMPF R8 #02B7 - 0x8C200706, // 02B1 GETMET R8 R3 K6 - 0x88280B0C, // 02B2 GETMBR R10 R5 K12 - 0x582C0009, // 02B3 LDCONST R11 K9 - 0x7C200600, // 02B4 CALL R8 3 - 0x80041000, // 02B5 RET 1 R8 - 0x7002004F, // 02B6 JMP #0307 - 0x54220009, // 02B7 LDINT R8 10 - 0x1C200E08, // 02B8 EQ R8 R7 R8 - 0x78220015, // 02B9 JMPF R8 #02D0 - 0xB8222400, // 02BA GETNGBL R8 K18 - 0x8C201126, // 02BB GETMET R8 R8 K38 - 0x58280054, // 02BC LDCONST R10 K84 - 0x502C0200, // 02BD LDBOOL R11 1 0 - 0x7C200600, // 02BE CALL R8 3 - 0x94201155, // 02BF GETIDX R8 R8 K85 - 0x94201157, // 02C0 GETIDX R8 R8 K87 - 0x8C24091B, // 02C1 GETMET R9 R4 K27 - 0x5C2C1000, // 02C2 MOVE R11 R8 - 0x58300058, // 02C3 LDCONST R12 K88 - 0x7C240600, // 02C4 CALL R9 3 - 0x24281305, // 02C5 GT R10 R9 K5 - 0x782A0002, // 02C6 JMPF R10 #02CA - 0x04281309, // 02C7 SUB R10 R9 K9 - 0x402A0A0A, // 02C8 CONNECT R10 K5 R10 - 0x9420100A, // 02C9 GETIDX R8 R8 R10 - 0x8C280706, // 02CA GETMET R10 R3 K6 - 0x88300B16, // 02CB GETMBR R12 R5 K22 - 0x5C341000, // 02CC MOVE R13 R8 - 0x7C280600, // 02CD CALL R10 3 - 0x80041400, // 02CE RET 1 R10 - 0x70020036, // 02CF JMP #0307 - 0x5422000E, // 02D0 LDINT R8 15 - 0x1C200E08, // 02D1 EQ R8 R7 R8 - 0x7822000B, // 02D2 JMPF R8 #02DF - 0x8C200706, // 02D3 GETMET R8 R3 K6 - 0x88280B16, // 02D4 GETMBR R10 R5 K22 - 0xB82E2400, // 02D5 GETNGBL R11 K18 - 0x8C2C1725, // 02D6 GETMET R11 R11 K37 - 0x7C2C0200, // 02D7 CALL R11 1 - 0x8C2C171B, // 02D8 GETMET R11 R11 K27 - 0x5834001C, // 02D9 LDCONST R13 K28 - 0x5838001D, // 02DA LDCONST R14 K29 - 0x7C2C0600, // 02DB CALL R11 3 - 0x7C200600, // 02DC CALL R8 3 - 0x80041000, // 02DD RET 1 R8 - 0x70020027, // 02DE JMP #0307 - 0x54220010, // 02DF LDINT R8 17 - 0x1C200E08, // 02E0 EQ R8 R7 R8 - 0x78220005, // 02E1 JMPF R8 #02E8 - 0x8C200706, // 02E2 GETMET R8 R3 K6 - 0x88280B10, // 02E3 GETMBR R10 R5 K16 - 0x582C0009, // 02E4 LDCONST R11 K9 - 0x7C200600, // 02E5 CALL R8 3 - 0x80041000, // 02E6 RET 1 R8 - 0x7002001E, // 02E7 JMP #0307 - 0x54220011, // 02E8 LDINT R8 18 - 0x1C200E08, // 02E9 EQ R8 R7 R8 - 0x7822000B, // 02EA JMPF R8 #02F7 - 0x8C200706, // 02EB GETMET R8 R3 K6 - 0x88280B16, // 02EC GETMBR R10 R5 K22 - 0xB82E2400, // 02ED GETNGBL R11 K18 - 0x8C2C1725, // 02EE GETMET R11 R11 K37 - 0x7C2C0200, // 02EF CALL R11 1 - 0x8C2C171B, // 02F0 GETMET R11 R11 K27 - 0x5834001C, // 02F1 LDCONST R13 K28 - 0x5838001D, // 02F2 LDCONST R14 K29 - 0x7C2C0600, // 02F3 CALL R11 3 - 0x7C200600, // 02F4 CALL R8 3 - 0x80041000, // 02F5 RET 1 R8 - 0x7002000F, // 02F6 JMP #0307 - 0x54220012, // 02F7 LDINT R8 19 - 0x1C200E08, // 02F8 EQ R8 R7 R8 - 0x7822000C, // 02F9 JMPF R8 #0307 - 0x8C200B0A, // 02FA GETMET R8 R5 K10 - 0x7C200200, // 02FB CALL R8 1 - 0x8C24110B, // 02FC GETMET R9 R8 K11 - 0x582C0005, // 02FD LDCONST R11 K5 - 0x88300B0C, // 02FE GETMBR R12 R5 K12 - 0x5834000F, // 02FF LDCONST R13 K15 - 0x7C240800, // 0300 CALL R9 4 - 0x8C24110B, // 0301 GETMET R9 R8 K11 - 0x582C0009, // 0302 LDCONST R11 K9 - 0x88300B0C, // 0303 GETMBR R12 R5 K12 - 0x5834000F, // 0304 LDCONST R13 K15 - 0x7C240800, // 0305 CALL R9 4 - 0x80041000, // 0306 RET 1 R8 - 0x70020097, // 0307 JMP #03A0 - 0x5422003E, // 0308 LDINT R8 63 - 0x1C200C08, // 0309 EQ R8 R6 R8 - 0x78220000, // 030A JMPF R8 #030C - 0x70020093, // 030B JMP #03A0 - 0x54220029, // 030C LDINT R8 42 - 0x1C200C08, // 030D EQ R8 R6 R8 - 0x7822001D, // 030E JMPF R8 #032D - 0x1C200F05, // 030F EQ R8 R7 K5 - 0x78220003, // 0310 JMPF R8 #0315 - 0x8C200B11, // 0311 GETMET R8 R5 K17 - 0x7C200200, // 0312 CALL R8 1 - 0x80041000, // 0313 RET 1 R8 - 0x70020016, // 0314 JMP #032C - 0x1C200F09, // 0315 EQ R8 R7 K9 - 0x78220005, // 0316 JMPF R8 #031D - 0x8C200706, // 0317 GETMET R8 R3 K6 - 0x88280B10, // 0318 GETMBR R10 R5 K16 - 0x582C0005, // 0319 LDCONST R11 K5 - 0x7C200600, // 031A CALL R8 3 - 0x80041000, // 031B RET 1 R8 - 0x7002000E, // 031C JMP #032C - 0x1C200F0D, // 031D EQ R8 R7 K13 - 0x78220005, // 031E JMPF R8 #0325 - 0x8C200706, // 031F GETMET R8 R3 K6 - 0x88280B0E, // 0320 GETMBR R10 R5 K14 - 0x582C0009, // 0321 LDCONST R11 K9 - 0x7C200600, // 0322 CALL R8 3 - 0x80041000, // 0323 RET 1 R8 - 0x70020006, // 0324 JMP #032C - 0x1C200F0F, // 0325 EQ R8 R7 K15 - 0x78220004, // 0326 JMPF R8 #032C - 0x8C200706, // 0327 GETMET R8 R3 K6 - 0x88280B18, // 0328 GETMBR R10 R5 K24 - 0x4C2C0000, // 0329 LDNIL R11 - 0x7C200600, // 032A CALL R8 3 - 0x80041000, // 032B RET 1 R8 - 0x70020072, // 032C JMP #03A0 - 0x5422002A, // 032D LDINT R8 43 - 0x1C200C08, // 032E EQ R8 R6 R8 - 0x78220016, // 032F JMPF R8 #0347 - 0x1C200F05, // 0330 EQ R8 R7 K5 - 0x78220007, // 0331 JMPF R8 #033A - 0x8C200706, // 0332 GETMET R8 R3 K6 - 0x88280B16, // 0333 GETMBR R10 R5 K22 - 0xB82E2400, // 0334 GETNGBL R11 K18 - 0x8C2C1759, // 0335 GETMET R11 R11 K89 - 0x7C2C0200, // 0336 CALL R11 1 - 0x7C200600, // 0337 CALL R8 3 - 0x80041000, // 0338 RET 1 R8 - 0x7002000B, // 0339 JMP #0346 - 0x1C200F09, // 033A EQ R8 R7 K9 - 0x78220009, // 033B JMPF R8 #0346 - 0x8C200B11, // 033C GETMET R8 R5 K17 - 0x7C200200, // 033D CALL R8 1 - 0x8C24110B, // 033E GETMET R9 R8 K11 - 0x4C2C0000, // 033F LDNIL R11 - 0x88300B16, // 0340 GETMBR R12 R5 K22 - 0xB8362400, // 0341 GETNGBL R13 K18 - 0x8C341B59, // 0342 GETMET R13 R13 K89 - 0x7C340200, // 0343 CALL R13 1 - 0x7C240800, // 0344 CALL R9 4 - 0x80041000, // 0345 RET 1 R8 - 0x70020058, // 0346 JMP #03A0 - 0x5422002B, // 0347 LDINT R8 44 - 0x1C200C08, // 0348 EQ R8 R6 R8 - 0x7822001C, // 0349 JMPF R8 #0367 - 0x1C200F05, // 034A EQ R8 R7 K5 - 0x78220005, // 034B JMPF R8 #0352 - 0x8C200706, // 034C GETMET R8 R3 K6 - 0x88280B0E, // 034D GETMBR R10 R5 K14 - 0x582C0009, // 034E LDCONST R11 K9 - 0x7C200600, // 034F CALL R8 3 - 0x80041000, // 0350 RET 1 R8 - 0x70020013, // 0351 JMP #0366 - 0x1C200F09, // 0352 EQ R8 R7 K9 - 0x78220005, // 0353 JMPF R8 #035A - 0x8C200706, // 0354 GETMET R8 R3 K6 - 0x88280B0E, // 0355 GETMBR R10 R5 K14 - 0x542E0003, // 0356 LDINT R11 4 - 0x7C200600, // 0357 CALL R8 3 - 0x80041000, // 0358 RET 1 R8 - 0x7002000B, // 0359 JMP #0366 - 0x1C200F0D, // 035A EQ R8 R7 K13 - 0x78220009, // 035B JMPF R8 #0366 - 0x8C200B11, // 035C GETMET R8 R5 K17 - 0x7C200200, // 035D CALL R8 1 - 0x8C24110B, // 035E GETMET R9 R8 K11 - 0x4C2C0000, // 035F LDNIL R11 - 0x8C300B5A, // 0360 GETMET R12 R5 K90 - 0x88380B0E, // 0361 GETMBR R14 R5 K14 - 0x543E0003, // 0362 LDINT R15 4 - 0x7C300600, // 0363 CALL R12 3 - 0x7C240600, // 0364 CALL R9 3 - 0x80041000, // 0365 RET 1 R8 - 0x70020038, // 0366 JMP #03A0 - 0x54220030, // 0367 LDINT R8 49 - 0x1C200C08, // 0368 EQ R8 R6 R8 - 0x78220007, // 0369 JMPF R8 #0372 - 0x1C200F0F, // 036A EQ R8 R7 K15 - 0x78220004, // 036B JMPF R8 #0371 - 0x8C200706, // 036C GETMET R8 R3 K6 - 0x88280B0E, // 036D GETMBR R10 R5 K14 - 0x542E001D, // 036E LDINT R11 30 - 0x7C200600, // 036F CALL R8 3 - 0x80041000, // 0370 RET 1 R8 - 0x7002002D, // 0371 JMP #03A0 - 0x5422001C, // 0372 LDINT R8 29 - 0x1C200C08, // 0373 EQ R8 R6 R8 - 0x7822002A, // 0374 JMPF R8 #03A0 - 0x1C200F0D, // 0375 EQ R8 R7 K13 - 0x78220008, // 0376 JMPF R8 #0380 - 0x8C200B11, // 0377 GETMET R8 R5 K17 - 0x7C200200, // 0378 CALL R8 1 - 0x8C24110B, // 0379 GETMET R9 R8 K11 - 0x4C2C0000, // 037A LDNIL R11 - 0x88300B0C, // 037B GETMBR R12 R5 K12 - 0x5436001E, // 037C LDINT R13 31 - 0x7C240800, // 037D CALL R9 4 - 0x80041000, // 037E RET 1 R8 - 0x7002001F, // 037F JMP #03A0 - 0x1C200F0F, // 0380 EQ R8 R7 K15 - 0x7822001D, // 0381 JMPF R8 #03A0 - 0x8C200B11, // 0382 GETMET R8 R5 K17 - 0x7C200200, // 0383 CALL R8 1 - 0x88240136, // 0384 GETMBR R9 R0 K54 - 0x8C24135B, // 0385 GETMET R9 R9 K91 - 0x502C0200, // 0386 LDBOOL R11 1 0 - 0x7C240400, // 0387 CALL R9 2 - 0x88280136, // 0388 GETMBR R10 R0 K54 - 0x8828155C, // 0389 GETMBR R10 R10 K92 - 0x602C0010, // 038A GETGBL R11 G16 - 0x5C301200, // 038B MOVE R12 R9 - 0x7C2C0200, // 038C CALL R11 1 - 0xA802000D, // 038D EXBLK 0 #039C - 0x5C301600, // 038E MOVE R12 R11 - 0x7C300000, // 038F CALL R12 0 - 0x5C341400, // 0390 MOVE R13 R10 - 0x78360003, // 0391 JMPF R13 #0396 - 0xB8360200, // 0392 GETNGBL R13 K1 - 0x88341B3D, // 0393 GETMBR R13 R13 K61 - 0x2034180D, // 0394 NE R13 R12 R13 - 0x78360004, // 0395 JMPF R13 #039B - 0x8C34110B, // 0396 GETMET R13 R8 K11 - 0x4C3C0000, // 0397 LDNIL R15 - 0x88400B0C, // 0398 GETMBR R16 R5 K12 - 0x5C441800, // 0399 MOVE R17 R12 - 0x7C340800, // 039A CALL R13 4 - 0x7001FFF1, // 039B JMP #038E - 0x582C003F, // 039C LDCONST R11 K63 - 0xAC2C0200, // 039D CATCH R11 1 0 - 0xB0080000, // 039E RAISE 2 R0 R0 - 0x80041000, // 039F RET 1 R8 - 0x60200003, // 03A0 GETGBL R8 G3 - 0x5C240000, // 03A1 MOVE R9 R0 - 0x7C200200, // 03A2 CALL R8 1 - 0x8C20115D, // 03A3 GETMET R8 R8 K93 - 0x5C280200, // 03A4 MOVE R10 R1 - 0x5C2C0400, // 03A5 MOVE R11 R2 - 0x5C300600, // 03A6 MOVE R12 R3 - 0x7C200800, // 03A7 CALL R8 4 - 0x80041000, // 03A8 RET 1 R8 + 0x7C200600, // 02AA CALL R8 3 + 0x80041000, // 02AB RET 1 R8 + 0x70020058, // 02AC JMP #0306 + 0x54220008, // 02AD LDINT R8 9 + 0x1C200E08, // 02AE EQ R8 R7 R8 + 0x78220005, // 02AF JMPF R8 #02B6 + 0x8C200706, // 02B0 GETMET R8 R3 K6 + 0x88280B0C, // 02B1 GETMBR R10 R5 K12 + 0x582C0009, // 02B2 LDCONST R11 K9 + 0x7C200600, // 02B3 CALL R8 3 + 0x80041000, // 02B4 RET 1 R8 + 0x7002004F, // 02B5 JMP #0306 + 0x54220009, // 02B6 LDINT R8 10 + 0x1C200E08, // 02B7 EQ R8 R7 R8 + 0x78220015, // 02B8 JMPF R8 #02CF + 0xB8222400, // 02B9 GETNGBL R8 K18 + 0x8C201126, // 02BA GETMET R8 R8 K38 + 0x58280053, // 02BB LDCONST R10 K83 + 0x502C0200, // 02BC LDBOOL R11 1 0 + 0x7C200600, // 02BD CALL R8 3 + 0x94201154, // 02BE GETIDX R8 R8 K84 + 0x94201156, // 02BF GETIDX R8 R8 K86 + 0x8C24091B, // 02C0 GETMET R9 R4 K27 + 0x5C2C1000, // 02C1 MOVE R11 R8 + 0x58300057, // 02C2 LDCONST R12 K87 + 0x7C240600, // 02C3 CALL R9 3 + 0x24281305, // 02C4 GT R10 R9 K5 + 0x782A0002, // 02C5 JMPF R10 #02C9 + 0x04281309, // 02C6 SUB R10 R9 K9 + 0x402A0A0A, // 02C7 CONNECT R10 K5 R10 + 0x9420100A, // 02C8 GETIDX R8 R8 R10 + 0x8C280706, // 02C9 GETMET R10 R3 K6 + 0x88300B16, // 02CA GETMBR R12 R5 K22 + 0x5C341000, // 02CB MOVE R13 R8 + 0x7C280600, // 02CC CALL R10 3 + 0x80041400, // 02CD RET 1 R10 + 0x70020036, // 02CE JMP #0306 + 0x5422000E, // 02CF LDINT R8 15 + 0x1C200E08, // 02D0 EQ R8 R7 R8 + 0x7822000B, // 02D1 JMPF R8 #02DE + 0x8C200706, // 02D2 GETMET R8 R3 K6 + 0x88280B16, // 02D3 GETMBR R10 R5 K22 + 0xB82E2400, // 02D4 GETNGBL R11 K18 + 0x8C2C1725, // 02D5 GETMET R11 R11 K37 + 0x7C2C0200, // 02D6 CALL R11 1 + 0x8C2C171B, // 02D7 GETMET R11 R11 K27 + 0x5834001C, // 02D8 LDCONST R13 K28 + 0x5838001D, // 02D9 LDCONST R14 K29 + 0x7C2C0600, // 02DA CALL R11 3 + 0x7C200600, // 02DB CALL R8 3 + 0x80041000, // 02DC RET 1 R8 + 0x70020027, // 02DD JMP #0306 + 0x54220010, // 02DE LDINT R8 17 + 0x1C200E08, // 02DF EQ R8 R7 R8 + 0x78220005, // 02E0 JMPF R8 #02E7 + 0x8C200706, // 02E1 GETMET R8 R3 K6 + 0x88280B10, // 02E2 GETMBR R10 R5 K16 + 0x582C0009, // 02E3 LDCONST R11 K9 + 0x7C200600, // 02E4 CALL R8 3 + 0x80041000, // 02E5 RET 1 R8 + 0x7002001E, // 02E6 JMP #0306 + 0x54220011, // 02E7 LDINT R8 18 + 0x1C200E08, // 02E8 EQ R8 R7 R8 + 0x7822000B, // 02E9 JMPF R8 #02F6 + 0x8C200706, // 02EA GETMET R8 R3 K6 + 0x88280B16, // 02EB GETMBR R10 R5 K22 + 0xB82E2400, // 02EC GETNGBL R11 K18 + 0x8C2C1725, // 02ED GETMET R11 R11 K37 + 0x7C2C0200, // 02EE CALL R11 1 + 0x8C2C171B, // 02EF GETMET R11 R11 K27 + 0x5834001C, // 02F0 LDCONST R13 K28 + 0x5838001D, // 02F1 LDCONST R14 K29 + 0x7C2C0600, // 02F2 CALL R11 3 + 0x7C200600, // 02F3 CALL R8 3 + 0x80041000, // 02F4 RET 1 R8 + 0x7002000F, // 02F5 JMP #0306 + 0x54220012, // 02F6 LDINT R8 19 + 0x1C200E08, // 02F7 EQ R8 R7 R8 + 0x7822000C, // 02F8 JMPF R8 #0306 + 0x8C200B0A, // 02F9 GETMET R8 R5 K10 + 0x7C200200, // 02FA CALL R8 1 + 0x8C24110B, // 02FB GETMET R9 R8 K11 + 0x582C0005, // 02FC LDCONST R11 K5 + 0x88300B0C, // 02FD GETMBR R12 R5 K12 + 0x5834000F, // 02FE LDCONST R13 K15 + 0x7C240800, // 02FF CALL R9 4 + 0x8C24110B, // 0300 GETMET R9 R8 K11 + 0x582C0009, // 0301 LDCONST R11 K9 + 0x88300B0C, // 0302 GETMBR R12 R5 K12 + 0x5834000F, // 0303 LDCONST R13 K15 + 0x7C240800, // 0304 CALL R9 4 + 0x80041000, // 0305 RET 1 R8 + 0x70020097, // 0306 JMP #039F + 0x5422003E, // 0307 LDINT R8 63 + 0x1C200C08, // 0308 EQ R8 R6 R8 + 0x78220000, // 0309 JMPF R8 #030B + 0x70020093, // 030A JMP #039F + 0x54220029, // 030B LDINT R8 42 + 0x1C200C08, // 030C EQ R8 R6 R8 + 0x7822001D, // 030D JMPF R8 #032C + 0x1C200F05, // 030E EQ R8 R7 K5 + 0x78220003, // 030F JMPF R8 #0314 + 0x8C200B11, // 0310 GETMET R8 R5 K17 + 0x7C200200, // 0311 CALL R8 1 + 0x80041000, // 0312 RET 1 R8 + 0x70020016, // 0313 JMP #032B + 0x1C200F09, // 0314 EQ R8 R7 K9 + 0x78220005, // 0315 JMPF R8 #031C + 0x8C200706, // 0316 GETMET R8 R3 K6 + 0x88280B10, // 0317 GETMBR R10 R5 K16 + 0x582C0005, // 0318 LDCONST R11 K5 + 0x7C200600, // 0319 CALL R8 3 + 0x80041000, // 031A RET 1 R8 + 0x7002000E, // 031B JMP #032B + 0x1C200F0D, // 031C EQ R8 R7 K13 + 0x78220005, // 031D JMPF R8 #0324 + 0x8C200706, // 031E GETMET R8 R3 K6 + 0x88280B0E, // 031F GETMBR R10 R5 K14 + 0x582C0009, // 0320 LDCONST R11 K9 + 0x7C200600, // 0321 CALL R8 3 + 0x80041000, // 0322 RET 1 R8 + 0x70020006, // 0323 JMP #032B + 0x1C200F0F, // 0324 EQ R8 R7 K15 + 0x78220004, // 0325 JMPF R8 #032B + 0x8C200706, // 0326 GETMET R8 R3 K6 + 0x88280B18, // 0327 GETMBR R10 R5 K24 + 0x4C2C0000, // 0328 LDNIL R11 + 0x7C200600, // 0329 CALL R8 3 + 0x80041000, // 032A RET 1 R8 + 0x70020072, // 032B JMP #039F + 0x5422002A, // 032C LDINT R8 43 + 0x1C200C08, // 032D EQ R8 R6 R8 + 0x78220016, // 032E JMPF R8 #0346 + 0x1C200F05, // 032F EQ R8 R7 K5 + 0x78220007, // 0330 JMPF R8 #0339 + 0x8C200706, // 0331 GETMET R8 R3 K6 + 0x88280B16, // 0332 GETMBR R10 R5 K22 + 0xB82E2400, // 0333 GETNGBL R11 K18 + 0x8C2C1758, // 0334 GETMET R11 R11 K88 + 0x7C2C0200, // 0335 CALL R11 1 + 0x7C200600, // 0336 CALL R8 3 + 0x80041000, // 0337 RET 1 R8 + 0x7002000B, // 0338 JMP #0345 + 0x1C200F09, // 0339 EQ R8 R7 K9 + 0x78220009, // 033A JMPF R8 #0345 + 0x8C200B11, // 033B GETMET R8 R5 K17 + 0x7C200200, // 033C CALL R8 1 + 0x8C24110B, // 033D GETMET R9 R8 K11 + 0x4C2C0000, // 033E LDNIL R11 + 0x88300B16, // 033F GETMBR R12 R5 K22 + 0xB8362400, // 0340 GETNGBL R13 K18 + 0x8C341B58, // 0341 GETMET R13 R13 K88 + 0x7C340200, // 0342 CALL R13 1 + 0x7C240800, // 0343 CALL R9 4 + 0x80041000, // 0344 RET 1 R8 + 0x70020058, // 0345 JMP #039F + 0x5422002B, // 0346 LDINT R8 44 + 0x1C200C08, // 0347 EQ R8 R6 R8 + 0x7822001C, // 0348 JMPF R8 #0366 + 0x1C200F05, // 0349 EQ R8 R7 K5 + 0x78220005, // 034A JMPF R8 #0351 + 0x8C200706, // 034B GETMET R8 R3 K6 + 0x88280B0E, // 034C GETMBR R10 R5 K14 + 0x582C0009, // 034D LDCONST R11 K9 + 0x7C200600, // 034E CALL R8 3 + 0x80041000, // 034F RET 1 R8 + 0x70020013, // 0350 JMP #0365 + 0x1C200F09, // 0351 EQ R8 R7 K9 + 0x78220005, // 0352 JMPF R8 #0359 + 0x8C200706, // 0353 GETMET R8 R3 K6 + 0x88280B0E, // 0354 GETMBR R10 R5 K14 + 0x542E0003, // 0355 LDINT R11 4 + 0x7C200600, // 0356 CALL R8 3 + 0x80041000, // 0357 RET 1 R8 + 0x7002000B, // 0358 JMP #0365 + 0x1C200F0D, // 0359 EQ R8 R7 K13 + 0x78220009, // 035A JMPF R8 #0365 + 0x8C200B11, // 035B GETMET R8 R5 K17 + 0x7C200200, // 035C CALL R8 1 + 0x8C24110B, // 035D GETMET R9 R8 K11 + 0x4C2C0000, // 035E LDNIL R11 + 0x8C300B59, // 035F GETMET R12 R5 K89 + 0x88380B0E, // 0360 GETMBR R14 R5 K14 + 0x543E0003, // 0361 LDINT R15 4 + 0x7C300600, // 0362 CALL R12 3 + 0x7C240600, // 0363 CALL R9 3 + 0x80041000, // 0364 RET 1 R8 + 0x70020038, // 0365 JMP #039F + 0x54220030, // 0366 LDINT R8 49 + 0x1C200C08, // 0367 EQ R8 R6 R8 + 0x78220007, // 0368 JMPF R8 #0371 + 0x1C200F0F, // 0369 EQ R8 R7 K15 + 0x78220004, // 036A JMPF R8 #0370 + 0x8C200706, // 036B GETMET R8 R3 K6 + 0x88280B0E, // 036C GETMBR R10 R5 K14 + 0x542E001D, // 036D LDINT R11 30 + 0x7C200600, // 036E CALL R8 3 + 0x80041000, // 036F RET 1 R8 + 0x7002002D, // 0370 JMP #039F + 0x5422001C, // 0371 LDINT R8 29 + 0x1C200C08, // 0372 EQ R8 R6 R8 + 0x7822002A, // 0373 JMPF R8 #039F + 0x1C200F0D, // 0374 EQ R8 R7 K13 + 0x78220008, // 0375 JMPF R8 #037F + 0x8C200B11, // 0376 GETMET R8 R5 K17 + 0x7C200200, // 0377 CALL R8 1 + 0x8C24110B, // 0378 GETMET R9 R8 K11 + 0x4C2C0000, // 0379 LDNIL R11 + 0x88300B0C, // 037A GETMBR R12 R5 K12 + 0x5436001E, // 037B LDINT R13 31 + 0x7C240800, // 037C CALL R9 4 + 0x80041000, // 037D RET 1 R8 + 0x7002001F, // 037E JMP #039F + 0x1C200F0F, // 037F EQ R8 R7 K15 + 0x7822001D, // 0380 JMPF R8 #039F + 0x8C200B11, // 0381 GETMET R8 R5 K17 + 0x7C200200, // 0382 CALL R8 1 + 0x88240136, // 0383 GETMBR R9 R0 K54 + 0x8C24135A, // 0384 GETMET R9 R9 K90 + 0x502C0200, // 0385 LDBOOL R11 1 0 + 0x7C240400, // 0386 CALL R9 2 + 0x88280136, // 0387 GETMBR R10 R0 K54 + 0x8828155B, // 0388 GETMBR R10 R10 K91 + 0x602C0010, // 0389 GETGBL R11 G16 + 0x5C301200, // 038A MOVE R12 R9 + 0x7C2C0200, // 038B CALL R11 1 + 0xA802000D, // 038C EXBLK 0 #039B + 0x5C301600, // 038D MOVE R12 R11 + 0x7C300000, // 038E CALL R12 0 + 0x5C341400, // 038F MOVE R13 R10 + 0x78360003, // 0390 JMPF R13 #0395 + 0xB8360200, // 0391 GETNGBL R13 K1 + 0x88341B5C, // 0392 GETMBR R13 R13 K92 + 0x2034180D, // 0393 NE R13 R12 R13 + 0x78360004, // 0394 JMPF R13 #039A + 0x8C34110B, // 0395 GETMET R13 R8 K11 + 0x4C3C0000, // 0396 LDNIL R15 + 0x88400B0C, // 0397 GETMBR R16 R5 K12 + 0x5C441800, // 0398 MOVE R17 R12 + 0x7C340800, // 0399 CALL R13 4 + 0x7001FFF1, // 039A JMP #038D + 0x582C003E, // 039B LDCONST R11 K62 + 0xAC2C0200, // 039C CATCH R11 1 0 + 0xB0080000, // 039D RAISE 2 R0 R0 + 0x80041000, // 039E RET 1 R8 + 0x60200003, // 039F GETGBL R8 G3 + 0x5C240000, // 03A0 MOVE R9 R0 + 0x7C200200, // 03A1 CALL R8 1 + 0x8C20115D, // 03A2 GETMET R8 R8 K93 + 0x5C280200, // 03A3 MOVE R10 R1 + 0x5C2C0400, // 03A4 MOVE R11 R2 + 0x5C300600, // 03A5 MOVE R12 R3 + 0x7C200800, // 03A6 CALL R8 4 + 0x80041000, // 03A7 RET 1 R8 }) ) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session_Store.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session_Store.h index 4747ddfb1..d9f78535c 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session_Store.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session_Store.h @@ -7,91 +7,9 @@ extern const bclass be_class_Matter_Session_Store; /******************************************************************** -** Solidified function: create_fabric +** Solidified function: remove_session ********************************************************************/ -be_local_closure(Matter_Session_Store_create_fabric, /* name */ - be_nested_proto( - 4, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(matter), - /* K1 */ be_nested_str_weak(Fabric), - }), - be_str_weak(create_fabric), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0xB8060000, // 0000 GETNGBL R1 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x5C0C0000, // 0002 MOVE R3 R0 - 0x7C040400, // 0003 CALL R1 2 - 0x80040200, // 0004 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_session_by_source_node_id -********************************************************************/ -be_local_closure(Matter_Session_Store_get_session_by_source_node_id, /* name */ - be_nested_proto( - 8, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str_weak(_source_node_id), - /* K3 */ be_nested_str_weak(update), - /* K4 */ be_const_int(1), - }), - be_str_weak(get_session_by_source_node_id), - &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x1C080202, // 0001 EQ R2 R1 R2 - 0x780A0001, // 0002 JMPF R2 #0005 - 0x4C080000, // 0003 LDNIL R2 - 0x80040400, // 0004 RET 1 R2 - 0x6008000C, // 0005 GETGBL R2 G12 - 0x880C0100, // 0006 GETMBR R3 R0 K0 - 0x7C080200, // 0007 CALL R2 1 - 0x580C0001, // 0008 LDCONST R3 K1 - 0x88100100, // 0009 GETMBR R4 R0 K0 - 0x14140602, // 000A LT R5 R3 R2 - 0x78160008, // 000B JMPF R5 #0015 - 0x94140803, // 000C GETIDX R5 R4 R3 - 0x88180B02, // 000D GETMBR R6 R5 K2 - 0x1C180C01, // 000E EQ R6 R6 R1 - 0x781A0002, // 000F JMPF R6 #0013 - 0x8C180B03, // 0010 GETMET R6 R5 K3 - 0x7C180200, // 0011 CALL R6 1 - 0x80040A00, // 0012 RET 1 R5 - 0x000C0704, // 0013 ADD R3 R3 K4 - 0x7001FFF4, // 0014 JMP #000A - 0x80000000, // 0015 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: remove_redundant_fabric -********************************************************************/ -be_local_closure(Matter_Session_Store_remove_redundant_fabric, /* name */ +be_local_closure(Matter_Session_Store_remove_session, /* name */ be_nested_proto( 7, /* nstack */ 2, /* argc */ @@ -101,43 +19,32 @@ be_local_closure(Matter_Session_Store_remove_redundant_fabric, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ + ( &(const bvalue[ 4]) { /* constants */ /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(fabrics), - /* K2 */ be_nested_str_weak(fabric_id), - /* K3 */ be_nested_str_weak(device_id), - /* K4 */ be_nested_str_weak(remove), - /* K5 */ be_const_int(1), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(remove), + /* K3 */ be_const_int(1), }), - be_str_weak(remove_redundant_fabric), + be_str_weak(remove_session), &be_const_str_solidified, - ( &(const binstruction[26]) { /* code */ + ( &(const binstruction[17]) { /* code */ 0x58080000, // 0000 LDCONST R2 K0 - 0x600C000C, // 0001 GETGBL R3 G12 - 0x88100101, // 0002 GETMBR R4 R0 K1 - 0x7C0C0200, // 0003 CALL R3 1 - 0x140C0403, // 0004 LT R3 R2 R3 - 0x780E0012, // 0005 JMPF R3 #0019 - 0x880C0101, // 0006 GETMBR R3 R0 K1 - 0x940C0602, // 0007 GETIDX R3 R3 R2 - 0x20100601, // 0008 NE R4 R3 R1 - 0x7812000C, // 0009 JMPF R4 #0017 - 0x88100702, // 000A GETMBR R4 R3 K2 - 0x88140302, // 000B GETMBR R5 R1 K2 - 0x1C100805, // 000C EQ R4 R4 R5 - 0x78120008, // 000D JMPF R4 #0017 - 0x88100703, // 000E GETMBR R4 R3 K3 - 0x88140303, // 000F GETMBR R5 R1 K3 - 0x1C100805, // 0010 EQ R4 R4 R5 - 0x78120004, // 0011 JMPF R4 #0017 - 0x88100101, // 0012 GETMBR R4 R0 K1 - 0x8C100904, // 0013 GETMET R4 R4 K4 - 0x5C180400, // 0014 MOVE R6 R2 - 0x7C100400, // 0015 CALL R4 2 - 0x70020000, // 0016 JMP #0018 - 0x00080505, // 0017 ADD R2 R2 K5 - 0x7001FFE7, // 0018 JMP #0001 - 0x80000000, // 0019 RET 0 + 0x880C0101, // 0001 GETMBR R3 R0 K1 + 0x6010000C, // 0002 GETGBL R4 G12 + 0x88140101, // 0003 GETMBR R5 R0 K1 + 0x7C100200, // 0004 CALL R4 1 + 0x14100404, // 0005 LT R4 R2 R4 + 0x78120008, // 0006 JMPF R4 #0010 + 0x94100602, // 0007 GETIDX R4 R3 R2 + 0x1C100801, // 0008 EQ R4 R4 R1 + 0x78120003, // 0009 JMPF R4 #000E + 0x8C100702, // 000A GETMET R4 R3 K2 + 0x5C180400, // 000B MOVE R6 R2 + 0x7C100400, // 000C CALL R4 2 + 0x70020000, // 000D JMP #000F + 0x00080503, // 000E ADD R2 R2 K3 + 0x7001FFF1, // 000F JMP #0002 + 0x80000000, // 0010 RET 0 }) ) ); @@ -145,139 +52,11 @@ be_local_closure(Matter_Session_Store_remove_redundant_fabric, /* name */ /******************************************************************** -** Solidified function: active_fabrics +** Solidified function: gen_local_session_id ********************************************************************/ -be_local_closure(Matter_Session_Store_active_fabrics, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(remove_expired), - /* K1 */ be_nested_str_weak(fabrics), - /* K2 */ be_nested_str_weak(persistables), - }), - be_str_weak(active_fabrics), - &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x7C040200, // 0001 CALL R1 1 - 0x88040101, // 0002 GETMBR R1 R0 K1 - 0x8C040302, // 0003 GETMET R1 R1 K2 - 0x7C040200, // 0004 CALL R1 1 - 0x80040200, // 0005 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: find_children_fabrics -********************************************************************/ -be_local_closure(Matter_Session_Store_find_children_fabrics, /* name */ +be_local_closure(Matter_Session_Store_gen_local_session_id, /* name */ be_nested_proto( 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 1]) { - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 3]) { /* upvals */ - be_local_const_upval(1, 0), - be_local_const_upval(1, 2), - be_local_const_upval(1, 3), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(active_fabrics), - /* K1 */ be_nested_str_weak(fabric_parent), - /* K2 */ be_nested_str_weak(find), - /* K3 */ be_nested_str_weak(fabric_index), - /* K4 */ be_nested_str_weak(push), - /* K5 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(find_children_fabrics_inner), - &be_const_str_solidified, - ( &(const binstruction[30]) { /* code */ - 0x60040010, // 0000 GETGBL R1 G16 - 0x68080000, // 0001 GETUPV R2 U0 - 0x8C080500, // 0002 GETMET R2 R2 K0 - 0x7C080200, // 0003 CALL R2 1 - 0x7C040200, // 0004 CALL R1 1 - 0xA8020013, // 0005 EXBLK 0 #001A - 0x5C080200, // 0006 MOVE R2 R1 - 0x7C080000, // 0007 CALL R2 0 - 0x880C0501, // 0008 GETMBR R3 R2 K1 - 0x1C0C0600, // 0009 EQ R3 R3 R0 - 0x780E000D, // 000A JMPF R3 #0019 - 0x680C0001, // 000B GETUPV R3 U1 - 0x8C0C0702, // 000C GETMET R3 R3 K2 - 0x7C0C0200, // 000D CALL R3 1 - 0x4C100000, // 000E LDNIL R4 - 0x1C0C0604, // 000F EQ R3 R3 R4 - 0x780E0007, // 0010 JMPF R3 #0019 - 0x880C0503, // 0011 GETMBR R3 R2 K3 - 0x68100001, // 0012 GETUPV R4 U1 - 0x8C100904, // 0013 GETMET R4 R4 K4 - 0x5C180600, // 0014 MOVE R6 R3 - 0x7C100400, // 0015 CALL R4 2 - 0x68100002, // 0016 GETUPV R4 U2 - 0x5C140600, // 0017 MOVE R5 R3 - 0x7C100200, // 0018 CALL R4 1 - 0x7001FFEB, // 0019 JMP #0006 - 0x58040005, // 001A LDCONST R1 K5 - 0xAC040200, // 001B CATCH R1 1 0 - 0xB0080000, // 001C RAISE 2 R0 R0 - 0x80000000, // 001D RET 0 - }) - ), - }), - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(find_children_fabrics), - &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x1C080202, // 0001 EQ R2 R1 R2 - 0x780A0002, // 0002 JMPF R2 #0006 - 0x60080012, // 0003 GETGBL R2 G18 - 0x7C080000, // 0004 CALL R2 0 - 0x80040400, // 0005 RET 1 R2 - 0x60080012, // 0006 GETGBL R2 G18 - 0x7C080000, // 0007 CALL R2 0 - 0x400C0401, // 0008 CONNECT R3 R2 R1 - 0x840C0000, // 0009 CLOSURE R3 P0 - 0x5C100600, // 000A MOVE R4 R3 - 0x5C140200, // 000B MOVE R5 R1 - 0x7C100200, // 000C CALL R4 1 - 0xA0000000, // 000D CLOSE R0 - 0x80040400, // 000E RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: next_fabric_idx -********************************************************************/ -be_local_closure(Matter_Session_Store_next_fabric_idx, /* name */ - be_nested_proto( - 7, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -286,41 +65,35 @@ be_local_closure(Matter_Session_Store_next_fabric_idx, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(remove_expired), - /* K1 */ be_const_int(1), - /* K2 */ be_nested_str_weak(active_fabrics), - /* K3 */ be_nested_str_weak(fabric_index), - /* K4 */ be_nested_str_weak(int), - /* K5 */ be_nested_str_weak(stop_iteration), + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(random), + /* K2 */ be_const_int(2), + /* K3 */ be_nested_str_weak(get), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(get_session_by_local_session_id), }), - be_str_weak(next_fabric_idx), + be_str_weak(gen_local_session_id), &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x7C040200, // 0001 CALL R1 1 - 0x58040001, // 0002 LDCONST R1 K1 - 0x60080010, // 0003 GETGBL R2 G16 - 0x8C0C0102, // 0004 GETMET R3 R0 K2 - 0x7C0C0200, // 0005 CALL R3 1 - 0x7C080200, // 0006 CALL R2 1 - 0xA802000C, // 0007 EXBLK 0 #0015 - 0x5C0C0400, // 0008 MOVE R3 R2 - 0x7C0C0000, // 0009 CALL R3 0 - 0x88100703, // 000A GETMBR R4 R3 K3 - 0x60140004, // 000B GETGBL R5 G4 - 0x5C180800, // 000C MOVE R6 R4 - 0x7C140200, // 000D CALL R5 1 - 0x1C140B04, // 000E EQ R5 R5 K4 - 0x78160003, // 000F JMPF R5 #0014 - 0x28140801, // 0010 GE R5 R4 R1 - 0x78160001, // 0011 JMPF R5 #0014 - 0x00140901, // 0012 ADD R5 R4 K1 - 0x5C040A00, // 0013 MOVE R1 R5 - 0x7001FFF2, // 0014 JMP #0008 - 0x58080005, // 0015 LDCONST R2 K5 - 0xAC080200, // 0016 CATCH R2 1 0 - 0xB0080000, // 0017 RAISE 2 R0 R0 - 0x80040200, // 0018 RET 1 R1 + ( &(const binstruction[19]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x50080200, // 0001 LDBOOL R2 1 0 + 0x780A000E, // 0002 JMPF R2 #0012 + 0x8C080301, // 0003 GETMET R2 R1 K1 + 0x58100002, // 0004 LDCONST R4 K2 + 0x7C080400, // 0005 CALL R2 2 + 0x8C080503, // 0006 GETMET R2 R2 K3 + 0x58100004, // 0007 LDCONST R4 K4 + 0x58140002, // 0008 LDCONST R5 K2 + 0x7C080600, // 0009 CALL R2 3 + 0x8C0C0105, // 000A GETMET R3 R0 K5 + 0x5C140400, // 000B MOVE R5 R2 + 0x7C0C0400, // 000C CALL R3 2 + 0x4C100000, // 000D LDNIL R4 + 0x1C0C0604, // 000E EQ R3 R3 R4 + 0x780E0000, // 000F JMPF R3 #0011 + 0x80040400, // 0010 RET 1 R2 + 0x7001FFEE, // 0011 JMP #0001 + 0x80000000, // 0012 RET 0 }) ) ); @@ -496,11 +269,106 @@ be_local_closure(Matter_Session_Store_load_fabrics, /* name */ /******************************************************************** -** Solidified function: count_active_fabrics +** Solidified function: find_children_fabrics ********************************************************************/ -be_local_closure(Matter_Session_Store_count_active_fabrics, /* name */ +be_local_closure(Matter_Session_Store_find_children_fabrics, /* name */ be_nested_proto( - 3, /* nstack */ + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 3]) { /* upvals */ + be_local_const_upval(1, 0), + be_local_const_upval(1, 2), + be_local_const_upval(1, 3), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(active_fabrics), + /* K1 */ be_nested_str_weak(fabric_parent), + /* K2 */ be_nested_str_weak(find), + /* K3 */ be_nested_str_weak(fabric_index), + /* K4 */ be_nested_str_weak(push), + /* K5 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(find_children_fabrics_inner), + &be_const_str_solidified, + ( &(const binstruction[30]) { /* code */ + 0x60040010, // 0000 GETGBL R1 G16 + 0x68080000, // 0001 GETUPV R2 U0 + 0x8C080500, // 0002 GETMET R2 R2 K0 + 0x7C080200, // 0003 CALL R2 1 + 0x7C040200, // 0004 CALL R1 1 + 0xA8020013, // 0005 EXBLK 0 #001A + 0x5C080200, // 0006 MOVE R2 R1 + 0x7C080000, // 0007 CALL R2 0 + 0x880C0501, // 0008 GETMBR R3 R2 K1 + 0x1C0C0600, // 0009 EQ R3 R3 R0 + 0x780E000D, // 000A JMPF R3 #0019 + 0x680C0001, // 000B GETUPV R3 U1 + 0x8C0C0702, // 000C GETMET R3 R3 K2 + 0x7C0C0200, // 000D CALL R3 1 + 0x4C100000, // 000E LDNIL R4 + 0x1C0C0604, // 000F EQ R3 R3 R4 + 0x780E0007, // 0010 JMPF R3 #0019 + 0x880C0503, // 0011 GETMBR R3 R2 K3 + 0x68100001, // 0012 GETUPV R4 U1 + 0x8C100904, // 0013 GETMET R4 R4 K4 + 0x5C180600, // 0014 MOVE R6 R3 + 0x7C100400, // 0015 CALL R4 2 + 0x68100002, // 0016 GETUPV R4 U2 + 0x5C140600, // 0017 MOVE R5 R3 + 0x7C100200, // 0018 CALL R4 1 + 0x7001FFEB, // 0019 JMP #0006 + 0x58040005, // 001A LDCONST R1 K5 + 0xAC040200, // 001B CATCH R1 1 0 + 0xB0080000, // 001C RAISE 2 R0 R0 + 0x80000000, // 001D RET 0 + }) + ), + }), + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(find_children_fabrics), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0002, // 0002 JMPF R2 #0006 + 0x60080012, // 0003 GETGBL R2 G18 + 0x7C080000, // 0004 CALL R2 0 + 0x80040400, // 0005 RET 1 R2 + 0x60080012, // 0006 GETGBL R2 G18 + 0x7C080000, // 0007 CALL R2 0 + 0x400C0401, // 0008 CONNECT R3 R2 R1 + 0x840C0000, // 0009 CLOSURE R3 P0 + 0x5C100600, // 000A MOVE R4 R3 + 0x5C140200, // 000B MOVE R5 R1 + 0x7C100200, // 000C CALL R4 1 + 0xA0000000, // 000D CLOSE R0 + 0x80040400, // 000E RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: sessions_active +********************************************************************/ +be_local_closure(Matter_Session_Store_sessions_active, /* name */ + be_nested_proto( + 7, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -508,192 +376,39 @@ be_local_closure(Matter_Session_Store_count_active_fabrics, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(remove_expired), - /* K1 */ be_nested_str_weak(fabrics), - /* K2 */ be_nested_str_weak(count_persistables), - /* K3 */ be_const_int(0), - }), - be_str_weak(count_active_fabrics), - &be_const_str_solidified, - ( &(const binstruction[13]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x7C040200, // 0001 CALL R1 1 - 0x88040101, // 0002 GETMBR R1 R0 K1 - 0x4C080000, // 0003 LDNIL R2 - 0x20040202, // 0004 NE R1 R1 R2 - 0x78060004, // 0005 JMPF R1 #000B - 0x88040101, // 0006 GETMBR R1 R0 K1 - 0x8C040302, // 0007 GETMET R1 R1 K2 - 0x7C040200, // 0008 CALL R1 1 - 0x80040200, // 0009 RET 1 R1 - 0x70020000, // 000A JMP #000C - 0x80060600, // 000B RET 1 K3 - 0x80000000, // 000C RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: remove_fabric -********************************************************************/ -be_local_closure(Matter_Session_Store_remove_fabric, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str_weak(_fabric), - /* K3 */ be_nested_str_weak(remove), - /* K4 */ be_const_int(1), - /* K5 */ be_nested_str_weak(fabrics), - /* K6 */ be_nested_str_weak(find), - }), - be_str_weak(remove_fabric), - &be_const_str_solidified, - ( &(const binstruction[34]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x4C0C0000, // 0001 LDNIL R3 - 0x20080403, // 0002 NE R2 R2 R3 - 0x780A0011, // 0003 JMPF R2 #0016 - 0x58080001, // 0004 LDCONST R2 K1 - 0x600C000C, // 0005 GETGBL R3 G12 - 0x88100100, // 0006 GETMBR R4 R0 K0 - 0x7C0C0200, // 0007 CALL R3 1 - 0x140C0403, // 0008 LT R3 R2 R3 - 0x780E000B, // 0009 JMPF R3 #0016 - 0x880C0100, // 000A GETMBR R3 R0 K0 - 0x940C0602, // 000B GETIDX R3 R3 R2 - 0x880C0702, // 000C GETMBR R3 R3 K2 - 0x1C0C0601, // 000D EQ R3 R3 R1 - 0x780E0004, // 000E JMPF R3 #0014 - 0x880C0100, // 000F GETMBR R3 R0 K0 - 0x8C0C0703, // 0010 GETMET R3 R3 K3 - 0x5C140400, // 0011 MOVE R5 R2 - 0x7C0C0400, // 0012 CALL R3 2 - 0x70020000, // 0013 JMP #0015 - 0x00080504, // 0014 ADD R2 R2 K4 - 0x7001FFEE, // 0015 JMP #0005 - 0x88080105, // 0016 GETMBR R2 R0 K5 - 0x4C0C0000, // 0017 LDNIL R3 - 0x20080403, // 0018 NE R2 R2 R3 - 0x780A0006, // 0019 JMPF R2 #0021 - 0x88080105, // 001A GETMBR R2 R0 K5 - 0x8C080503, // 001B GETMET R2 R2 K3 - 0x88100105, // 001C GETMBR R4 R0 K5 - 0x8C100906, // 001D GETMET R4 R4 K6 - 0x5C180200, // 001E MOVE R6 R1 - 0x7C100400, // 001F CALL R4 2 - 0x7C080400, // 0020 CALL R2 2 - 0x80000000, // 0021 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: remove_session -********************************************************************/ -be_local_closure(Matter_Session_Store_remove_session, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ + ( &(const bvalue[ 6]) { /* constants */ /* K0 */ be_const_int(0), /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(remove), - /* K3 */ be_const_int(1), + /* K2 */ be_nested_str_weak(get_device_id), + /* K3 */ be_nested_str_weak(get_fabric_id), + /* K4 */ be_nested_str_weak(push), + /* K5 */ be_const_int(1), }), - be_str_weak(remove_session), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0x58080000, // 0000 LDCONST R2 K0 - 0x880C0101, // 0001 GETMBR R3 R0 K1 - 0x6010000C, // 0002 GETGBL R4 G12 - 0x88140101, // 0003 GETMBR R5 R0 K1 - 0x7C100200, // 0004 CALL R4 1 - 0x14100404, // 0005 LT R4 R2 R4 - 0x78120008, // 0006 JMPF R4 #0010 - 0x94100602, // 0007 GETIDX R4 R3 R2 - 0x1C100801, // 0008 EQ R4 R4 R1 - 0x78120003, // 0009 JMPF R4 #000E - 0x8C100702, // 000A GETMET R4 R3 K2 - 0x5C180400, // 000B MOVE R6 R2 - 0x7C100400, // 000C CALL R4 2 - 0x70020000, // 000D JMP #000F - 0x00080503, // 000E ADD R2 R2 K3 - 0x7001FFF1, // 000F JMP #0002 - 0x80000000, // 0010 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: add_fabric -********************************************************************/ -be_local_closure(Matter_Session_Store_add_fabric, /* name */ - be_nested_proto( - 5, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(matter), - /* K1 */ be_nested_str_weak(Fabric), - /* K2 */ be_nested_str_weak(value_error), - /* K3 */ be_nested_str_weak(must_X20be_X20of_X20class_X20matter_X2EFabric), - /* K4 */ be_nested_str_weak(fabrics), - /* K5 */ be_nested_str_weak(find), - /* K6 */ be_nested_str_weak(remove_redundant_fabric), - /* K7 */ be_nested_str_weak(push), - }), - be_str_weak(add_fabric), + be_str_weak(sessions_active), &be_const_str_solidified, ( &(const binstruction[22]) { /* code */ - 0x6008000F, // 0000 GETGBL R2 G15 - 0x5C0C0200, // 0001 MOVE R3 R1 - 0xB8120000, // 0002 GETNGBL R4 K0 - 0x88100901, // 0003 GETMBR R4 R4 K1 - 0x7C080400, // 0004 CALL R2 2 - 0x740A0000, // 0005 JMPT R2 #0007 - 0xB0060503, // 0006 RAISE 1 K2 K3 - 0x88080104, // 0007 GETMBR R2 R0 K4 - 0x8C080505, // 0008 GETMET R2 R2 K5 - 0x5C100200, // 0009 MOVE R4 R1 - 0x7C080400, // 000A CALL R2 2 - 0x4C0C0000, // 000B LDNIL R3 - 0x1C080403, // 000C EQ R2 R2 R3 - 0x780A0006, // 000D JMPF R2 #0015 - 0x8C080106, // 000E GETMET R2 R0 K6 - 0x5C100200, // 000F MOVE R4 R1 - 0x7C080400, // 0010 CALL R2 2 - 0x88080104, // 0011 GETMBR R2 R0 K4 - 0x8C080507, // 0012 GETMET R2 R2 K7 - 0x5C100200, // 0013 MOVE R4 R1 - 0x7C080400, // 0014 CALL R2 2 - 0x80000000, // 0015 RET 0 + 0x60040012, // 0000 GETGBL R1 G18 + 0x7C040000, // 0001 CALL R1 0 + 0x58080000, // 0002 LDCONST R2 K0 + 0x600C000C, // 0003 GETGBL R3 G12 + 0x88100101, // 0004 GETMBR R4 R0 K1 + 0x7C0C0200, // 0005 CALL R3 1 + 0x140C0403, // 0006 LT R3 R2 R3 + 0x780E000C, // 0007 JMPF R3 #0015 + 0x880C0101, // 0008 GETMBR R3 R0 K1 + 0x940C0602, // 0009 GETIDX R3 R3 R2 + 0x8C100702, // 000A GETMET R4 R3 K2 + 0x7C100200, // 000B CALL R4 1 + 0x78120005, // 000C JMPF R4 #0013 + 0x8C100703, // 000D GETMET R4 R3 K3 + 0x7C100200, // 000E CALL R4 1 + 0x78120002, // 000F JMPF R4 #0013 + 0x8C100304, // 0010 GETMET R4 R1 K4 + 0x5C180600, // 0011 MOVE R6 R3 + 0x7C100400, // 0012 CALL R4 2 + 0x00080505, // 0013 ADD R2 R2 K5 + 0x7001FFED, // 0014 JMP #0003 + 0x80040200, // 0015 RET 1 R1 }) ) ); @@ -747,9 +462,9 @@ be_local_closure(Matter_Session_Store_find_fabric_by_index, /* name */ /******************************************************************** -** Solidified function: remove_expired +** Solidified function: active_fabrics ********************************************************************/ -be_local_closure(Matter_Session_Store_remove_expired, /* name */ +be_local_closure(Matter_Session_Store_active_fabrics, /* name */ be_nested_proto( 3, /* nstack */ 1, /* argc */ @@ -760,227 +475,19 @@ be_local_closure(Matter_Session_Store_remove_expired, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_nested_str_weak(every_second), - /* K2 */ be_nested_str_weak(fabrics), - }), - be_str_weak(remove_expired), - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x7C040200, // 0002 CALL R1 1 - 0x88040102, // 0003 GETMBR R1 R0 K2 - 0x8C040301, // 0004 GETMET R1 R1 K1 - 0x7C040200, // 0005 CALL R1 1 - 0x80000000, // 0006 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: add_session -********************************************************************/ -be_local_closure(Matter_Session_Store_add_session, /* name */ - be_nested_proto( - 6, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(set_expire_in_seconds), - /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(push), - }), - be_str_weak(add_session), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x200C0403, // 0001 NE R3 R2 R3 - 0x780E0002, // 0002 JMPF R3 #0006 - 0x8C0C0300, // 0003 GETMET R3 R1 K0 - 0x5C140400, // 0004 MOVE R5 R2 - 0x7C0C0400, // 0005 CALL R3 2 - 0x880C0101, // 0006 GETMBR R3 R0 K1 - 0x8C0C0702, // 0007 GETMET R3 R3 K2 - 0x5C140200, // 0008 MOVE R5 R1 - 0x7C0C0400, // 0009 CALL R3 2 - 0x80000000, // 000A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: create_session -********************************************************************/ -be_local_closure(Matter_Session_Store_create_session, /* name */ - be_nested_proto( - 9, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(get_session_by_local_session_id), - /* K1 */ be_nested_str_weak(remove_session), - /* K2 */ be_nested_str_weak(matter), - /* K3 */ be_nested_str_weak(Session), - /* K4 */ be_nested_str_weak(sessions), - /* K5 */ be_nested_str_weak(push), - }), - be_str_weak(create_session), - &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x8C0C0100, // 0000 GETMET R3 R0 K0 - 0x5C140200, // 0001 MOVE R5 R1 - 0x7C0C0400, // 0002 CALL R3 2 - 0x4C100000, // 0003 LDNIL R4 - 0x20100604, // 0004 NE R4 R3 R4 - 0x78120002, // 0005 JMPF R4 #0009 - 0x8C100101, // 0006 GETMET R4 R0 K1 - 0x5C180600, // 0007 MOVE R6 R3 - 0x7C100400, // 0008 CALL R4 2 - 0xB8120400, // 0009 GETNGBL R4 K2 - 0x8C100903, // 000A GETMET R4 R4 K3 - 0x5C180000, // 000B MOVE R6 R0 - 0x5C1C0200, // 000C MOVE R7 R1 - 0x5C200400, // 000D MOVE R8 R2 - 0x7C100800, // 000E CALL R4 4 - 0x5C0C0800, // 000F MOVE R3 R4 - 0x88100104, // 0010 GETMBR R4 R0 K4 - 0x8C100905, // 0011 GETMET R4 R4 K5 - 0x5C180600, // 0012 MOVE R6 R3 - 0x7C100400, // 0013 CALL R4 2 - 0x80040600, // 0014 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Session_Store_init, /* name */ - be_nested_proto( - 4, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(device), - /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(matter), - /* K3 */ be_nested_str_weak(Expirable_list), - /* K4 */ be_nested_str_weak(fabrics), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0xB80A0400, // 0001 GETNGBL R2 K2 - 0x8C080503, // 0002 GETMET R2 R2 K3 - 0x7C080200, // 0003 CALL R2 1 - 0x90020202, // 0004 SETMBR R0 K1 R2 - 0xB80A0400, // 0005 GETNGBL R2 K2 - 0x8C080503, // 0006 GETMET R2 R2 K3 - 0x7C080200, // 0007 CALL R2 1 - 0x90020802, // 0008 SETMBR R0 K4 R2 - 0x80000000, // 0009 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_session_by_local_session_id -********************************************************************/ -be_local_closure(Matter_Session_Store_get_session_by_local_session_id, /* name */ - be_nested_proto( - 8, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str_weak(local_session_id), - /* K3 */ be_nested_str_weak(update), - /* K4 */ be_const_int(1), - }), - be_str_weak(get_session_by_local_session_id), - &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x1C080202, // 0001 EQ R2 R1 R2 - 0x780A0001, // 0002 JMPF R2 #0005 - 0x4C080000, // 0003 LDNIL R2 - 0x80040400, // 0004 RET 1 R2 - 0x6008000C, // 0005 GETGBL R2 G12 - 0x880C0100, // 0006 GETMBR R3 R0 K0 - 0x7C080200, // 0007 CALL R2 1 - 0x580C0001, // 0008 LDCONST R3 K1 - 0x88100100, // 0009 GETMBR R4 R0 K0 - 0x14140602, // 000A LT R5 R3 R2 - 0x78160008, // 000B JMPF R5 #0015 - 0x94140803, // 000C GETIDX R5 R4 R3 - 0x88180B02, // 000D GETMBR R6 R5 K2 - 0x1C180C01, // 000E EQ R6 R6 R1 - 0x781A0002, // 000F JMPF R6 #0013 - 0x8C180B03, // 0010 GETMET R6 R5 K3 - 0x7C180200, // 0011 CALL R6 1 - 0x80040A00, // 0012 RET 1 R5 - 0x000C0704, // 0013 ADD R3 R3 K4 - 0x7001FFF4, // 0014 JMP #000A - 0x80000000, // 0015 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: every_second -********************************************************************/ -be_local_closure(Matter_Session_Store_every_second, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ /* K0 */ be_nested_str_weak(remove_expired), + /* K1 */ be_nested_str_weak(fabrics), + /* K2 */ be_nested_str_weak(persistables), }), - be_str_weak(every_second), + be_str_weak(active_fabrics), &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ + ( &(const binstruction[ 6]) { /* code */ 0x8C040100, // 0000 GETMET R1 R0 K0 0x7C040200, // 0001 CALL R1 1 - 0x80000000, // 0002 RET 0 + 0x88040101, // 0002 GETMBR R1 R0 K1 + 0x8C040302, // 0003 GETMET R1 R1 K2 + 0x7C040200, // 0004 CALL R1 1 + 0x80040200, // 0005 RET 1 R1 }) ) ); @@ -988,68 +495,11 @@ be_local_closure(Matter_Session_Store_every_second, /* name */ /******************************************************************** -** Solidified function: find_session_source_id_unsecure +** Solidified function: create_fabric ********************************************************************/ -be_local_closure(Matter_Session_Store_find_session_source_id_unsecure, /* name */ +be_local_closure(Matter_Session_Store_create_fabric, /* name */ be_nested_proto( - 9, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_nested_str_weak(get_session_by_source_node_id), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(Session), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str_weak(_source_node_id), - /* K5 */ be_nested_str_weak(sessions), - /* K6 */ be_nested_str_weak(push), - /* K7 */ be_nested_str_weak(set_expire_in_seconds), - /* K8 */ be_nested_str_weak(update), - }), - be_str_weak(find_session_source_id_unsecure), - &be_const_str_solidified, - ( &(const binstruction[24]) { /* code */ - 0x8C0C0100, // 0000 GETMET R3 R0 K0 - 0x5C140200, // 0001 MOVE R5 R1 - 0x7C0C0400, // 0002 CALL R3 2 - 0x4C100000, // 0003 LDNIL R4 - 0x1C100604, // 0004 EQ R4 R3 R4 - 0x7812000E, // 0005 JMPF R4 #0015 - 0xB8120200, // 0006 GETNGBL R4 K1 - 0x8C100902, // 0007 GETMET R4 R4 K2 - 0x5C180000, // 0008 MOVE R6 R0 - 0x581C0003, // 0009 LDCONST R7 K3 - 0x58200003, // 000A LDCONST R8 K3 - 0x7C100800, // 000B CALL R4 4 - 0x5C0C0800, // 000C MOVE R3 R4 - 0x900E0801, // 000D SETMBR R3 K4 R1 - 0x88100105, // 000E GETMBR R4 R0 K5 - 0x8C100906, // 000F GETMET R4 R4 K6 - 0x5C180600, // 0010 MOVE R6 R3 - 0x7C100400, // 0011 CALL R4 2 - 0x8C100707, // 0012 GETMET R4 R3 K7 - 0x5C180400, // 0013 MOVE R6 R2 - 0x7C100400, // 0014 CALL R4 2 - 0x8C100708, // 0015 GETMET R4 R3 K8 - 0x7C100200, // 0016 CALL R4 1 - 0x80040600, // 0017 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: sessions_active -********************************************************************/ -be_local_closure(Matter_Session_Store_sessions_active, /* name */ - be_nested_proto( - 7, /* nstack */ + 4, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1057,39 +507,59 @@ be_local_closure(Matter_Session_Store_sessions_active, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(get_device_id), - /* K3 */ be_nested_str_weak(get_fabric_id), - /* K4 */ be_nested_str_weak(push), - /* K5 */ be_const_int(1), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(Fabric), }), - be_str_weak(sessions_active), + be_str_weak(create_fabric), &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0x60040012, // 0000 GETGBL R1 G18 - 0x7C040000, // 0001 CALL R1 0 - 0x58080000, // 0002 LDCONST R2 K0 - 0x600C000C, // 0003 GETGBL R3 G12 - 0x88100101, // 0004 GETMBR R4 R0 K1 - 0x7C0C0200, // 0005 CALL R3 1 - 0x140C0403, // 0006 LT R3 R2 R3 - 0x780E000C, // 0007 JMPF R3 #0015 - 0x880C0101, // 0008 GETMBR R3 R0 K1 - 0x940C0602, // 0009 GETIDX R3 R3 R2 - 0x8C100702, // 000A GETMET R4 R3 K2 - 0x7C100200, // 000B CALL R4 1 - 0x78120005, // 000C JMPF R4 #0013 - 0x8C100703, // 000D GETMET R4 R3 K3 - 0x7C100200, // 000E CALL R4 1 - 0x78120002, // 000F JMPF R4 #0013 - 0x8C100304, // 0010 GETMET R4 R1 K4 - 0x5C180600, // 0011 MOVE R6 R3 - 0x7C100400, // 0012 CALL R4 2 - 0x00080505, // 0013 ADD R2 R2 K5 - 0x7001FFED, // 0014 JMP #0003 - 0x80040200, // 0015 RET 1 R1 + ( &(const binstruction[ 5]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x5C0C0000, // 0002 MOVE R3 R0 + 0x7C040400, // 0003 CALL R1 2 + 0x80040200, // 0004 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: count_active_fabrics +********************************************************************/ +be_local_closure(Matter_Session_Store_count_active_fabrics, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(remove_expired), + /* K1 */ be_nested_str_weak(fabrics), + /* K2 */ be_nested_str_weak(count_persistables), + /* K3 */ be_const_int(0), + }), + be_str_weak(count_active_fabrics), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x88040101, // 0002 GETMBR R1 R0 K1 + 0x4C080000, // 0003 LDNIL R2 + 0x20040202, // 0004 NE R1 R1 R2 + 0x78060004, // 0005 JMPF R1 #000B + 0x88040101, // 0006 GETMBR R1 R0 K1 + 0x8C040302, // 0007 GETMET R1 R1 K2 + 0x7C040200, // 0008 CALL R1 1 + 0x80040200, // 0009 RET 1 R1 + 0x70020000, // 000A JMP #000C + 0x80060600, // 000B RET 1 K3 + 0x80000000, // 000C RET 0 }) ) ); @@ -1168,133 +638,37 @@ be_local_closure(Matter_Session_Store_find_session_by_resumption_id, /* name * /******************************************************************** -** Solidified function: save_fabrics +** Solidified function: add_session ********************************************************************/ -be_local_closure(Matter_Session_Store_save_fabrics, /* name */ +be_local_closure(Matter_Session_Store_add_session, /* name */ be_nested_proto( - 11, /* nstack */ - 1, /* argc */ + 6, /* nstack */ + 3, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[24]) { /* constants */ - /* K0 */ be_nested_str_weak(json), - /* K1 */ be_nested_str_weak(remove_expired), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(_FABRICS), - /* K4 */ be_nested_str_weak(w), - /* K5 */ be_nested_str_weak(write), - /* K6 */ be_nested_str_weak(_X5B), - /* K7 */ be_nested_str_weak(fabrics), - /* K8 */ be_nested_str_weak(persistables), - /* K9 */ be_nested_str_weak(_sessions), - /* K10 */ be_const_int(1), - /* K11 */ be_nested_str_weak(stop_iteration), - /* K12 */ be_nested_str_weak(_X2C), - /* K13 */ be_nested_str_weak(tojson), - /* K14 */ be_nested_str_weak(_X5D), - /* K15 */ be_nested_str_weak(close), - /* K16 */ be_nested_str_weak(tasmota), - /* K17 */ be_nested_str_weak(log), - /* K18 */ be_nested_str_weak(MTR_X3A_X20_X3DSaved_X20_X20_X20_X20_X20_X25s_X20fabric_X28s_X29_X20and_X20_X25s_X20session_X28s_X29), - /* K19 */ be_const_int(2), - /* K20 */ be_nested_str_weak(device), - /* K21 */ be_nested_str_weak(event_fabrics_saved), - /* K22 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), - /* K23 */ be_nested_str_weak(_X7C), + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(set_expire_in_seconds), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(push), }), - be_str_weak(save_fabrics), + be_str_weak(add_session), &be_const_str_solidified, - ( &(const binstruction[86]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0xA8020041, // 0001 EXBLK 0 #0044 - 0x8C080101, // 0002 GETMET R2 R0 K1 - 0x7C080200, // 0003 CALL R2 1 - 0x58080002, // 0004 LDCONST R2 K2 - 0x580C0002, // 0005 LDCONST R3 K2 - 0x60100011, // 0006 GETGBL R4 G17 - 0x88140103, // 0007 GETMBR R5 R0 K3 - 0x58180004, // 0008 LDCONST R6 K4 - 0x7C100400, // 0009 CALL R4 2 - 0x8C140905, // 000A GETMET R5 R4 K5 - 0x581C0006, // 000B LDCONST R7 K6 - 0x7C140400, // 000C CALL R5 2 - 0x60140010, // 000D GETGBL R5 G16 - 0x88180107, // 000E GETMBR R6 R0 K7 - 0x8C180D08, // 000F GETMET R6 R6 K8 - 0x7C180200, // 0010 CALL R6 1 - 0x7C140200, // 0011 CALL R5 1 - 0xA802001A, // 0012 EXBLK 0 #002E - 0x5C180A00, // 0013 MOVE R6 R5 - 0x7C180000, // 0014 CALL R6 0 - 0x601C0010, // 0015 GETGBL R7 G16 - 0x88200D09, // 0016 GETMBR R8 R6 K9 - 0x8C201108, // 0017 GETMET R8 R8 K8 - 0x7C200200, // 0018 CALL R8 1 - 0x7C1C0200, // 0019 CALL R7 1 - 0xA8020003, // 001A EXBLK 0 #001F - 0x5C200E00, // 001B MOVE R8 R7 - 0x7C200000, // 001C CALL R8 0 - 0x0008050A, // 001D ADD R2 R2 K10 - 0x7001FFFB, // 001E JMP #001B - 0x581C000B, // 001F LDCONST R7 K11 - 0xAC1C0200, // 0020 CATCH R7 1 0 - 0xB0080000, // 0021 RAISE 2 R0 R0 - 0x241C0702, // 0022 GT R7 R3 K2 - 0x781E0002, // 0023 JMPF R7 #0027 - 0x8C1C0905, // 0024 GETMET R7 R4 K5 - 0x5824000C, // 0025 LDCONST R9 K12 - 0x7C1C0400, // 0026 CALL R7 2 - 0x8C1C0D0D, // 0027 GETMET R7 R6 K13 - 0x7C1C0200, // 0028 CALL R7 1 - 0x8C200905, // 0029 GETMET R8 R4 K5 - 0x5C280E00, // 002A MOVE R10 R7 - 0x7C200400, // 002B CALL R8 2 - 0x000C070A, // 002C ADD R3 R3 K10 - 0x7001FFE4, // 002D JMP #0013 - 0x5814000B, // 002E LDCONST R5 K11 - 0xAC140200, // 002F CATCH R5 1 0 - 0xB0080000, // 0030 RAISE 2 R0 R0 - 0x8C140905, // 0031 GETMET R5 R4 K5 - 0x581C000E, // 0032 LDCONST R7 K14 - 0x7C140400, // 0033 CALL R5 2 - 0x8C14090F, // 0034 GETMET R5 R4 K15 - 0x7C140200, // 0035 CALL R5 1 - 0xB8162000, // 0036 GETNGBL R5 K16 - 0x8C140B11, // 0037 GETMET R5 R5 K17 - 0x601C0018, // 0038 GETGBL R7 G24 - 0x58200012, // 0039 LDCONST R8 K18 - 0x5C240600, // 003A MOVE R9 R3 - 0x5C280400, // 003B MOVE R10 R2 - 0x7C1C0600, // 003C CALL R7 3 - 0x58200013, // 003D LDCONST R8 K19 - 0x7C140600, // 003E CALL R5 3 - 0x88140114, // 003F GETMBR R5 R0 K20 - 0x8C140B15, // 0040 GETMET R5 R5 K21 - 0x7C140200, // 0041 CALL R5 1 - 0xA8040001, // 0042 EXBLK 1 1 - 0x70020010, // 0043 JMP #0055 - 0xAC080002, // 0044 CATCH R2 0 2 - 0x7002000D, // 0045 JMP #0054 - 0xB8122000, // 0046 GETNGBL R4 K16 - 0x8C100911, // 0047 GETMET R4 R4 K17 - 0x60180008, // 0048 GETGBL R6 G8 - 0x5C1C0400, // 0049 MOVE R7 R2 - 0x7C180200, // 004A CALL R6 1 - 0x001A2C06, // 004B ADD R6 K22 R6 - 0x00180D17, // 004C ADD R6 R6 K23 - 0x601C0008, // 004D GETGBL R7 G8 - 0x5C200600, // 004E MOVE R8 R3 - 0x7C1C0200, // 004F CALL R7 1 - 0x00180C07, // 0050 ADD R6 R6 R7 - 0x581C0013, // 0051 LDCONST R7 K19 - 0x7C100600, // 0052 CALL R4 3 - 0x70020000, // 0053 JMP #0055 - 0xB0080000, // 0054 RAISE 2 R0 R0 - 0x80000000, // 0055 RET 0 + ( &(const binstruction[11]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x200C0403, // 0001 NE R3 R2 R3 + 0x780E0002, // 0002 JMPF R3 #0006 + 0x8C0C0300, // 0003 GETMET R3 R1 K0 + 0x5C140400, // 0004 MOVE R5 R2 + 0x7C0C0400, // 0005 CALL R3 2 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x8C0C0702, // 0007 GETMET R3 R3 K2 + 0x5C140200, // 0008 MOVE R5 R1 + 0x7C0C0400, // 0009 CALL R3 2 + 0x80000000, // 000A RET 0 }) ) ); @@ -1302,11 +676,381 @@ be_local_closure(Matter_Session_Store_save_fabrics, /* name */ /******************************************************************** -** Solidified function: gen_local_session_id +** Solidified function: find_session_source_id_unsecure ********************************************************************/ -be_local_closure(Matter_Session_Store_gen_local_session_id, /* name */ +be_local_closure(Matter_Session_Store_find_session_source_id_unsecure, /* name */ be_nested_proto( - 6, /* nstack */ + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(get_session_by_source_node_id), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(Session), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(_source_node_id), + /* K5 */ be_nested_str_weak(sessions), + /* K6 */ be_nested_str_weak(push), + /* K7 */ be_nested_str_weak(set_expire_in_seconds), + /* K8 */ be_nested_str_weak(update), + }), + be_str_weak(find_session_source_id_unsecure), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140200, // 0001 MOVE R5 R1 + 0x7C0C0400, // 0002 CALL R3 2 + 0x4C100000, // 0003 LDNIL R4 + 0x1C100604, // 0004 EQ R4 R3 R4 + 0x7812000E, // 0005 JMPF R4 #0015 + 0xB8120200, // 0006 GETNGBL R4 K1 + 0x8C100902, // 0007 GETMET R4 R4 K2 + 0x5C180000, // 0008 MOVE R6 R0 + 0x581C0003, // 0009 LDCONST R7 K3 + 0x58200003, // 000A LDCONST R8 K3 + 0x7C100800, // 000B CALL R4 4 + 0x5C0C0800, // 000C MOVE R3 R4 + 0x900E0801, // 000D SETMBR R3 K4 R1 + 0x88100105, // 000E GETMBR R4 R0 K5 + 0x8C100906, // 000F GETMET R4 R4 K6 + 0x5C180600, // 0010 MOVE R6 R3 + 0x7C100400, // 0011 CALL R4 2 + 0x8C100707, // 0012 GETMET R4 R3 K7 + 0x5C180400, // 0013 MOVE R6 R2 + 0x7C100400, // 0014 CALL R4 2 + 0x8C100708, // 0015 GETMET R4 R3 K8 + 0x7C100200, // 0016 CALL R4 1 + 0x80040600, // 0017 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_Session_Store_every_second, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(remove_expired), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_session_by_local_session_id +********************************************************************/ +be_local_closure(Matter_Session_Store_get_session_by_local_session_id, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(local_session_id), + /* K3 */ be_nested_str_weak(update), + /* K4 */ be_const_int(1), + }), + be_str_weak(get_session_by_local_session_id), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x6008000C, // 0005 GETGBL R2 G12 + 0x880C0100, // 0006 GETMBR R3 R0 K0 + 0x7C080200, // 0007 CALL R2 1 + 0x580C0001, // 0008 LDCONST R3 K1 + 0x88100100, // 0009 GETMBR R4 R0 K0 + 0x14140602, // 000A LT R5 R3 R2 + 0x78160008, // 000B JMPF R5 #0015 + 0x94140803, // 000C GETIDX R5 R4 R3 + 0x88180B02, // 000D GETMBR R6 R5 K2 + 0x1C180C01, // 000E EQ R6 R6 R1 + 0x781A0002, // 000F JMPF R6 #0013 + 0x8C180B03, // 0010 GETMET R6 R5 K3 + 0x7C180200, // 0011 CALL R6 1 + 0x80040A00, // 0012 RET 1 R5 + 0x000C0704, // 0013 ADD R3 R3 K4 + 0x7001FFF4, // 0014 JMP #000A + 0x80000000, // 0015 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Session_Store_init, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(Expirable_list), + /* K4 */ be_nested_str_weak(fabrics), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0xB80A0400, // 0001 GETNGBL R2 K2 + 0x8C080503, // 0002 GETMET R2 R2 K3 + 0x7C080200, // 0003 CALL R2 1 + 0x90020202, // 0004 SETMBR R0 K1 R2 + 0xB80A0400, // 0005 GETNGBL R2 K2 + 0x8C080503, // 0006 GETMET R2 R2 K3 + 0x7C080200, // 0007 CALL R2 1 + 0x90020802, // 0008 SETMBR R0 K4 R2 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_expired +********************************************************************/ +be_local_closure(Matter_Session_Store_remove_expired, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_nested_str_weak(every_second), + /* K2 */ be_nested_str_weak(fabrics), + }), + be_str_weak(remove_expired), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x88040102, // 0003 GETMBR R1 R0 K2 + 0x8C040301, // 0004 GETMET R1 R1 K1 + 0x7C040200, // 0005 CALL R1 1 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_redundant_fabric +********************************************************************/ +be_local_closure(Matter_Session_Store_remove_redundant_fabric, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(fabrics), + /* K2 */ be_nested_str_weak(fabric_id), + /* K3 */ be_nested_str_weak(device_id), + /* K4 */ be_nested_str_weak(remove), + /* K5 */ be_const_int(1), + }), + be_str_weak(remove_redundant_fabric), + &be_const_str_solidified, + ( &(const binstruction[26]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0x600C000C, // 0001 GETGBL R3 G12 + 0x88100101, // 0002 GETMBR R4 R0 K1 + 0x7C0C0200, // 0003 CALL R3 1 + 0x140C0403, // 0004 LT R3 R2 R3 + 0x780E0012, // 0005 JMPF R3 #0019 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x940C0602, // 0007 GETIDX R3 R3 R2 + 0x20100601, // 0008 NE R4 R3 R1 + 0x7812000C, // 0009 JMPF R4 #0017 + 0x88100702, // 000A GETMBR R4 R3 K2 + 0x88140302, // 000B GETMBR R5 R1 K2 + 0x1C100805, // 000C EQ R4 R4 R5 + 0x78120008, // 000D JMPF R4 #0017 + 0x88100703, // 000E GETMBR R4 R3 K3 + 0x88140303, // 000F GETMBR R5 R1 K3 + 0x1C100805, // 0010 EQ R4 R4 R5 + 0x78120004, // 0011 JMPF R4 #0017 + 0x88100101, // 0012 GETMBR R4 R0 K1 + 0x8C100904, // 0013 GETMET R4 R4 K4 + 0x5C180400, // 0014 MOVE R6 R2 + 0x7C100400, // 0015 CALL R4 2 + 0x70020000, // 0016 JMP #0018 + 0x00080505, // 0017 ADD R2 R2 K5 + 0x7001FFE7, // 0018 JMP #0001 + 0x80000000, // 0019 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_fabric +********************************************************************/ +be_local_closure(Matter_Session_Store_add_fabric, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(Fabric), + /* K2 */ be_nested_str_weak(value_error), + /* K3 */ be_nested_str_weak(must_X20be_X20of_X20class_X20matter_X2EFabric), + /* K4 */ be_nested_str_weak(fabrics), + /* K5 */ be_nested_str_weak(find), + /* K6 */ be_nested_str_weak(remove_redundant_fabric), + /* K7 */ be_nested_str_weak(push), + }), + be_str_weak(add_fabric), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x6008000F, // 0000 GETGBL R2 G15 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0xB8120000, // 0002 GETNGBL R4 K0 + 0x88100901, // 0003 GETMBR R4 R4 K1 + 0x7C080400, // 0004 CALL R2 2 + 0x740A0000, // 0005 JMPT R2 #0007 + 0xB0060503, // 0006 RAISE 1 K2 K3 + 0x88080104, // 0007 GETMBR R2 R0 K4 + 0x8C080505, // 0008 GETMET R2 R2 K5 + 0x5C100200, // 0009 MOVE R4 R1 + 0x7C080400, // 000A CALL R2 2 + 0x4C0C0000, // 000B LDNIL R3 + 0x1C080403, // 000C EQ R2 R2 R3 + 0x780A0006, // 000D JMPF R2 #0015 + 0x8C080106, // 000E GETMET R2 R0 K6 + 0x5C100200, // 000F MOVE R4 R1 + 0x7C080400, // 0010 CALL R2 2 + 0x88080104, // 0011 GETMBR R2 R0 K4 + 0x8C080507, // 0012 GETMET R2 R2 K7 + 0x5C100200, // 0013 MOVE R4 R1 + 0x7C080400, // 0014 CALL R2 2 + 0x80000000, // 0015 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_session_by_source_node_id +********************************************************************/ +be_local_closure(Matter_Session_Store_get_session_by_source_node_id, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(_source_node_id), + /* K3 */ be_nested_str_weak(update), + /* K4 */ be_const_int(1), + }), + be_str_weak(get_session_by_source_node_id), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x6008000C, // 0005 GETGBL R2 G12 + 0x880C0100, // 0006 GETMBR R3 R0 K0 + 0x7C080200, // 0007 CALL R2 1 + 0x580C0001, // 0008 LDCONST R3 K1 + 0x88100100, // 0009 GETMBR R4 R0 K0 + 0x14140602, // 000A LT R5 R3 R2 + 0x78160008, // 000B JMPF R5 #0015 + 0x94140803, // 000C GETIDX R5 R4 R3 + 0x88180B02, // 000D GETMBR R6 R5 K2 + 0x1C180C01, // 000E EQ R6 R6 R1 + 0x781A0002, // 000F JMPF R6 #0013 + 0x8C180B03, // 0010 GETMET R6 R5 K3 + 0x7C180200, // 0011 CALL R6 1 + 0x80040A00, // 0012 RET 1 R5 + 0x000C0704, // 0013 ADD R3 R3 K4 + 0x7001FFF4, // 0014 JMP #000A + 0x80000000, // 0015 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: next_fabric_idx +********************************************************************/ +be_local_closure(Matter_Session_Store_next_fabric_idx, /* name */ + be_nested_proto( + 7, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1315,35 +1059,311 @@ be_local_closure(Matter_Session_Store_gen_local_session_id, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(random), - /* K2 */ be_const_int(2), - /* K3 */ be_nested_str_weak(get), - /* K4 */ be_const_int(0), - /* K5 */ be_nested_str_weak(get_session_by_local_session_id), + /* K0 */ be_nested_str_weak(remove_expired), + /* K1 */ be_const_int(1), + /* K2 */ be_nested_str_weak(active_fabrics), + /* K3 */ be_nested_str_weak(fabric_index), + /* K4 */ be_nested_str_weak(int), + /* K5 */ be_nested_str_weak(stop_iteration), }), - be_str_weak(gen_local_session_id), + be_str_weak(next_fabric_idx), &be_const_str_solidified, - ( &(const binstruction[19]) { /* code */ + ( &(const binstruction[25]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x58040001, // 0002 LDCONST R1 K1 + 0x60080010, // 0003 GETGBL R2 G16 + 0x8C0C0102, // 0004 GETMET R3 R0 K2 + 0x7C0C0200, // 0005 CALL R3 1 + 0x7C080200, // 0006 CALL R2 1 + 0xA802000C, // 0007 EXBLK 0 #0015 + 0x5C0C0400, // 0008 MOVE R3 R2 + 0x7C0C0000, // 0009 CALL R3 0 + 0x88100703, // 000A GETMBR R4 R3 K3 + 0x60140004, // 000B GETGBL R5 G4 + 0x5C180800, // 000C MOVE R6 R4 + 0x7C140200, // 000D CALL R5 1 + 0x1C140B04, // 000E EQ R5 R5 K4 + 0x78160003, // 000F JMPF R5 #0014 + 0x28140801, // 0010 GE R5 R4 R1 + 0x78160001, // 0011 JMPF R5 #0014 + 0x00140901, // 0012 ADD R5 R4 K1 + 0x5C040A00, // 0013 MOVE R1 R5 + 0x7001FFF2, // 0014 JMP #0008 + 0x58080005, // 0015 LDCONST R2 K5 + 0xAC080200, // 0016 CATCH R2 1 0 + 0xB0080000, // 0017 RAISE 2 R0 R0 + 0x80040200, // 0018 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: save_fabrics +********************************************************************/ +be_local_closure(Matter_Session_Store_save_fabrics, /* name */ + be_nested_proto( + 12, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[29]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(path), + /* K2 */ be_nested_str_weak(remove_expired), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(_FABRICS_TEMP), + /* K5 */ be_nested_str_weak(w), + /* K6 */ be_nested_str_weak(write), + /* K7 */ be_nested_str_weak(_X5B), + /* K8 */ be_nested_str_weak(fabrics), + /* K9 */ be_nested_str_weak(persistables), + /* K10 */ be_nested_str_weak(_sessions), + /* K11 */ be_const_int(1), + /* K12 */ be_nested_str_weak(stop_iteration), + /* K13 */ be_nested_str_weak(_X2C), + /* K14 */ be_nested_str_weak(writejson), + /* K15 */ be_nested_str_weak(_X5D), + /* K16 */ be_nested_str_weak(close), + /* K17 */ be_nested_str_weak(remove), + /* K18 */ be_nested_str_weak(_FABRICS), + /* K19 */ be_nested_str_weak(rename), + /* K20 */ be_nested_str_weak(tasmota), + /* K21 */ be_nested_str_weak(log), + /* K22 */ be_nested_str_weak(MTR_X3A_X20_X3DSaved_X20_X20_X20_X20_X20_X25s_X20fabric_X28s_X29_X20and_X20_X25s_X20session_X28s_X29), + /* K23 */ be_const_int(2), + /* K24 */ be_nested_str_weak(device), + /* K25 */ be_nested_str_weak(event_fabrics_saved), + /* K26 */ be_nested_str_weak(MTR_X3A_X20Saving_X20Fabrics_X20failed), + /* K27 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), + /* K28 */ be_nested_str_weak(_X7C), + }), + be_str_weak(save_fabrics), + &be_const_str_solidified, + ( &(const binstruction[101]) { /* code */ 0xA4060000, // 0000 IMPORT R1 K0 - 0x50080200, // 0001 LDBOOL R2 1 0 - 0x780A000E, // 0002 JMPF R2 #0012 - 0x8C080301, // 0003 GETMET R2 R1 K1 - 0x58100002, // 0004 LDCONST R4 K2 - 0x7C080400, // 0005 CALL R2 2 - 0x8C080503, // 0006 GETMET R2 R2 K3 - 0x58100004, // 0007 LDCONST R4 K4 - 0x58140002, // 0008 LDCONST R5 K2 - 0x7C080600, // 0009 CALL R2 3 - 0x8C0C0105, // 000A GETMET R3 R0 K5 - 0x5C140400, // 000B MOVE R5 R2 - 0x7C0C0400, // 000C CALL R3 2 - 0x4C100000, // 000D LDNIL R4 - 0x1C0C0604, // 000E EQ R3 R3 R4 - 0x780E0000, // 000F JMPF R3 #0011 - 0x80040400, // 0010 RET 1 R2 - 0x7001FFEE, // 0011 JMP #0001 - 0x80000000, // 0012 RET 0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xA802004F, // 0002 EXBLK 0 #0053 + 0x8C0C0102, // 0003 GETMET R3 R0 K2 + 0x7C0C0200, // 0004 CALL R3 1 + 0x580C0003, // 0005 LDCONST R3 K3 + 0x58100003, // 0006 LDCONST R4 K3 + 0x60140011, // 0007 GETGBL R5 G17 + 0x88180104, // 0008 GETMBR R6 R0 K4 + 0x581C0005, // 0009 LDCONST R7 K5 + 0x7C140400, // 000A CALL R5 2 + 0x8C180B06, // 000B GETMET R6 R5 K6 + 0x58200007, // 000C LDCONST R8 K7 + 0x7C180400, // 000D CALL R6 2 + 0x60180010, // 000E GETGBL R6 G16 + 0x881C0108, // 000F GETMBR R7 R0 K8 + 0x8C1C0F09, // 0010 GETMET R7 R7 K9 + 0x7C1C0200, // 0011 CALL R7 1 + 0x7C180200, // 0012 CALL R6 1 + 0xA8020018, // 0013 EXBLK 0 #002D + 0x5C1C0C00, // 0014 MOVE R7 R6 + 0x7C1C0000, // 0015 CALL R7 0 + 0x60200010, // 0016 GETGBL R8 G16 + 0x88240F0A, // 0017 GETMBR R9 R7 K10 + 0x8C241309, // 0018 GETMET R9 R9 K9 + 0x7C240200, // 0019 CALL R9 1 + 0x7C200200, // 001A CALL R8 1 + 0xA8020003, // 001B EXBLK 0 #0020 + 0x5C241000, // 001C MOVE R9 R8 + 0x7C240000, // 001D CALL R9 0 + 0x000C070B, // 001E ADD R3 R3 K11 + 0x7001FFFB, // 001F JMP #001C + 0x5820000C, // 0020 LDCONST R8 K12 + 0xAC200200, // 0021 CATCH R8 1 0 + 0xB0080000, // 0022 RAISE 2 R0 R0 + 0x24200903, // 0023 GT R8 R4 K3 + 0x78220002, // 0024 JMPF R8 #0028 + 0x8C200B06, // 0025 GETMET R8 R5 K6 + 0x5828000D, // 0026 LDCONST R10 K13 + 0x7C200400, // 0027 CALL R8 2 + 0x8C200F0E, // 0028 GETMET R8 R7 K14 + 0x5C280A00, // 0029 MOVE R10 R5 + 0x7C200400, // 002A CALL R8 2 + 0x0010090B, // 002B ADD R4 R4 K11 + 0x7001FFE6, // 002C JMP #0014 + 0x5818000C, // 002D LDCONST R6 K12 + 0xAC180200, // 002E CATCH R6 1 0 + 0xB0080000, // 002F RAISE 2 R0 R0 + 0x8C180B06, // 0030 GETMET R6 R5 K6 + 0x5820000F, // 0031 LDCONST R8 K15 + 0x7C180400, // 0032 CALL R6 2 + 0x8C180B10, // 0033 GETMET R6 R5 K16 + 0x7C180200, // 0034 CALL R6 1 + 0x8C180511, // 0035 GETMET R6 R2 K17 + 0x88200112, // 0036 GETMBR R8 R0 K18 + 0x7C180400, // 0037 CALL R6 2 + 0x8C180513, // 0038 GETMET R6 R2 K19 + 0x88200104, // 0039 GETMBR R8 R0 K4 + 0x88240112, // 003A GETMBR R9 R0 K18 + 0x7C180600, // 003B CALL R6 3 + 0x781A000C, // 003C JMPF R6 #004A + 0xB81A2800, // 003D GETNGBL R6 K20 + 0x8C180D15, // 003E GETMET R6 R6 K21 + 0x60200018, // 003F GETGBL R8 G24 + 0x58240016, // 0040 LDCONST R9 K22 + 0x5C280800, // 0041 MOVE R10 R4 + 0x5C2C0600, // 0042 MOVE R11 R3 + 0x7C200600, // 0043 CALL R8 3 + 0x58240017, // 0044 LDCONST R9 K23 + 0x7C180600, // 0045 CALL R6 3 + 0x88180118, // 0046 GETMBR R6 R0 K24 + 0x8C180D19, // 0047 GETMET R6 R6 K25 + 0x7C180200, // 0048 CALL R6 1 + 0x70020006, // 0049 JMP #0051 + 0xB81A2800, // 004A GETNGBL R6 K20 + 0x8C180D15, // 004B GETMET R6 R6 K21 + 0x60200018, // 004C GETGBL R8 G24 + 0x5824001A, // 004D LDCONST R9 K26 + 0x7C200200, // 004E CALL R8 1 + 0x58240017, // 004F LDCONST R9 K23 + 0x7C180600, // 0050 CALL R6 3 + 0xA8040001, // 0051 EXBLK 1 1 + 0x70020010, // 0052 JMP #0064 + 0xAC0C0002, // 0053 CATCH R3 0 2 + 0x7002000D, // 0054 JMP #0063 + 0xB8162800, // 0055 GETNGBL R5 K20 + 0x8C140B15, // 0056 GETMET R5 R5 K21 + 0x601C0008, // 0057 GETGBL R7 G8 + 0x5C200600, // 0058 MOVE R8 R3 + 0x7C1C0200, // 0059 CALL R7 1 + 0x001E3607, // 005A ADD R7 K27 R7 + 0x001C0F1C, // 005B ADD R7 R7 K28 + 0x60200008, // 005C GETGBL R8 G8 + 0x5C240800, // 005D MOVE R9 R4 + 0x7C200200, // 005E CALL R8 1 + 0x001C0E08, // 005F ADD R7 R7 R8 + 0x58200017, // 0060 LDCONST R8 K23 + 0x7C140600, // 0061 CALL R5 3 + 0x70020000, // 0062 JMP #0064 + 0xB0080000, // 0063 RAISE 2 R0 R0 + 0x80000000, // 0064 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: create_session +********************************************************************/ +be_local_closure(Matter_Session_Store_create_session, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(get_session_by_local_session_id), + /* K1 */ be_nested_str_weak(remove_session), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(Session), + /* K4 */ be_nested_str_weak(sessions), + /* K5 */ be_nested_str_weak(push), + }), + be_str_weak(create_session), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140200, // 0001 MOVE R5 R1 + 0x7C0C0400, // 0002 CALL R3 2 + 0x4C100000, // 0003 LDNIL R4 + 0x20100604, // 0004 NE R4 R3 R4 + 0x78120002, // 0005 JMPF R4 #0009 + 0x8C100101, // 0006 GETMET R4 R0 K1 + 0x5C180600, // 0007 MOVE R6 R3 + 0x7C100400, // 0008 CALL R4 2 + 0xB8120400, // 0009 GETNGBL R4 K2 + 0x8C100903, // 000A GETMET R4 R4 K3 + 0x5C180000, // 000B MOVE R6 R0 + 0x5C1C0200, // 000C MOVE R7 R1 + 0x5C200400, // 000D MOVE R8 R2 + 0x7C100800, // 000E CALL R4 4 + 0x5C0C0800, // 000F MOVE R3 R4 + 0x88100104, // 0010 GETMBR R4 R0 K4 + 0x8C100905, // 0011 GETMET R4 R4 K5 + 0x5C180600, // 0012 MOVE R6 R3 + 0x7C100400, // 0013 CALL R4 2 + 0x80040600, // 0014 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_fabric +********************************************************************/ +be_local_closure(Matter_Session_Store_remove_fabric, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(_fabric), + /* K3 */ be_nested_str_weak(remove), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(fabrics), + /* K6 */ be_nested_str_weak(find), + }), + be_str_weak(remove_fabric), + &be_const_str_solidified, + ( &(const binstruction[34]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x20080403, // 0002 NE R2 R2 R3 + 0x780A0011, // 0003 JMPF R2 #0016 + 0x58080001, // 0004 LDCONST R2 K1 + 0x600C000C, // 0005 GETGBL R3 G12 + 0x88100100, // 0006 GETMBR R4 R0 K0 + 0x7C0C0200, // 0007 CALL R3 1 + 0x140C0403, // 0008 LT R3 R2 R3 + 0x780E000B, // 0009 JMPF R3 #0016 + 0x880C0100, // 000A GETMBR R3 R0 K0 + 0x940C0602, // 000B GETIDX R3 R3 R2 + 0x880C0702, // 000C GETMBR R3 R3 K2 + 0x1C0C0601, // 000D EQ R3 R3 R1 + 0x780E0004, // 000E JMPF R3 #0014 + 0x880C0100, // 000F GETMBR R3 R0 K0 + 0x8C0C0703, // 0010 GETMET R3 R3 K3 + 0x5C140400, // 0011 MOVE R5 R2 + 0x7C0C0400, // 0012 CALL R3 2 + 0x70020000, // 0013 JMP #0015 + 0x00080504, // 0014 ADD R2 R2 K4 + 0x7001FFEE, // 0015 JMP #0005 + 0x88080105, // 0016 GETMBR R2 R0 K5 + 0x4C0C0000, // 0017 LDNIL R3 + 0x20080403, // 0018 NE R2 R2 R3 + 0x780A0006, // 0019 JMPF R2 #0021 + 0x88080105, // 001A GETMBR R2 R0 K5 + 0x8C080503, // 001B GETMET R2 R2 K3 + 0x88100105, // 001C GETMBR R4 R0 K5 + 0x8C100906, // 001D GETMET R4 R4 K6 + 0x5C180200, // 001E MOVE R6 R1 + 0x7C100400, // 001F CALL R4 2 + 0x7C080400, // 0020 CALL R2 2 + 0x80000000, // 0021 RET 0 }) ) ); @@ -1356,35 +1376,36 @@ be_local_closure(Matter_Session_Store_gen_local_session_id, /* name */ be_local_class(Matter_Session_Store, 3, NULL, - be_nested_map(27, + be_nested_map(28, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(gen_local_session_id, -1), be_const_closure(Matter_Session_Store_gen_local_session_id_closure) }, - { be_const_key_weak(create_fabric, -1), be_const_closure(Matter_Session_Store_create_fabric_closure) }, - { be_const_key_weak(get_session_by_source_node_id, -1), be_const_closure(Matter_Session_Store_get_session_by_source_node_id_closure) }, - { be_const_key_weak(save_fabrics, -1), be_const_closure(Matter_Session_Store_save_fabrics_closure) }, - { be_const_key_weak(active_fabrics, 10), be_const_closure(Matter_Session_Store_active_fabrics_closure) }, - { be_const_key_weak(find_session_by_resumption_id, 20), be_const_closure(Matter_Session_Store_find_session_by_resumption_id_closure) }, - { be_const_key_weak(sessions_active, -1), be_const_closure(Matter_Session_Store_sessions_active_closure) }, { be_const_key_weak(sessions, -1), be_const_var(1) }, - { be_const_key_weak(fabrics, -1), be_const_var(2) }, - { be_const_key_weak(load_fabrics, 6), be_const_closure(Matter_Session_Store_load_fabrics_closure) }, - { be_const_key_weak(find_session_source_id_unsecure, 23), be_const_closure(Matter_Session_Store_find_session_source_id_unsecure_closure) }, - { be_const_key_weak(_FABRICS, -1), be_nested_str_weak(_matter_fabrics_X2Ejson) }, + { be_const_key_weak(remove_fabric, -1), be_const_closure(Matter_Session_Store_remove_fabric_closure) }, { be_const_key_weak(remove_session, -1), be_const_closure(Matter_Session_Store_remove_session_closure) }, - { be_const_key_weak(remove_fabric, 22), be_const_closure(Matter_Session_Store_remove_fabric_closure) }, - { be_const_key_weak(find_fabric_by_index, 19), be_const_closure(Matter_Session_Store_find_fabric_by_index_closure) }, - { be_const_key_weak(remove_expired, -1), be_const_closure(Matter_Session_Store_remove_expired_closure) }, - { be_const_key_weak(add_session, -1), be_const_closure(Matter_Session_Store_add_session_closure) }, - { be_const_key_weak(remove_redundant_fabric, 11), be_const_closure(Matter_Session_Store_remove_redundant_fabric_closure) }, - { be_const_key_weak(create_session, -1), be_const_closure(Matter_Session_Store_create_session_closure) }, - { be_const_key_weak(get_session_by_local_session_id, -1), be_const_closure(Matter_Session_Store_get_session_by_local_session_id_closure) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Session_Store_init_closure) }, + { be_const_key_weak(active_fabrics, -1), be_const_closure(Matter_Session_Store_active_fabrics_closure) }, + { be_const_key_weak(load_fabrics, 18), be_const_closure(Matter_Session_Store_load_fabrics_closure) }, + { be_const_key_weak(fabrics, -1), be_const_var(2) }, + { be_const_key_weak(save_fabrics, -1), be_const_closure(Matter_Session_Store_save_fabrics_closure) }, + { be_const_key_weak(_FABRICS_TEMP, 22), be_nested_str_weak(_X2F_matter_fabrics_X2Etmp) }, + { be_const_key_weak(create_fabric, -1), be_const_closure(Matter_Session_Store_create_fabric_closure) }, + { be_const_key_weak(find_fabric_by_index, -1), be_const_closure(Matter_Session_Store_find_fabric_by_index_closure) }, + { be_const_key_weak(gen_local_session_id, 3), be_const_closure(Matter_Session_Store_gen_local_session_id_closure) }, + { be_const_key_weak(sessions_active, 8), be_const_closure(Matter_Session_Store_sessions_active_closure) }, + { be_const_key_weak(_FABRICS, -1), be_nested_str_weak(_X2F_matter_fabrics_X2Ejson) }, + { be_const_key_weak(get_session_by_source_node_id, -1), be_const_closure(Matter_Session_Store_get_session_by_source_node_id_closure) }, + { be_const_key_weak(count_active_fabrics, 23), be_const_closure(Matter_Session_Store_count_active_fabrics_closure) }, + { be_const_key_weak(add_session, 13), be_const_closure(Matter_Session_Store_add_session_closure) }, + { be_const_key_weak(find_session_source_id_unsecure, -1), be_const_closure(Matter_Session_Store_find_session_source_id_unsecure_closure) }, { be_const_key_weak(every_second, -1), be_const_closure(Matter_Session_Store_every_second_closure) }, { be_const_key_weak(add_fabric, -1), be_const_closure(Matter_Session_Store_add_fabric_closure) }, - { be_const_key_weak(count_active_fabrics, -1), be_const_closure(Matter_Session_Store_count_active_fabrics_closure) }, - { be_const_key_weak(device, 5), be_const_var(0) }, - { be_const_key_weak(next_fabric_idx, 3), be_const_closure(Matter_Session_Store_next_fabric_idx_closure) }, - { be_const_key_weak(find_children_fabrics, 0), be_const_closure(Matter_Session_Store_find_children_fabrics_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Session_Store_init_closure) }, + { be_const_key_weak(remove_redundant_fabric, -1), be_const_closure(Matter_Session_Store_remove_redundant_fabric_closure) }, + { be_const_key_weak(get_session_by_local_session_id, 20), be_const_closure(Matter_Session_Store_get_session_by_local_session_id_closure) }, + { be_const_key_weak(remove_expired, -1), be_const_closure(Matter_Session_Store_remove_expired_closure) }, + { be_const_key_weak(find_session_by_resumption_id, -1), be_const_closure(Matter_Session_Store_find_session_by_resumption_id_closure) }, + { be_const_key_weak(next_fabric_idx, -1), be_const_closure(Matter_Session_Store_next_fabric_idx_closure) }, + { be_const_key_weak(find_children_fabrics, 6), be_const_closure(Matter_Session_Store_find_children_fabrics_closure) }, + { be_const_key_weak(create_session, -1), be_const_closure(Matter_Session_Store_create_session_closure) }, + { be_const_key_weak(device, 1), be_const_var(0) }, })), be_str_weak(Matter_Session_Store) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h index c829d0346..64a9aabfd 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h @@ -771,112 +771,110 @@ be_local_closure(Matter_TLV_item_parse, /* name */ }), be_str_weak(parse), &be_const_str_solidified, - ( &(const binstruction[105]) { /* code */ + ( &(const binstruction[103]) { /* code */ 0x880C0100, // 0000 GETMBR R3 R0 K0 0x88100101, // 0001 GETMBR R4 R0 K1 0x88140902, // 0002 GETMBR R5 R4 K2 0x94140A03, // 0003 GETIDX R5 R5 R3 0x541A0007, // 0004 LDINT R6 8 0x1C180A06, // 0005 EQ R6 R5 R6 - 0x781A000A, // 0006 JMPF R6 #0012 + 0x781A0008, // 0006 JMPF R6 #0010 0xB81A0800, // 0007 GETNGBL R6 K4 - 0x7C180000, // 0008 CALL R6 0 - 0x90020606, // 0009 SETMBR R0 K3 R6 - 0x88180103, // 000A GETMBR R6 R0 K3 - 0x8C180D05, // 000B GETMET R6 R6 K5 - 0x5C200200, // 000C MOVE R8 R1 - 0x5C240400, // 000D MOVE R9 R2 - 0x7C180600, // 000E CALL R6 3 - 0x541A0007, // 000F LDINT R6 8 - 0x00080406, // 0010 ADD R2 R2 R6 - 0x70020054, // 0011 JMP #0067 - 0x88180906, // 0012 GETMBR R6 R4 K6 - 0x1C180606, // 0013 EQ R6 R3 R6 - 0x741A0002, // 0014 JMPT R6 #0018 - 0x88180907, // 0015 GETMBR R6 R4 K7 - 0x1C180606, // 0016 EQ R6 R3 R6 - 0x781A0003, // 0017 JMPF R6 #001C - 0x88180907, // 0018 GETMBR R6 R4 K7 - 0x1C180606, // 0019 EQ R6 R3 R6 - 0x90020606, // 001A SETMBR R0 K3 R6 - 0x7002004A, // 001B JMP #0067 - 0x88180908, // 001C GETMBR R6 R4 K8 - 0x14180606, // 001D LT R6 R3 R6 - 0x781A000E, // 001E JMPF R6 #002E - 0x88180909, // 001F GETMBR R6 R4 K9 - 0x18180606, // 0020 LE R6 R3 R6 - 0x781A0004, // 0021 JMPF R6 #0027 - 0x8C18030A, // 0022 GETMET R6 R1 K10 - 0x5C200400, // 0023 MOVE R8 R2 - 0x5C240A00, // 0024 MOVE R9 R5 - 0x7C180600, // 0025 CALL R6 3 - 0x70020003, // 0026 JMP #002B - 0x8C18030B, // 0027 GETMET R6 R1 K11 - 0x5C200400, // 0028 MOVE R8 R2 - 0x5C240A00, // 0029 MOVE R9 R5 - 0x7C180600, // 002A CALL R6 3 - 0x90020606, // 002B SETMBR R0 K3 R6 - 0x00080405, // 002C ADD R2 R2 R5 - 0x70020038, // 002D JMP #0067 - 0x8818090C, // 002E GETMBR R6 R4 K12 - 0x1C180606, // 002F EQ R6 R3 R6 - 0x781A0006, // 0030 JMPF R6 #0038 - 0x8C18030D, // 0031 GETMET R6 R1 K13 - 0x5C200400, // 0032 MOVE R8 R2 - 0x7C180400, // 0033 CALL R6 2 - 0x90020606, // 0034 SETMBR R0 K3 R6 - 0x541A0003, // 0035 LDINT R6 4 - 0x00080406, // 0036 ADD R2 R2 R6 - 0x7002002E, // 0037 JMP #0067 - 0x5419FFF7, // 0038 LDINT R6 -8 - 0x28180A06, // 0039 GE R6 R5 R6 - 0x781A0016, // 003A JMPF R6 #0052 - 0x5419FFFE, // 003B LDINT R6 -1 - 0x18180A06, // 003C LE R6 R5 R6 - 0x781A0013, // 003D JMPF R6 #0052 - 0x8C18030B, // 003E GETMET R6 R1 K11 - 0x5C200400, // 003F MOVE R8 R2 - 0x44240A00, // 0040 NEG R9 R5 - 0x7C180600, // 0041 CALL R6 3 - 0x441C0A00, // 0042 NEG R7 R5 - 0x00080407, // 0043 ADD R2 R2 R7 - 0x001C0406, // 0044 ADD R7 R2 R6 - 0x041C0F0E, // 0045 SUB R7 R7 K14 - 0x401C0407, // 0046 CONNECT R7 R2 R7 - 0x941C0207, // 0047 GETIDX R7 R1 R7 - 0x90020607, // 0048 SETMBR R0 K3 R7 - 0x00080406, // 0049 ADD R2 R2 R6 - 0x881C090F, // 004A GETMBR R7 R4 K15 - 0x181C0607, // 004B LE R7 R3 R7 - 0x781E0003, // 004C JMPF R7 #0051 - 0x881C0103, // 004D GETMBR R7 R0 K3 - 0x8C1C0F10, // 004E GETMET R7 R7 K16 - 0x7C1C0200, // 004F CALL R7 1 - 0x90020607, // 0050 SETMBR R0 K3 R7 - 0x70020014, // 0051 JMP #0067 - 0x88180911, // 0052 GETMBR R6 R4 K17 - 0x1C180606, // 0053 EQ R6 R3 R6 - 0x781A0000, // 0054 JMPF R6 #0056 - 0x70020010, // 0055 JMP #0067 - 0x88180912, // 0056 GETMBR R6 R4 K18 - 0x1C180606, // 0057 EQ R6 R3 R6 - 0x781A0005, // 0058 JMPF R6 #005F - 0xB81A2600, // 0059 GETNGBL R6 K19 - 0x8C180D14, // 005A GETMET R6 R6 K20 - 0x58200015, // 005B LDCONST R8 K21 - 0x58240016, // 005C LDCONST R9 K22 - 0x7C180600, // 005D CALL R6 3 - 0x70020007, // 005E JMP #0067 - 0xB81A2600, // 005F GETNGBL R6 K19 - 0x8C180D14, // 0060 GETMET R6 R6 K20 - 0x60200008, // 0061 GETGBL R8 G8 - 0x5C240600, // 0062 MOVE R9 R3 - 0x7C200200, // 0063 CALL R8 1 - 0x00222E08, // 0064 ADD R8 K23 R8 - 0x58240016, // 0065 LDCONST R9 K22 - 0x7C180600, // 0066 CALL R6 3 - 0x90023002, // 0067 SETMBR R0 K24 R2 - 0x80040400, // 0068 RET 1 R2 + 0x8C180D05, // 0008 GETMET R6 R6 K5 + 0x5C200200, // 0009 MOVE R8 R1 + 0x5C240400, // 000A MOVE R9 R2 + 0x7C180600, // 000B CALL R6 3 + 0x90020606, // 000C SETMBR R0 K3 R6 + 0x541A0007, // 000D LDINT R6 8 + 0x00080406, // 000E ADD R2 R2 R6 + 0x70020054, // 000F JMP #0065 + 0x88180906, // 0010 GETMBR R6 R4 K6 + 0x1C180606, // 0011 EQ R6 R3 R6 + 0x741A0002, // 0012 JMPT R6 #0016 + 0x88180907, // 0013 GETMBR R6 R4 K7 + 0x1C180606, // 0014 EQ R6 R3 R6 + 0x781A0003, // 0015 JMPF R6 #001A + 0x88180907, // 0016 GETMBR R6 R4 K7 + 0x1C180606, // 0017 EQ R6 R3 R6 + 0x90020606, // 0018 SETMBR R0 K3 R6 + 0x7002004A, // 0019 JMP #0065 + 0x88180908, // 001A GETMBR R6 R4 K8 + 0x14180606, // 001B LT R6 R3 R6 + 0x781A000E, // 001C JMPF R6 #002C + 0x88180909, // 001D GETMBR R6 R4 K9 + 0x18180606, // 001E LE R6 R3 R6 + 0x781A0004, // 001F JMPF R6 #0025 + 0x8C18030A, // 0020 GETMET R6 R1 K10 + 0x5C200400, // 0021 MOVE R8 R2 + 0x5C240A00, // 0022 MOVE R9 R5 + 0x7C180600, // 0023 CALL R6 3 + 0x70020003, // 0024 JMP #0029 + 0x8C18030B, // 0025 GETMET R6 R1 K11 + 0x5C200400, // 0026 MOVE R8 R2 + 0x5C240A00, // 0027 MOVE R9 R5 + 0x7C180600, // 0028 CALL R6 3 + 0x90020606, // 0029 SETMBR R0 K3 R6 + 0x00080405, // 002A ADD R2 R2 R5 + 0x70020038, // 002B JMP #0065 + 0x8818090C, // 002C GETMBR R6 R4 K12 + 0x1C180606, // 002D EQ R6 R3 R6 + 0x781A0006, // 002E JMPF R6 #0036 + 0x8C18030D, // 002F GETMET R6 R1 K13 + 0x5C200400, // 0030 MOVE R8 R2 + 0x7C180400, // 0031 CALL R6 2 + 0x90020606, // 0032 SETMBR R0 K3 R6 + 0x541A0003, // 0033 LDINT R6 4 + 0x00080406, // 0034 ADD R2 R2 R6 + 0x7002002E, // 0035 JMP #0065 + 0x5419FFF7, // 0036 LDINT R6 -8 + 0x28180A06, // 0037 GE R6 R5 R6 + 0x781A0016, // 0038 JMPF R6 #0050 + 0x5419FFFE, // 0039 LDINT R6 -1 + 0x18180A06, // 003A LE R6 R5 R6 + 0x781A0013, // 003B JMPF R6 #0050 + 0x8C18030B, // 003C GETMET R6 R1 K11 + 0x5C200400, // 003D MOVE R8 R2 + 0x44240A00, // 003E NEG R9 R5 + 0x7C180600, // 003F CALL R6 3 + 0x441C0A00, // 0040 NEG R7 R5 + 0x00080407, // 0041 ADD R2 R2 R7 + 0x001C0406, // 0042 ADD R7 R2 R6 + 0x041C0F0E, // 0043 SUB R7 R7 K14 + 0x401C0407, // 0044 CONNECT R7 R2 R7 + 0x941C0207, // 0045 GETIDX R7 R1 R7 + 0x90020607, // 0046 SETMBR R0 K3 R7 + 0x00080406, // 0047 ADD R2 R2 R6 + 0x881C090F, // 0048 GETMBR R7 R4 K15 + 0x181C0607, // 0049 LE R7 R3 R7 + 0x781E0003, // 004A JMPF R7 #004F + 0x881C0103, // 004B GETMBR R7 R0 K3 + 0x8C1C0F10, // 004C GETMET R7 R7 K16 + 0x7C1C0200, // 004D CALL R7 1 + 0x90020607, // 004E SETMBR R0 K3 R7 + 0x70020014, // 004F JMP #0065 + 0x88180911, // 0050 GETMBR R6 R4 K17 + 0x1C180606, // 0051 EQ R6 R3 R6 + 0x781A0000, // 0052 JMPF R6 #0054 + 0x70020010, // 0053 JMP #0065 + 0x88180912, // 0054 GETMBR R6 R4 K18 + 0x1C180606, // 0055 EQ R6 R3 R6 + 0x781A0005, // 0056 JMPF R6 #005D + 0xB81A2600, // 0057 GETNGBL R6 K19 + 0x8C180D14, // 0058 GETMET R6 R6 K20 + 0x58200015, // 0059 LDCONST R8 K21 + 0x58240016, // 005A LDCONST R9 K22 + 0x7C180600, // 005B CALL R6 3 + 0x70020007, // 005C JMP #0065 + 0xB81A2600, // 005D GETNGBL R6 K19 + 0x8C180D14, // 005E GETMET R6 R6 K20 + 0x60200008, // 005F GETGBL R8 G8 + 0x5C240600, // 0060 MOVE R9 R3 + 0x7C200200, // 0061 CALL R8 1 + 0x00222E08, // 0062 ADD R8 K23 R8 + 0x58240016, // 0063 LDCONST R9 K22 + 0x7C180600, // 0064 CALL R6 3 + 0x90023002, // 0065 SETMBR R0 K24 R2 + 0x80040400, // 0066 RET 1 R2 }) ) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_zz_Device.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_zz_Device.h index d5af95655..b8df6edf0 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_zz_Device.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_zz_Device.h @@ -1488,305 +1488,108 @@ be_local_closure(Matter_Device_mdns_announce_op_discovery_all_fabrics, /* name ********************************************************************/ be_local_closure(Matter_Device_process_attribute_expansion, /* name */ be_nested_proto( - 24, /* nstack */ + 16, /* nstack */ 3, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 1]) { - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 0, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(keys), - /* K1 */ be_nested_str_weak(push), - /* K2 */ be_nested_str_weak(stop_iteration), - /* K3 */ be_const_int(1), - /* K4 */ be_const_int(0), - }), - be_str_weak(keys_sorted), - &be_const_str_solidified, - ( &(const binstruction[45]) { /* code */ - 0x60040012, // 0000 GETGBL R1 G18 - 0x7C040000, // 0001 CALL R1 0 - 0x60080010, // 0002 GETGBL R2 G16 - 0x8C0C0100, // 0003 GETMET R3 R0 K0 - 0x7C0C0200, // 0004 CALL R3 1 - 0x7C080200, // 0005 CALL R2 1 - 0xA8020005, // 0006 EXBLK 0 #000D - 0x5C0C0400, // 0007 MOVE R3 R2 - 0x7C0C0000, // 0008 CALL R3 0 - 0x8C100301, // 0009 GETMET R4 R1 K1 - 0x5C180600, // 000A MOVE R6 R3 - 0x7C100400, // 000B CALL R4 2 - 0x7001FFF9, // 000C JMP #0007 - 0x58080002, // 000D LDCONST R2 K2 - 0xAC080200, // 000E CATCH R2 1 0 - 0xB0080000, // 000F RAISE 2 R0 R0 - 0x60080010, // 0010 GETGBL R2 G16 - 0x600C000C, // 0011 GETGBL R3 G12 - 0x5C100200, // 0012 MOVE R4 R1 - 0x7C0C0200, // 0013 CALL R3 1 - 0x040C0703, // 0014 SUB R3 R3 K3 - 0x400E0603, // 0015 CONNECT R3 K3 R3 - 0x7C080200, // 0016 CALL R2 1 - 0xA8020010, // 0017 EXBLK 0 #0029 - 0x5C0C0400, // 0018 MOVE R3 R2 - 0x7C0C0000, // 0019 CALL R3 0 - 0x94100203, // 001A GETIDX R4 R1 R3 - 0x5C140600, // 001B MOVE R5 R3 - 0x24180B04, // 001C GT R6 R5 K4 - 0x781A0008, // 001D JMPF R6 #0027 - 0x04180B03, // 001E SUB R6 R5 K3 - 0x94180206, // 001F GETIDX R6 R1 R6 - 0x24180C04, // 0020 GT R6 R6 R4 - 0x781A0004, // 0021 JMPF R6 #0027 - 0x04180B03, // 0022 SUB R6 R5 K3 - 0x94180206, // 0023 GETIDX R6 R1 R6 - 0x98040A06, // 0024 SETIDX R1 R5 R6 - 0x04140B03, // 0025 SUB R5 R5 K3 - 0x7001FFF4, // 0026 JMP #001C - 0x98040A04, // 0027 SETIDX R1 R5 R4 - 0x7001FFEE, // 0028 JMP #0018 - 0x58080002, // 0029 LDCONST R2 K2 - 0xAC080200, // 002A CATCH R2 1 0 - 0xB0080000, // 002B RAISE 2 R0 R0 - 0x80040200, // 002C RET 1 R1 - }) - ), - }), + 0, /* has sup protos */ + NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[16]) { /* constants */ /* K0 */ be_nested_str_weak(endpoint), /* K1 */ be_nested_str_weak(cluster), /* K2 */ be_nested_str_weak(attribute), - /* K3 */ be_nested_str_weak(plugins), - /* K4 */ be_nested_str_weak(get_endpoint), - /* K5 */ be_nested_str_weak(contains), - /* K6 */ be_nested_str_weak(get_cluster_list), - /* K7 */ be_nested_str_weak(get_attribute_list), - /* K8 */ be_nested_str_weak(push), - /* K9 */ be_nested_str_weak(stop_iteration), - /* K10 */ be_nested_str_weak(status), - /* K11 */ be_nested_str_weak(matter), - /* K12 */ be_nested_str_weak(UNSUPPORTED_ENDPOINT), - /* K13 */ be_nested_str_weak(UNSUPPORTED_CLUSTER), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(PathGenerator), + /* K5 */ be_nested_str_weak(start), + /* K6 */ be_nested_str_weak(next), + /* K7 */ be_nested_str_weak(get_pi), + /* K8 */ be_nested_str_weak(endpoint_found), + /* K9 */ be_nested_str_weak(status), + /* K10 */ be_nested_str_weak(UNSUPPORTED_ENDPOINT), + /* K11 */ be_nested_str_weak(cluster_found), + /* K12 */ be_nested_str_weak(UNSUPPORTED_CLUSTER), + /* K13 */ be_nested_str_weak(attribute_found), /* K14 */ be_nested_str_weak(UNSUPPORTED_ATTRIBUTE), /* K15 */ be_nested_str_weak(UNREPORTABLE_ATTRIBUTE), }), be_str_weak(process_attribute_expansion), &be_const_str_solidified, - ( &(const binstruction[203]) { /* code */ - 0x840C0000, // 0000 CLOSURE R3 P0 - 0x88100300, // 0001 GETMBR R4 R1 K0 - 0x88140301, // 0002 GETMBR R5 R1 K1 - 0x88180302, // 0003 GETMBR R6 R1 K2 + ( &(const binstruction[73]) { /* code */ + 0x880C0300, // 0000 GETMBR R3 R1 K0 + 0x88100301, // 0001 GETMBR R4 R1 K1 + 0x88140302, // 0002 GETMBR R5 R1 K2 + 0x50180000, // 0003 LDBOOL R6 0 0 0x501C0000, // 0004 LDBOOL R7 0 0 0x50200000, // 0005 LDBOOL R8 0 0 - 0x50240000, // 0006 LDBOOL R9 0 0 - 0x88280300, // 0007 GETMBR R10 R1 K0 - 0x4C2C0000, // 0008 LDNIL R11 - 0x2028140B, // 0009 NE R10 R10 R11 - 0x782A0007, // 000A JMPF R10 #0013 - 0x88280301, // 000B GETMBR R10 R1 K1 - 0x4C2C0000, // 000C LDNIL R11 - 0x2028140B, // 000D NE R10 R10 R11 - 0x782A0003, // 000E JMPF R10 #0013 - 0x88280302, // 000F GETMBR R10 R1 K2 - 0x4C2C0000, // 0010 LDNIL R11 - 0x2028140B, // 0011 NE R10 R10 R11 - 0x742A0000, // 0012 JMPT R10 #0014 - 0x50280001, // 0013 LDBOOL R10 0 1 - 0x50280200, // 0014 LDBOOL R10 1 0 - 0x602C0013, // 0015 GETGBL R11 G19 - 0x7C2C0000, // 0016 CALL R11 0 - 0x60300010, // 0017 GETGBL R12 G16 - 0x88340103, // 0018 GETMBR R13 R0 K3 - 0x7C300200, // 0019 CALL R12 1 - 0xA8020053, // 001A EXBLK 0 #006F - 0x5C341800, // 001B MOVE R13 R12 - 0x7C340000, // 001C CALL R13 0 - 0x8C381B04, // 001D GETMET R14 R13 K4 - 0x7C380200, // 001E CALL R14 1 - 0x4C3C0000, // 001F LDNIL R15 - 0x203C080F, // 0020 NE R15 R4 R15 - 0x783E0002, // 0021 JMPF R15 #0025 - 0x203C1C04, // 0022 NE R15 R14 R4 - 0x783E0000, // 0023 JMPF R15 #0025 - 0x7001FFF5, // 0024 JMP #001B - 0x8C3C1705, // 0025 GETMET R15 R11 K5 - 0x5C441C00, // 0026 MOVE R17 R14 - 0x7C3C0400, // 0027 CALL R15 2 - 0x743E0002, // 0028 JMPT R15 #002C - 0x603C0013, // 0029 GETGBL R15 G19 - 0x7C3C0000, // 002A CALL R15 0 - 0x982C1C0F, // 002B SETIDX R11 R14 R15 - 0x501C0200, // 002C LDBOOL R7 1 0 - 0x8C3C1B06, // 002D GETMET R15 R13 K6 - 0x7C3C0200, // 002E CALL R15 1 - 0x60400010, // 002F GETGBL R16 G16 - 0x5C441E00, // 0030 MOVE R17 R15 - 0x7C400200, // 0031 CALL R16 1 - 0xA8020037, // 0032 EXBLK 0 #006B - 0x5C442000, // 0033 MOVE R17 R16 - 0x7C440000, // 0034 CALL R17 0 - 0x4C480000, // 0035 LDNIL R18 - 0x20480A12, // 0036 NE R18 R5 R18 - 0x784A0002, // 0037 JMPF R18 #003B - 0x20482205, // 0038 NE R18 R17 R5 - 0x784A0000, // 0039 JMPF R18 #003B - 0x7001FFF7, // 003A JMP #0033 - 0x9448160E, // 003B GETIDX R18 R11 R14 - 0x8C482505, // 003C GETMET R18 R18 K5 - 0x5C502200, // 003D MOVE R20 R17 - 0x7C480400, // 003E CALL R18 2 - 0x744A0003, // 003F JMPT R18 #0044 - 0x9448160E, // 0040 GETIDX R18 R11 R14 - 0x604C0013, // 0041 GETGBL R19 G19 - 0x7C4C0000, // 0042 CALL R19 0 - 0x98482213, // 0043 SETIDX R18 R17 R19 - 0x50200200, // 0044 LDBOOL R8 1 0 - 0x8C481B07, // 0045 GETMET R18 R13 K7 - 0x5C502200, // 0046 MOVE R20 R17 - 0x7C480400, // 0047 CALL R18 2 - 0x604C0010, // 0048 GETGBL R19 G16 - 0x5C502400, // 0049 MOVE R20 R18 - 0x7C4C0200, // 004A CALL R19 1 - 0xA802001A, // 004B EXBLK 0 #0067 - 0x5C502600, // 004C MOVE R20 R19 - 0x7C500000, // 004D CALL R20 0 - 0x4C540000, // 004E LDNIL R21 - 0x20540C15, // 004F NE R21 R6 R21 - 0x78560002, // 0050 JMPF R21 #0054 - 0x20542806, // 0051 NE R21 R20 R6 - 0x78560000, // 0052 JMPF R21 #0054 - 0x7001FFF7, // 0053 JMP #004C - 0x9454160E, // 0054 GETIDX R21 R11 R14 - 0x94542A11, // 0055 GETIDX R21 R21 R17 - 0x8C542B05, // 0056 GETMET R21 R21 K5 - 0x5C5C2800, // 0057 MOVE R23 R20 - 0x7C540400, // 0058 CALL R21 2 - 0x74560004, // 0059 JMPT R21 #005F - 0x9454160E, // 005A GETIDX R21 R11 R14 - 0x94542A11, // 005B GETIDX R21 R21 R17 - 0x60580012, // 005C GETGBL R22 G18 - 0x7C580000, // 005D CALL R22 0 - 0x98542816, // 005E SETIDX R21 R20 R22 - 0x50240200, // 005F LDBOOL R9 1 0 - 0x9454160E, // 0060 GETIDX R21 R11 R14 - 0x94542A11, // 0061 GETIDX R21 R21 R17 - 0x94542A14, // 0062 GETIDX R21 R21 R20 - 0x8C542B08, // 0063 GETMET R21 R21 K8 - 0x5C5C1A00, // 0064 MOVE R23 R13 - 0x7C540400, // 0065 CALL R21 2 - 0x7001FFE4, // 0066 JMP #004C - 0x584C0009, // 0067 LDCONST R19 K9 - 0xAC4C0200, // 0068 CATCH R19 1 0 - 0xB0080000, // 0069 RAISE 2 R0 R0 - 0x7001FFC7, // 006A JMP #0033 - 0x58400009, // 006B LDCONST R16 K9 - 0xAC400200, // 006C CATCH R16 1 0 - 0xB0080000, // 006D RAISE 2 R0 R0 - 0x7001FFAB, // 006E JMP #001B - 0x58300009, // 006F LDCONST R12 K9 - 0xAC300200, // 0070 CATCH R12 1 0 - 0xB0080000, // 0071 RAISE 2 R0 R0 - 0x60300010, // 0072 GETGBL R12 G16 - 0x5C340600, // 0073 MOVE R13 R3 - 0x5C381600, // 0074 MOVE R14 R11 - 0x7C340200, // 0075 CALL R13 1 - 0x7C300200, // 0076 CALL R12 1 - 0xA8020033, // 0077 EXBLK 0 #00AC - 0x5C341800, // 0078 MOVE R13 R12 - 0x7C340000, // 0079 CALL R13 0 - 0x60380010, // 007A GETGBL R14 G16 - 0x5C3C0600, // 007B MOVE R15 R3 - 0x9440160D, // 007C GETIDX R16 R11 R13 - 0x7C3C0200, // 007D CALL R15 1 - 0x7C380200, // 007E CALL R14 1 - 0xA8020027, // 007F EXBLK 0 #00A8 - 0x5C3C1C00, // 0080 MOVE R15 R14 - 0x7C3C0000, // 0081 CALL R15 0 - 0x60400010, // 0082 GETGBL R16 G16 - 0x5C440600, // 0083 MOVE R17 R3 - 0x9448160D, // 0084 GETIDX R18 R11 R13 - 0x9448240F, // 0085 GETIDX R18 R18 R15 - 0x7C440200, // 0086 CALL R17 1 - 0x7C400200, // 0087 CALL R16 1 - 0xA802001A, // 0088 EXBLK 0 #00A4 - 0x5C442000, // 0089 MOVE R17 R16 - 0x7C440000, // 008A CALL R17 0 - 0x60480010, // 008B GETGBL R18 G16 - 0x944C160D, // 008C GETIDX R19 R11 R13 - 0x944C260F, // 008D GETIDX R19 R19 R15 - 0x944C2611, // 008E GETIDX R19 R19 R17 - 0x7C480200, // 008F CALL R18 1 - 0xA802000E, // 0090 EXBLK 0 #00A0 - 0x5C4C2400, // 0091 MOVE R19 R18 - 0x7C4C0000, // 0092 CALL R19 0 - 0x9006000D, // 0093 SETMBR R1 K0 R13 - 0x9006020F, // 0094 SETMBR R1 K1 R15 - 0x90060411, // 0095 SETMBR R1 K2 R17 - 0x5C500400, // 0096 MOVE R20 R2 - 0x5C542600, // 0097 MOVE R21 R19 - 0x5C580200, // 0098 MOVE R22 R1 - 0x5C5C1400, // 0099 MOVE R23 R10 - 0x7C500600, // 009A CALL R20 3 - 0x782A0002, // 009B JMPF R10 #009F - 0x78520001, // 009C JMPF R20 #009F - 0xA8040004, // 009D EXBLK 1 4 - 0x80002A00, // 009E RET 0 - 0x7001FFF0, // 009F JMP #0091 - 0x58480009, // 00A0 LDCONST R18 K9 - 0xAC480200, // 00A1 CATCH R18 1 0 - 0xB0080000, // 00A2 RAISE 2 R0 R0 - 0x7001FFE4, // 00A3 JMP #0089 - 0x58400009, // 00A4 LDCONST R16 K9 - 0xAC400200, // 00A5 CATCH R16 1 0 - 0xB0080000, // 00A6 RAISE 2 R0 R0 - 0x7001FFD7, // 00A7 JMP #0080 - 0x58380009, // 00A8 LDCONST R14 K9 - 0xAC380200, // 00A9 CATCH R14 1 0 - 0xB0080000, // 00AA RAISE 2 R0 R0 - 0x7001FFCB, // 00AB JMP #0078 - 0x58300009, // 00AC LDCONST R12 K9 - 0xAC300200, // 00AD CATCH R12 1 0 - 0xB0080000, // 00AE RAISE 2 R0 R0 - 0x782A0019, // 00AF JMPF R10 #00CA - 0x5C300E00, // 00B0 MOVE R12 R7 - 0x74320003, // 00B1 JMPT R12 #00B6 - 0xB8321600, // 00B2 GETNGBL R12 K11 - 0x8830190C, // 00B3 GETMBR R12 R12 K12 - 0x9006140C, // 00B4 SETMBR R1 K10 R12 - 0x7002000E, // 00B5 JMP #00C5 - 0x5C301000, // 00B6 MOVE R12 R8 - 0x74320003, // 00B7 JMPT R12 #00BC - 0xB8321600, // 00B8 GETNGBL R12 K11 - 0x8830190D, // 00B9 GETMBR R12 R12 K13 - 0x9006140C, // 00BA SETMBR R1 K10 R12 - 0x70020008, // 00BB JMP #00C5 - 0x5C301200, // 00BC MOVE R12 R9 - 0x74320003, // 00BD JMPT R12 #00C2 - 0xB8321600, // 00BE GETNGBL R12 K11 - 0x8830190E, // 00BF GETMBR R12 R12 K14 - 0x9006140C, // 00C0 SETMBR R1 K10 R12 - 0x70020002, // 00C1 JMP #00C5 - 0xB8321600, // 00C2 GETNGBL R12 K11 - 0x8830190F, // 00C3 GETMBR R12 R12 K15 - 0x9006140C, // 00C4 SETMBR R1 K10 R12 - 0x5C300400, // 00C5 MOVE R12 R2 - 0x4C340000, // 00C6 LDNIL R13 - 0x5C380200, // 00C7 MOVE R14 R1 - 0x503C0200, // 00C8 LDBOOL R15 1 0 - 0x7C300600, // 00C9 CALL R12 3 - 0x80000000, // 00CA RET 0 + 0x88240300, // 0006 GETMBR R9 R1 K0 + 0x4C280000, // 0007 LDNIL R10 + 0x2024120A, // 0008 NE R9 R9 R10 + 0x78260007, // 0009 JMPF R9 #0012 + 0x88240301, // 000A GETMBR R9 R1 K1 + 0x4C280000, // 000B LDNIL R10 + 0x2024120A, // 000C NE R9 R9 R10 + 0x78260003, // 000D JMPF R9 #0012 + 0x88240302, // 000E GETMBR R9 R1 K2 + 0x4C280000, // 000F LDNIL R10 + 0x2024120A, // 0010 NE R9 R9 R10 + 0x74260000, // 0011 JMPT R9 #0013 + 0x50240001, // 0012 LDBOOL R9 0 1 + 0x50240200, // 0013 LDBOOL R9 1 0 + 0xB82A0600, // 0014 GETNGBL R10 K3 + 0x8C281504, // 0015 GETMET R10 R10 K4 + 0x5C300000, // 0016 MOVE R12 R0 + 0x7C280400, // 0017 CALL R10 2 + 0x8C2C1505, // 0018 GETMET R11 R10 K5 + 0x5C340200, // 0019 MOVE R13 R1 + 0x4C380000, // 001A LDNIL R14 + 0x7C2C0600, // 001B CALL R11 3 + 0x4C2C0000, // 001C LDNIL R11 + 0x8C301506, // 001D GETMET R12 R10 K6 + 0x7C300200, // 001E CALL R12 1 + 0x5C2C1800, // 001F MOVE R11 R12 + 0x4C340000, // 0020 LDNIL R13 + 0x2030180D, // 0021 NE R12 R12 R13 + 0x78320009, // 0022 JMPF R12 #002D + 0x5C300400, // 0023 MOVE R12 R2 + 0x8C341507, // 0024 GETMET R13 R10 K7 + 0x7C340200, // 0025 CALL R13 1 + 0x5C381600, // 0026 MOVE R14 R11 + 0x5C3C1200, // 0027 MOVE R15 R9 + 0x7C300600, // 0028 CALL R12 3 + 0x78260001, // 0029 JMPF R9 #002C + 0x78320000, // 002A JMPF R12 #002C + 0x80001A00, // 002B RET 0 + 0x7001FFEF, // 002C JMP #001D + 0x78260019, // 002D JMPF R9 #0048 + 0x88301508, // 002E GETMBR R12 R10 K8 + 0x74320003, // 002F JMPT R12 #0034 + 0xB8320600, // 0030 GETNGBL R12 K3 + 0x8830190A, // 0031 GETMBR R12 R12 K10 + 0x9006120C, // 0032 SETMBR R1 K9 R12 + 0x7002000E, // 0033 JMP #0043 + 0x8830150B, // 0034 GETMBR R12 R10 K11 + 0x74320003, // 0035 JMPT R12 #003A + 0xB8320600, // 0036 GETNGBL R12 K3 + 0x8830190C, // 0037 GETMBR R12 R12 K12 + 0x9006120C, // 0038 SETMBR R1 K9 R12 + 0x70020008, // 0039 JMP #0043 + 0x8830150D, // 003A GETMBR R12 R10 K13 + 0x74320003, // 003B JMPT R12 #0040 + 0xB8320600, // 003C GETNGBL R12 K3 + 0x8830190E, // 003D GETMBR R12 R12 K14 + 0x9006120C, // 003E SETMBR R1 K9 R12 + 0x70020002, // 003F JMP #0043 + 0xB8320600, // 0040 GETNGBL R12 K3 + 0x8830190F, // 0041 GETMBR R12 R12 K15 + 0x9006120C, // 0042 SETMBR R1 K9 R12 + 0x5C300400, // 0043 MOVE R12 R2 + 0x4C340000, // 0044 LDNIL R13 + 0x5C380200, // 0045 MOVE R14 R1 + 0x503C0200, // 0046 LDBOOL R15 1 0 + 0x7C300600, // 0047 CALL R12 3 + 0x80000000, // 0048 RET 0 }) ) ); @@ -6407,40 +6210,40 @@ be_local_class(Matter_Device, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_weak(aggregator, -1), be_const_class(be_class_Matter_Plugin_Aggregator) }, { be_const_key_weak(light2, -1), be_const_class(be_class_Matter_Plugin_Light2) }, - { be_const_key_weak(v_light1, 26), be_const_class(be_class_Matter_Plugin_Virt_Light1) }, + { be_const_key_weak(v_light1, 17), be_const_class(be_class_Matter_Plugin_Virt_Light1) }, { be_const_key_weak(v_light3, -1), be_const_class(be_class_Matter_Plugin_Virt_Light3) }, { be_const_key_weak(v_flow, -1), be_const_class(be_class_Matter_Plugin_Virt_Sensor_Flow) }, { be_const_key_weak(shutter, 14), be_const_class(be_class_Matter_Plugin_Shutter) }, { be_const_key_weak(v_pressure, -1), be_const_class(be_class_Matter_Plugin_Virt_Sensor_Pressure) }, { be_const_key_weak(v_temp, -1), be_const_class(be_class_Matter_Plugin_Virt_Sensor_Temp) }, - { be_const_key_weak(http_light2, 31), be_const_class(be_class_Matter_Plugin_Bridge_Light2) }, + { be_const_key_weak(http_contact, -1), be_const_class(be_class_Matter_Plugin_Bridge_Sensor_Contact) }, { be_const_key_weak(http_humidity, 22), be_const_class(be_class_Matter_Plugin_Bridge_Sensor_Humidity) }, { be_const_key_weak(pressure, 13), be_const_class(be_class_Matter_Plugin_Sensor_Pressure) }, - { be_const_key_weak(http_pressure, 29), be_const_class(be_class_Matter_Plugin_Bridge_Sensor_Pressure) }, + { be_const_key_weak(http_pressure, 8), be_const_class(be_class_Matter_Plugin_Bridge_Sensor_Pressure) }, { be_const_key_weak(illuminance, -1), be_const_class(be_class_Matter_Plugin_Sensor_Illuminance) }, { be_const_key_weak(light1, -1), be_const_class(be_class_Matter_Plugin_Light1) }, { be_const_key_weak(http_light1, -1), be_const_class(be_class_Matter_Plugin_Bridge_Light1) }, { be_const_key_weak(light3, 36), be_const_class(be_class_Matter_Plugin_Light3) }, - { be_const_key_weak(http_occupancy, 32), be_const_class(be_class_Matter_Plugin_Bridge_Sensor_Occupancy) }, - { be_const_key_weak(onoff, -1), be_const_class(be_class_Matter_Plugin_Sensor_OnOff) }, + { be_const_key_weak(http_occupancy, 31), be_const_class(be_class_Matter_Plugin_Bridge_Sensor_Occupancy) }, + { be_const_key_weak(v_relay, -1), be_const_class(be_class_Matter_Plugin_Virt_OnOff) }, { be_const_key_weak(contact, -1), be_const_class(be_class_Matter_Plugin_Sensor_Contact) }, - { be_const_key_weak(http_temperature, 8), be_const_class(be_class_Matter_Plugin_Bridge_Sensor_Temp) }, + { be_const_key_weak(http_temperature, 26), be_const_class(be_class_Matter_Plugin_Bridge_Sensor_Temp) }, { be_const_key_weak(v_occupancy, -1), be_const_class(be_class_Matter_Plugin_Virt_Sensor_Occupancy) }, { be_const_key_weak(occupancy, -1), be_const_class(be_class_Matter_Plugin_Sensor_Occupancy) }, - { be_const_key_weak(temperature, 35), be_const_class(be_class_Matter_Plugin_Sensor_Temp) }, + { be_const_key_weak(temperature, 32), be_const_class(be_class_Matter_Plugin_Sensor_Temp) }, { be_const_key_weak(flow, 4), be_const_class(be_class_Matter_Plugin_Sensor_Flow) }, { be_const_key_weak(v_contact, 6), be_const_class(be_class_Matter_Plugin_Virt_Sensor_Contact) }, { be_const_key_weak(http_relay, 3), be_const_class(be_class_Matter_Plugin_Bridge_OnOff) }, - { be_const_key_weak(v_relay, -1), be_const_class(be_class_Matter_Plugin_Virt_OnOff) }, + { be_const_key_weak(http_light2, 29), be_const_class(be_class_Matter_Plugin_Bridge_Light2) }, { be_const_key_weak(root, -1), be_const_class(be_class_Matter_Plugin_Root) }, { be_const_key_weak(http_light3, 9), be_const_class(be_class_Matter_Plugin_Bridge_Light3) }, - { be_const_key_weak(http_contact, -1), be_const_class(be_class_Matter_Plugin_Bridge_Sensor_Contact) }, - { be_const_key_weak(http_illuminance, 17), be_const_class(be_class_Matter_Plugin_Bridge_Sensor_Illuminance) }, { be_const_key_weak(light0, -1), be_const_class(be_class_Matter_Plugin_Light0) }, + { be_const_key_weak(http_illuminance, 35), be_const_class(be_class_Matter_Plugin_Bridge_Sensor_Illuminance) }, { be_const_key_weak(v_light2, -1), be_const_class(be_class_Matter_Plugin_Virt_Light2) }, + { be_const_key_weak(v_illuminance, -1), be_const_class(be_class_Matter_Plugin_Virt_Sensor_Illuminance) }, { be_const_key_weak(v_humidity, 15), be_const_class(be_class_Matter_Plugin_Virt_Sensor_Humidity) }, { be_const_key_weak(v_light0, -1), be_const_class(be_class_Matter_Plugin_Virt_Light0) }, - { be_const_key_weak(v_illuminance, -1), be_const_class(be_class_Matter_Plugin_Virt_Sensor_Illuminance) }, + { be_const_key_weak(onoff, -1), be_const_class(be_class_Matter_Plugin_Sensor_OnOff) }, { be_const_key_weak(relay, -1), be_const_class(be_class_Matter_Plugin_OnOff) }, { be_const_key_weak(http_light0, -1), be_const_class(be_class_Matter_Plugin_Bridge_Light0) }, { be_const_key_weak(shutter_X2Btilt, -1), be_const_class(be_class_Matter_Plugin_ShutterTilt) }, diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_zzz_TLV_test.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_zzz_TLV_test.h new file mode 100644 index 000000000..50a506760 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_zzz_TLV_test.h @@ -0,0 +1,7 @@ +/* Solidification of Matter_zzz_TLV_test.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_tasmota/include/be_port.h b/lib/libesp32/berry_tasmota/include/be_port.h index 91e7fe8fa..a7a1a7e23 100644 --- a/lib/libesp32/berry_tasmota/include/be_port.h +++ b/lib/libesp32/berry_tasmota/include/be_port.h @@ -8,3 +8,4 @@ #define MPATH_EXISTS 4 #define MPATH_MODIFIED 5 #define MPATH_REMOVE 6 +#define MPATH_RENAME 7 diff --git a/lib/libesp32/berry_tasmota/src/be_TFL_lib.c b/lib/libesp32/berry_tasmota/src/be_TFL_lib.c index bfc4c2b54..517693a57 100644 --- a/lib/libesp32/berry_tasmota/src/be_TFL_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_TFL_lib.c @@ -27,9 +27,6 @@ BE_FUNC_CTYPE_DECLARE(be_TFL_input, "b", "@(bytes)~"); extern bbool be_TFL_output(struct bvm *vm, const uint8_t *buf, size_t size); BE_FUNC_CTYPE_DECLARE(be_TFL_output, "b", "@(bytes)~"); -extern void be_TFL_rec(struct bvm *vm, const char* filename, size_t seconds); -BE_FUNC_CTYPE_DECLARE(be_TFL_rec, "", "@si"); - #include "be_fixed_TFL.h" /* @const_object_info_begin @@ -40,7 +37,6 @@ module TFL (scope: global) { output, ctype_func(be_TFL_output) log, ctype_func(be_TFL_log) stats, ctype_func(be_TFL_stats) - rec, ctype_func(be_TFL_rec) } @const_object_info_end */ diff --git a/lib/libesp32/berry_tasmota/src/be_flash_lib.c b/lib/libesp32/berry_tasmota/src/be_flash_lib.c index 9367828d2..a823a518d 100644 --- a/lib/libesp32/berry_tasmota/src/be_flash_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_flash_lib.c @@ -15,6 +15,10 @@ extern void p_factory(bbool force_ota); BE_FUNC_CTYPE_DECLARE(p_factory, "", "b"); +// return current OTA partition +extern int p_cur_ota(); +BE_FUNC_CTYPE_DECLARE(p_cur_ota, "i", ""); + int32_t p_flashid(void) { uint32_t id = bootloader_read_flash_id(); id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00); @@ -42,6 +46,7 @@ module flash (scope: global) { id, ctype_func(p_flashid) size, ctype_func(p_flashsize) + current_ota, ctype_func(p_cur_ota) } @const_object_info_end */ #include "be_fixed_flash.h" diff --git a/lib/libesp32/berry_tasmota/src/be_lv_tasmota_lib.c b/lib/libesp32/berry_tasmota/src/be_lv_tasmota_lib.c index 5fa0d4d58..3ca0b4bf7 100644 --- a/lib/libesp32/berry_tasmota/src/be_lv_tasmota_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_lv_tasmota_lib.c @@ -6,6 +6,7 @@ #ifdef USE_LVGL extern int lv0_start(bvm *vm); +extern int lv0_constants_as_hash(bvm *vm); // dump all integer constants extern int lv0_register_button_encoder(bvm *vm); // add buttons with encoder logic @@ -22,6 +23,7 @@ extern int lv0_load_freetype_font(bvm *vm); /* @const_object_info_begin module lv_tasmota (scope: global, strings: weak) { init, closure(lv_tasmota_init_closure) + _constants, func(lv0_constants_as_hash) start, func(lv0_start) splash, closure(lv_tasmota_splash_closure) diff --git a/lib/libesp32/berry_tasmota/src/be_path_tasmota_lib.c b/lib/libesp32/berry_tasmota/src/be_path_tasmota_lib.c index 1822abcc1..1ca2638d3 100644 --- a/lib/libesp32/berry_tasmota/src/be_path_tasmota_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_path_tasmota_lib.c @@ -36,6 +36,9 @@ static int m_path_mkdir(bvm *vm) { static int m_path_rmdir(bvm *vm) { return _m_path_action(vm, MPATH_RMDIR); } +static int m_path_rename(bvm *vm) { + return _m_path_action(vm, MPATH_RENAME); +} static int m_path_exists(bvm *vm) { return _m_path_action(vm, MPATH_EXISTS); } @@ -69,6 +72,7 @@ module path (scope: global, file: tasmota_path) { format, func(m_path_format) mkdir, func(m_path_mkdir) rmdir, func(m_path_rmdir) + rename, func(m_path_rename) } @const_object_info_end */ #include "be_fixed_tasmota_path.h" diff --git a/lib/libesp32/berry_tasmota/src/be_port.cpp b/lib/libesp32/berry_tasmota/src/be_port.cpp index 647c94269..0c70bf61c 100644 --- a/lib/libesp32/berry_tasmota/src/be_port.cpp +++ b/lib/libesp32/berry_tasmota/src/be_port.cpp @@ -119,7 +119,8 @@ extern "C" { break; } - if (be_top(vm) >= 1 && be_isstring(vm, 1)) { + int argc = be_top(vm); + if (argc >= 1 && be_isstring(vm, 1)) { const char *path = be_tostring(vm, 1); if (path != nullptr) { switch (action){ @@ -135,6 +136,16 @@ extern "C" { case MPATH_MKDIR: res = zip_ufsp.mkdir(path); break; + case MPATH_RENAME: + { + if (argc >= 2 && be_isstring(vm, 2)) { + const char *path2 = be_tostring(vm, 2); + res = zip_ufsp.rename(path, path2); + } else { + res = -1; + } + } + break; case MPATH_LISTDIR: be_newobject(vm, "list"); // add our list object and fall through returnit = 1; diff --git a/lib/libesp32/berry_tasmota/src/be_serial_lib.c b/lib/libesp32/berry_tasmota/src/be_serial_lib.c index 3b2c4cfd7..6592f270d 100644 --- a/lib/libesp32/berry_tasmota/src/be_serial_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_serial_lib.c @@ -6,9 +6,10 @@ * 2 wire communication - I2C *******************************************************************/ #include "be_constobj.h" -#include "esp_idf_version.h" +#include "esp_arduino_version.h" extern int b_serial_init(bvm *vm); +extern int b_config_tx_en(bvm *vm); extern int b_serial_deinit(bvm *vm); extern int b_serial_write(bvm *vm); @@ -16,7 +17,7 @@ extern int b_serial_read(bvm *vm); extern int b_serial_available(bvm *vm); extern int b_serial_flush(bvm *vm); -#if ESP_IDF_VERSION_MAJOR < 5 +#if (ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(2, 0, 15)) #include "esp32-hal.h" #else // it should be #include "HardwareSerial.h" @@ -83,7 +84,9 @@ class be_class_serial (scope: global, name: serial) { SERIAL_8O2, int(SERIAL_8O2) init, func(b_serial_init) + config_tx_en, func(b_config_tx_en) deinit, func(b_serial_deinit) + close, func(b_serial_deinit) write, func(b_serial_write) read, func(b_serial_read) diff --git a/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c b/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c index 54449644d..5ab61d2bd 100644 --- a/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c @@ -180,6 +180,7 @@ class be_class_tasmota (scope: global, name: Tasmota) { add_driver, closure(Tasmota_add_driver_closure) remove_driver, closure(Tasmota_remove_driver_closure) load, closure(Tasmota_load_closure) + compile, closure(Tasmota_compile_closure) wire_scan, closure(Tasmota_wire_scan_closure) time_str, closure(Tasmota_time_str_closure) urlfetch, closure(Tasmota_urlfetch_closure) diff --git a/lib/libesp32/berry_tasmota/src/be_webserver_lib.c b/lib/libesp32/berry_tasmota/src/be_webserver_lib.c index 279b1fb05..49aa105ff 100644 --- a/lib/libesp32/berry_tasmota/src/be_webserver_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_webserver_lib.c @@ -25,6 +25,7 @@ extern int w_webserver_content_response(bvm *vm); extern int w_webserver_content_send_style(bvm *vm); extern int w_webserver_content_flush(bvm *vm); extern int w_webserver_content_stop(bvm *vm); +extern int w_webserver_content_close(bvm *vm); extern int w_webserver_content_button(bvm *vm); extern int w_webserver_html_escape(bvm *vm); @@ -153,6 +154,7 @@ module webserver (scope: global) { content_open, func(w_webserver_content_open) content_start, func(w_webserver_content_start) content_stop, func(w_webserver_content_stop) + content_close, func(w_webserver_content_close) content_button, func(w_webserver_content_button) html_escape, func(w_webserver_html_escape) diff --git a/lib/libesp32/berry_tasmota/src/embedded/driver_class.be b/lib/libesp32/berry_tasmota/src/embedded/driver_class.be index eb2fadc38..2efed4619 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/driver_class.be +++ b/lib/libesp32/berry_tasmota/src/embedded/driver_class.be @@ -14,6 +14,7 @@ class Driver var save_before_restart var web_sensor var json_append + var after_teleperiod var button_pressed var display diff --git a/lib/libesp32/berry_tasmota/src/embedded/i2c_driver.be b/lib/libesp32/berry_tasmota/src/embedded/i2c_driver.be index 29d41f882..97cd50a3b 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/i2c_driver.be +++ b/lib/libesp32/berry_tasmota/src/embedded/i2c_driver.be @@ -84,6 +84,16 @@ class I2C_Driver var buf = self.wire.read_bytes(self.addr, reg, 2) return (buf[0] << 5) + buf[1] end + # read 14 bits + def read14(reg) + var buf = self.wire.read_bytes(self.addr, reg, 2) + return (buf[0] << 6) + buf[1] + end + # read 16 bits + def read16(reg) + var buf = self.wire.read_bytes(self.addr, reg, 2) + return (buf[0] << 8) + buf[1] + end # read 24 bits def read24(reg) var buf = self.wire.read_bytes(self.addr, reg, 3) diff --git a/lib/libesp32/berry_tasmota/src/embedded/lv_tasmota.be b/lib/libesp32/berry_tasmota/src/embedded/lv_tasmota.be index 3edea396c..f98dea1dc 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/lv_tasmota.be +++ b/lib/libesp32/berry_tasmota/src/embedded/lv_tasmota.be @@ -8,6 +8,7 @@ lv_tasmota = module("lv_tasmota") def init(lv_tasmota) import lv lv.start = lv_tasmota.start + lv._constants = lv_tasmota._constants lv.splash_init = lv_tasmota.splash_init lv.splash_remove = lv_tasmota.splash_remove lv.splash = lv_tasmota.splash diff --git a/lib/libesp32/berry_tasmota/src/embedded/lv_tasmota_widgets.be b/lib/libesp32/berry_tasmota/src/embedded/lv_tasmota_widgets.be index e9f464906..409041429 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/lv_tasmota_widgets.be +++ b/lib/libesp32/berry_tasmota/src/embedded/lv_tasmota_widgets.be @@ -94,6 +94,7 @@ class lv_signal_arcs : lv_obj super(self).init(parent) self.set_style_bg_opa(0, 0) # transparent background self.set_style_border_width(0, 0) # remove border + self.set_style_pad_all(0,0) # own values self.percentage = 100 # pre-allocate buffers diff --git a/lib/libesp32/berry_tasmota/src/embedded/rule_matcher.be b/lib/libesp32/berry_tasmota/src/embedded/rule_matcher.be index 79ed625fc..e7b83f052 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/rule_matcher.be +++ b/lib/libesp32/berry_tasmota/src/embedded/rule_matcher.be @@ -171,7 +171,7 @@ class Rule_Matcher var keyu = string.toupper(keyi) if isinstance(m, map) for k:m.keys() - if string.toupper(k)==keyu + if string.toupper(str(k))==keyu return k end end diff --git a/lib/libesp32/berry_tasmota/src/embedded/tasmota_class.be b/lib/libesp32/berry_tasmota/src/embedded/tasmota_class.be index 981c49482..92b186e5c 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/tasmota_class.be +++ b/lib/libesp32/berry_tasmota/src/embedded/tasmota_class.be @@ -30,12 +30,7 @@ class Tasmota self.settings = ctypes_bytes_dyn(introspect.toptr(settings_addr), self._settings_def) end self.wd = "" - self._debug_present = false - try - import debug - self._debug_present = true - except .. - end + self._debug_present = global.contains("debug") # declare `UrlFetch` command self.add_cmd('UrlFetch', def (cmd, idx, payload, payload_json) self.urlfetch_cmd(cmd, idx, payload, payload_json) end) end @@ -357,7 +352,55 @@ class Tasmota return format("%04d-%02d-%02dT%02d:%02d:%02d", tm['year'], tm['month'], tm['day'], tm['hour'], tm['min'], tm['sec']) end - def load(f) + # takes a .be file and compile to .bec file with the same name + # tasmota.compile("autoexec.be") -- compiles autoexec.be to autoexec.bec + # + # Returns 'true' if succesful of 'false' if file is not found or corrupt + def compile(f_name) + import string + if !string.endswith(f_name, ".be") + print(f"BRY: file '{f_name}' does not have '.be' extension") + return false + end + + if string.find(f_name, "#") > 0 + print(f"BRY: cannot compile file in read-only archive") + return false + end + + # compile in-memory + var compiled_code + try + compiled_code = compile(f_name, 'file') + if (compiled_code == nil) + print(f"BRY: empty compiled file") + return false + end + except .. as e, m + print(f"BRY: failed to load '{f_name}' ({e} - {m})") + return false + end + + # save to .bec file + var f_name_bec = f_name + "c" + try + self.save(f_name_bec, compiled_code) + except .. as e + print(format('BRY: could not save compiled file %s (%s)',f_name_bec,e)) + return false + end + + return true + end + + # takes file name with or without suffix: + # load("autoexec.be") -- loads file from .be or .bec if .be is not here, remove .bec if .be exists + # load("autoexec") -- same as above + # load("autoexec.bec") -- load only .bec file and ignore .be + # load("app.tapp#module.be") -- loads from tapp arhive + # + # Returns 'true' if succesful of 'false' if file is not found or corrupt + def load(f_name) # embedded functions # puth_path: adds the current archive to sys.path def push_path(p) @@ -392,7 +435,7 @@ class Tasmota f.close() except .. as e if f != nil f.close() end - print(format('BRY: failed to load compiled \'%s\' (%s)',fname_bec,e)) + print(f"BRY: failed to load compiled '{fname_bec}' ({e})") end return nil end @@ -414,7 +457,7 @@ class Tasmota var compiled = compile(f_name, 'file') return compiled except .. as e, m - print(format('BRY: failed to load \'%s\' (%s - %s)',f_name,e,m)) + print(f"BRY: failed to load '{f_name}' ({e} - {m})") end return nil end @@ -427,7 +470,7 @@ class Tasmota compiled_code() return true except .. as e, m - print(format("BRY: failed to run compiled code '%s' - %s", e, m)) + print(f"BRY: failed to run compiled code ({e} - {m})") if self._debug_present import debug debug.traceback() @@ -441,51 +484,54 @@ class Tasmota import path # fail if empty string - if size(f) == 0 return false end - # Ex: f = 'app.zip#autoexec' + if size(f_name) == 0 return false end + # Ex: f_name = 'app.zip#autoexec' # add leading '/' if absent - if f[0] != '/' f = '/' + f end - # Ex: f = '/app.zip#autoexec' + if !string.startswith(f_name, '/') f_name = '/' + f_name end + # Ex: f_name = '/app.zip#autoexec' - var f_items = string.split(f, '#') - var f_prefix = f_items[0] - var f_suffix = f_items[-1] # last token - var f_archive = size(f_items) > 1 # is the file in an archive + var f_find_hash = string.find(f_name, '#') + var f_archive = (f_find_hash > 0) # is the file in an archive + var f_prefix = f_archive ? f_name[0..f_find_hash - 1] : f_name + var f_suffix = f_archive ? f_name[f_find_hash + 1 ..] : f_name # last token # if no dot, add the default '.be' extension if string.find(f_suffix, '.') < 0 # does the final file has a '.' - f += ".be" + f_name += ".be" f_suffix += ".be" end - # Ex: f = '/app.zip#autoexec.be' + # Ex: f_name = '/app.zip#autoexec.be' # is the suffix .be or .bec ? - var suffix_be = f_suffix[-3..-1] == '.be' - var suffix_bec = f_suffix[-4..-1] == '.bec' - # Ex: f = '/app.zip#autoexec.be', f_suffix = 'autoexec.be', suffix_be = true, suffix_bec = false + var suffix_be = string.endswith(f_suffix, '.be') + var suffix_bec = string.endswith(f_suffix, '.bec') + var f_name_bec = suffix_bec ? f_name : f_name + "c" # f_name_bec holds the bec version of the filename + # Ex: f_name = '/app.zip#autoexec.be', f_suffix = 'autoexec.be', suffix_be = true, suffix_bec = false # check that the file ends with '.be' of '.bec' if !suffix_be && !suffix_bec - raise "io_error", "file extension is not '.be' or '.bec'" + print("BRY: file extension is not '.be' nor '.bec'") + return false end - # get the last_modified time of the file or archive, returns `nil` if the file does not exist - var f_time = path.last_modified(f) - var f_name_bec = suffix_bec ? f : f + "c" # f_name_bec holds the bec version of the filename - - if suffix_bec - if f_time == nil return false end # file requested is .bec but does not exist, fail - # from now, .bec file does exist - else - var f_time_bec = path.last_modified(f_name_bec) # timestamp for .bec bytecode, nil if does not exist - if f_time == nil && f_time_bec == nil return false end # abort if neither .be nor .bec file exist - if f_time_bec != nil && (f_time == nil || f_time_bec >= f_time) - # bytecode exists and is more recent than berry source, use bytecode - ##### temporarily disable loading from bec file - suffix_bec = true + var use_bec = false # if 'true' load .bec file, if 'false' use .be file + if suffix_bec # we accept only .bec file, thys ignore .be + if !path.exists(f_name_bec) + return false # file does not exist + end + use_bec = true + else # suffix is .be so we can use .be or .bec + if path.exists(f_name) + # in such case remove .bec file if it exists to avoid confusion with obsolete version + if path.exists(f_name_bec) + try_remove_file(f_name_bec) + end + elif path.exists(f_name_bec) + use_bec = true + else + return false # file does not exist end - # print("f_time",f_time,"f_time_bec",f_time_bec,"suffix_bec",suffix_bec) end # recall the working directory @@ -498,16 +544,16 @@ class Tasmota # try to load code into `compiled_code`, or `nil` if didn't succeed var compiled_code - if suffix_bec # try the .bec version + if use_bec # try the .bec version # in this section we try to load the pre-compiled bytecode first # (we already know that the file exists) var bec_version = try_get_bec_version(f_name_bec) var version_ok = true if bec_version == nil - print(format('BRY: corrupt bytecode \'%s\'',f_name_bec)) + print(f"BRY: corrupt bytecode '{f_name_bec}'") version_ok = false elif bec_version != 0x04 # -- this is the currenlty supported version - print(format('BRY: bytecode has wrong version \'%s\' (%i)',f_name_bec,bec_version)) + print(f"BRY: bytecode has wrong version '{f_name_bec}' ({bec_version})") version_ok = false end @@ -517,25 +563,15 @@ class Tasmota if compiled_code == nil # bytecode is bad, try to delete it and fallback try_remove_file(f_name_bec) - suffix_bec = false + use_bec = false end end - if suffix_be && compiled_code == nil + if !use_bec # the pre-compiled is absent to failed, load the be file instead - compiled_code = try_compile(f) + compiled_code = try_compile(f_name) end - # save the compiled bytecode unless it's an archive - # print("compiled_code",compiled_code,"suffix_be",suffix_be,"suffix_bec",suffix_bec,"archive",f_archive,"f_name_bec",f_name_bec) - if compiled_code != nil && !suffix_bec && !f_archive - # try to save the pre-compiled version - try - self.save(f_name_bec, compiled_code) - except .. as e - print(format('BRY: could not save compiled file %s (%s)',f_name_bec,e)) - end - end # call the compiled code var run_ok = try_run_compiled(compiled_code) # call successfuls diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_driver_class.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_driver_class.h index 75351ee0c..d67d02248 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_driver_class.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_driver_class.h @@ -70,24 +70,25 @@ be_local_closure(Driver_add_cmd, /* name */ ** Solidified class: Driver ********************************************************************/ be_local_class(Driver, - 13, + 14, NULL, - be_nested_map(14, + be_nested_map(15, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key(web_add_console_button, 6), be_const_var(7) }, - { be_const_key(web_add_config_button, -1), be_const_var(6) }, - { be_const_key(button_pressed, 9), be_const_var(11) }, - { be_const_key(every_second, 1), be_const_var(0) }, - { be_const_key(web_add_handler, 11), be_const_var(2) }, + { be_const_key(web_add_config_button, 12), be_const_var(6) }, + { be_const_key(web_add_main_button, -1), be_const_var(4) }, + { be_const_key(web_add_handler, 10), be_const_var(2) }, + { be_const_key(save_before_restart, 5), be_const_var(8) }, { be_const_key(add_cmd, -1), be_const_closure(Driver_add_cmd_closure) }, - { be_const_key(web_sensor, -1), be_const_var(9) }, - { be_const_key(display, -1), be_const_var(12) }, - { be_const_key(web_add_main_button, 2), be_const_var(4) }, - { be_const_key(save_before_restart, -1), be_const_var(8) }, - { be_const_key(web_add_management_button, 0), be_const_var(5) }, - { be_const_key(every_100ms, 13), be_const_var(1) }, - { be_const_key(json_append, -1), be_const_var(10) }, { be_const_key(web_add_button, -1), be_const_var(3) }, + { be_const_key(web_add_management_button, -1), be_const_var(5) }, + { be_const_key(display, -1), be_const_var(13) }, + { be_const_key(after_teleperiod, -1), be_const_var(11) }, + { be_const_key(every_100ms, -1), be_const_var(1) }, + { be_const_key(web_add_console_button, 13), be_const_var(7) }, + { be_const_key(button_pressed, -1), be_const_var(12) }, + { be_const_key(every_second, -1), be_const_var(0) }, + { be_const_key(web_sensor, -1), be_const_var(9) }, + { be_const_key(json_append, 1), be_const_var(10) }, })), (bstring*) &be_const_str_Driver ); diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_driver.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_driver.h index e4ff81021..3b29d8c76 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_driver.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_driver.h @@ -6,135 +6,6 @@ extern const bclass be_class_I2C_Driver; -/******************************************************************** -** Solidified function: read32 -********************************************************************/ -be_local_closure(I2C_Driver_read32, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_nested_str(wire), - /* K1 */ be_nested_str(read_bytes), - /* K2 */ be_nested_str(addr), - /* K3 */ be_const_int(0), - /* K4 */ be_const_int(1), - /* K5 */ be_const_int(2), - /* K6 */ be_const_int(3), - }), - &be_const_str_read32, - &be_const_str_solidified, - ( &(const binstruction[20]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x88100102, // 0002 GETMBR R4 R0 K2 - 0x5C140200, // 0003 MOVE R5 R1 - 0x541A0003, // 0004 LDINT R6 4 - 0x7C080800, // 0005 CALL R2 4 - 0x940C0503, // 0006 GETIDX R3 R2 K3 - 0x54120017, // 0007 LDINT R4 24 - 0x380C0604, // 0008 SHL R3 R3 R4 - 0x94100504, // 0009 GETIDX R4 R2 K4 - 0x5416000F, // 000A LDINT R5 16 - 0x38100805, // 000B SHL R4 R4 R5 - 0x000C0604, // 000C ADD R3 R3 R4 - 0x94100505, // 000D GETIDX R4 R2 K5 - 0x54160007, // 000E LDINT R5 8 - 0x38100805, // 000F SHL R4 R4 R5 - 0x000C0604, // 0010 ADD R3 R3 R4 - 0x94100506, // 0011 GETIDX R4 R2 K6 - 0x000C0604, // 0012 ADD R3 R3 R4 - 0x80040600, // 0013 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: write8 -********************************************************************/ -be_local_closure(I2C_Driver_write8, /* name */ - be_nested_proto( - 9, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str(wire), - /* K1 */ be_nested_str(write), - /* K2 */ be_nested_str(addr), - /* K3 */ be_const_int(1), - }), - &be_const_str_write8, - &be_const_str_solidified, - ( &(const binstruction[ 8]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x8C0C0701, // 0001 GETMET R3 R3 K1 - 0x88140102, // 0002 GETMBR R5 R0 K2 - 0x5C180200, // 0003 MOVE R6 R1 - 0x5C1C0400, // 0004 MOVE R7 R2 - 0x58200003, // 0005 LDCONST R8 K3 - 0x7C0C0A00, // 0006 CALL R3 5 - 0x80040600, // 0007 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: read12 -********************************************************************/ -be_local_closure(I2C_Driver_read12, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str(wire), - /* K1 */ be_nested_str(read_bytes), - /* K2 */ be_nested_str(addr), - /* K3 */ be_const_int(2), - /* K4 */ be_const_int(0), - /* K5 */ be_const_int(1), - }), - &be_const_str_read12, - &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x88100102, // 0002 GETMBR R4 R0 K2 - 0x5C140200, // 0003 MOVE R5 R1 - 0x58180003, // 0004 LDCONST R6 K3 - 0x7C080800, // 0005 CALL R2 4 - 0x940C0504, // 0006 GETIDX R3 R2 K4 - 0x54120003, // 0007 LDINT R4 4 - 0x380C0604, // 0008 SHL R3 R3 R4 - 0x94100505, // 0009 GETIDX R4 R2 K5 - 0x000C0604, // 000A ADD R3 R3 R4 - 0x80040600, // 000B RET 1 R3 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: write_bit ********************************************************************/ @@ -189,6 +60,99 @@ be_local_closure(I2C_Driver_write_bit, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: read32 +********************************************************************/ +be_local_closure(I2C_Driver_read32, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str(wire), + /* K1 */ be_nested_str(read_bytes), + /* K2 */ be_nested_str(addr), + /* K3 */ be_const_int(0), + /* K4 */ be_const_int(1), + /* K5 */ be_const_int(2), + /* K6 */ be_const_int(3), + }), + &be_const_str_read32, + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x88100102, // 0002 GETMBR R4 R0 K2 + 0x5C140200, // 0003 MOVE R5 R1 + 0x541A0003, // 0004 LDINT R6 4 + 0x7C080800, // 0005 CALL R2 4 + 0x940C0503, // 0006 GETIDX R3 R2 K3 + 0x54120017, // 0007 LDINT R4 24 + 0x380C0604, // 0008 SHL R3 R3 R4 + 0x94100504, // 0009 GETIDX R4 R2 K4 + 0x5416000F, // 000A LDINT R5 16 + 0x38100805, // 000B SHL R4 R4 R5 + 0x000C0604, // 000C ADD R3 R3 R4 + 0x94100505, // 000D GETIDX R4 R2 K5 + 0x54160007, // 000E LDINT R5 8 + 0x38100805, // 000F SHL R4 R4 R5 + 0x000C0604, // 0010 ADD R3 R3 R4 + 0x94100506, // 0011 GETIDX R4 R2 K6 + 0x000C0604, // 0012 ADD R3 R3 R4 + 0x80040600, // 0013 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read13 +********************************************************************/ +be_local_closure(I2C_Driver_read13, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str(wire), + /* K1 */ be_nested_str(read_bytes), + /* K2 */ be_nested_str(addr), + /* K3 */ be_const_int(2), + /* K4 */ be_const_int(0), + /* K5 */ be_const_int(1), + }), + &be_const_str_read13, + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x88100102, // 0002 GETMBR R4 R0 K2 + 0x5C140200, // 0003 MOVE R5 R1 + 0x58180003, // 0004 LDCONST R6 K3 + 0x7C080800, // 0005 CALL R2 4 + 0x940C0504, // 0006 GETIDX R3 R2 K4 + 0x54120004, // 0007 LDINT R4 5 + 0x380C0604, // 0008 SHL R3 R3 R4 + 0x94100505, // 0009 GETIDX R4 R2 K5 + 0x000C0604, // 000A ADD R3 R3 R4 + 0x80040600, // 000B RET 1 R3 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: read24 ********************************************************************/ @@ -237,9 +201,9 @@ be_local_closure(I2C_Driver_read24, /* name */ /******************************************************************** -** Solidified function: read8 +** Solidified function: read14 ********************************************************************/ -be_local_closure(I2C_Driver_read8, /* name */ +be_local_closure(I2C_Driver_read14, /* name */ be_nested_proto( 7, /* nstack */ 2, /* argc */ @@ -249,22 +213,29 @@ be_local_closure(I2C_Driver_read8, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ + ( &(const bvalue[ 6]) { /* constants */ /* K0 */ be_nested_str(wire), - /* K1 */ be_nested_str(read), + /* K1 */ be_nested_str(read_bytes), /* K2 */ be_nested_str(addr), - /* K3 */ be_const_int(1), + /* K3 */ be_const_int(2), + /* K4 */ be_const_int(0), + /* K5 */ be_const_int(1), }), - &be_const_str_read8, + &be_const_str_read14, &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ + ( &(const binstruction[12]) { /* code */ 0x88080100, // 0000 GETMBR R2 R0 K0 0x8C080501, // 0001 GETMET R2 R2 K1 0x88100102, // 0002 GETMBR R4 R0 K2 0x5C140200, // 0003 MOVE R5 R1 0x58180003, // 0004 LDCONST R6 K3 0x7C080800, // 0005 CALL R2 4 - 0x80040400, // 0006 RET 1 R2 + 0x940C0504, // 0006 GETIDX R3 R2 K4 + 0x54120005, // 0007 LDINT R4 6 + 0x380C0604, // 0008 SHL R3 R3 R4 + 0x94100505, // 0009 GETIDX R4 R2 K5 + 0x000C0604, // 000A ADD R3 R3 R4 + 0x80040600, // 000B RET 1 R3 }) ) ); @@ -350,9 +321,80 @@ be_local_closure(I2C_Driver_init, /* name */ /******************************************************************** -** Solidified function: read13 +** Solidified function: write8 ********************************************************************/ -be_local_closure(I2C_Driver_read13, /* name */ +be_local_closure(I2C_Driver_write8, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str(wire), + /* K1 */ be_nested_str(write), + /* K2 */ be_nested_str(addr), + /* K3 */ be_const_int(1), + }), + &be_const_str_write8, + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x8C0C0701, // 0001 GETMET R3 R3 K1 + 0x88140102, // 0002 GETMBR R5 R0 K2 + 0x5C180200, // 0003 MOVE R6 R1 + 0x5C1C0400, // 0004 MOVE R7 R2 + 0x58200003, // 0005 LDCONST R8 K3 + 0x7C0C0A00, // 0006 CALL R3 5 + 0x80040600, // 0007 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read8 +********************************************************************/ +be_local_closure(I2C_Driver_read8, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str(wire), + /* K1 */ be_nested_str(read), + /* K2 */ be_nested_str(addr), + /* K3 */ be_const_int(1), + }), + &be_const_str_read8, + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x88100102, // 0002 GETMBR R4 R0 K2 + 0x5C140200, // 0003 MOVE R5 R1 + 0x58180003, // 0004 LDCONST R6 K3 + 0x7C080800, // 0005 CALL R2 4 + 0x80040400, // 0006 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read12 +********************************************************************/ +be_local_closure(I2C_Driver_read12, /* name */ be_nested_proto( 7, /* nstack */ 2, /* argc */ @@ -370,7 +412,7 @@ be_local_closure(I2C_Driver_read13, /* name */ /* K4 */ be_const_int(0), /* K5 */ be_const_int(1), }), - &be_const_str_read13, + &be_const_str_read12, &be_const_str_solidified, ( &(const binstruction[12]) { /* code */ 0x88080100, // 0000 GETMBR R2 R0 K0 @@ -380,7 +422,49 @@ be_local_closure(I2C_Driver_read13, /* name */ 0x58180003, // 0004 LDCONST R6 K3 0x7C080800, // 0005 CALL R2 4 0x940C0504, // 0006 GETIDX R3 R2 K4 - 0x54120004, // 0007 LDINT R4 5 + 0x54120003, // 0007 LDINT R4 4 + 0x380C0604, // 0008 SHL R3 R3 R4 + 0x94100505, // 0009 GETIDX R4 R2 K5 + 0x000C0604, // 000A ADD R3 R3 R4 + 0x80040600, // 000B RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read16 +********************************************************************/ +be_local_closure(I2C_Driver_read16, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str(wire), + /* K1 */ be_nested_str(read_bytes), + /* K2 */ be_nested_str(addr), + /* K3 */ be_const_int(2), + /* K4 */ be_const_int(0), + /* K5 */ be_const_int(1), + }), + &be_const_str_read16, + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x88100102, // 0002 GETMBR R4 R0 K2 + 0x5C140200, // 0003 MOVE R5 R1 + 0x58180003, // 0004 LDCONST R6 K3 + 0x7C080800, // 0005 CALL R2 4 + 0x940C0504, // 0006 GETIDX R3 R2 K4 + 0x54120007, // 0007 LDINT R4 8 0x380C0604, // 0008 SHL R3 R3 R4 0x94100505, // 0009 GETIDX R4 R2 K5 0x000C0604, // 000A ADD R3 R3 R4 @@ -397,19 +481,21 @@ be_local_closure(I2C_Driver_read13, /* name */ be_local_class(I2C_Driver, 3, NULL, - be_nested_map(11, + be_nested_map(13, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key(read32, -1), be_const_closure(I2C_Driver_read32_closure) }, - { be_const_key(write8, 6), be_const_closure(I2C_Driver_write8_closure) }, - { be_const_key(name, -1), be_const_var(2) }, - { be_const_key(addr, 8), be_const_var(1) }, - { be_const_key(read12, -1), be_const_closure(I2C_Driver_read12_closure) }, - { be_const_key(wire, 10), be_const_var(0) }, - { be_const_key(read13, -1), be_const_closure(I2C_Driver_read13_closure) }, - { be_const_key(read24, -1), be_const_closure(I2C_Driver_read24_closure) }, - { be_const_key(read8, -1), be_const_closure(I2C_Driver_read8_closure) }, - { be_const_key(init, -1), be_const_closure(I2C_Driver_init_closure) }, { be_const_key(write_bit, -1), be_const_closure(I2C_Driver_write_bit_closure) }, + { be_const_key(addr, -1), be_const_var(1) }, + { be_const_key(read32, -1), be_const_closure(I2C_Driver_read32_closure) }, + { be_const_key(read13, -1), be_const_closure(I2C_Driver_read13_closure) }, + { be_const_key(read16, -1), be_const_closure(I2C_Driver_read16_closure) }, + { be_const_key(read14, -1), be_const_closure(I2C_Driver_read14_closure) }, + { be_const_key(read24, 12), be_const_closure(I2C_Driver_read24_closure) }, + { be_const_key(name, 4), be_const_var(2) }, + { be_const_key(write8, -1), be_const_closure(I2C_Driver_write8_closure) }, + { be_const_key(wire, 8), be_const_var(0) }, + { be_const_key(read8, -1), be_const_closure(I2C_Driver_read8_closure) }, + { be_const_key(read12, -1), be_const_closure(I2C_Driver_read12_closure) }, + { be_const_key(init, -1), be_const_closure(I2C_Driver_init_closure) }, })), (bstring*) &be_const_str_I2C_Driver ); diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota.h index 5ff64c7fd..f982fdcb3 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota.h @@ -17,46 +17,47 @@ be_local_closure(lv_tasmota_init, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[35]) { /* constants */ + ( &(const bvalue[36]) { /* constants */ /* K0 */ be_nested_str_weak(lv), /* K1 */ be_nested_str_weak(start), - /* K2 */ be_nested_str_weak(splash_init), - /* K3 */ be_nested_str_weak(splash_remove), - /* K4 */ be_nested_str_weak(splash), - /* K5 */ be_nested_str_weak(_splash), - /* K6 */ be_nested_str_weak(font_montserrat), - /* K7 */ be_nested_str_weak(montserrat_font), - /* K8 */ be_nested_str_weak(font_seg7), - /* K9 */ be_nested_str_weak(seg7_font), - /* K10 */ be_nested_str_weak(font_embedded), - /* K11 */ be_nested_str_weak(load_freetype_font), - /* K12 */ be_nested_str_weak(register_button_encoder), - /* K13 */ be_nested_str_weak(screenshot), - /* K14 */ be_nested_str_weak(version), - /* K15 */ be_nested_str_weak(version_major), - /* K16 */ be_nested_str_weak(clock), - /* K17 */ be_nested_str_weak(lv_clock), - /* K18 */ be_nested_str_weak(clock_icon), - /* K19 */ be_nested_str_weak(lv_clock_icon), - /* K20 */ be_nested_str_weak(signal_arcs), - /* K21 */ be_nested_str_weak(lv_signal_arcs), - /* K22 */ be_nested_str_weak(signal_bars), - /* K23 */ be_nested_str_weak(lv_signal_bars), - /* K24 */ be_nested_str_weak(wifi_arcs_icon), - /* K25 */ be_nested_str_weak(lv_wifi_arcs_icon), - /* K26 */ be_nested_str_weak(wifi_arcs), - /* K27 */ be_nested_str_weak(lv_wifi_arcs), - /* K28 */ be_nested_str_weak(wifi_bars_icon), - /* K29 */ be_nested_str_weak(lv_wifi_bars_icon), - /* K30 */ be_nested_str_weak(wifi_bars), - /* K31 */ be_nested_str_weak(lv_wifi_bars), - /* K32 */ be_nested_str_weak(tasmota), - /* K33 */ be_nested_str_weak(get_option), - /* K34 */ be_const_int(0), + /* K2 */ be_nested_str_weak(_constants), + /* K3 */ be_nested_str_weak(splash_init), + /* K4 */ be_nested_str_weak(splash_remove), + /* K5 */ be_nested_str_weak(splash), + /* K6 */ be_nested_str_weak(_splash), + /* K7 */ be_nested_str_weak(font_montserrat), + /* K8 */ be_nested_str_weak(montserrat_font), + /* K9 */ be_nested_str_weak(font_seg7), + /* K10 */ be_nested_str_weak(seg7_font), + /* K11 */ be_nested_str_weak(font_embedded), + /* K12 */ be_nested_str_weak(load_freetype_font), + /* K13 */ be_nested_str_weak(register_button_encoder), + /* K14 */ be_nested_str_weak(screenshot), + /* K15 */ be_nested_str_weak(version), + /* K16 */ be_nested_str_weak(version_major), + /* K17 */ be_nested_str_weak(clock), + /* K18 */ be_nested_str_weak(lv_clock), + /* K19 */ be_nested_str_weak(clock_icon), + /* K20 */ be_nested_str_weak(lv_clock_icon), + /* K21 */ be_nested_str_weak(signal_arcs), + /* K22 */ be_nested_str_weak(lv_signal_arcs), + /* K23 */ be_nested_str_weak(signal_bars), + /* K24 */ be_nested_str_weak(lv_signal_bars), + /* K25 */ be_nested_str_weak(wifi_arcs_icon), + /* K26 */ be_nested_str_weak(lv_wifi_arcs_icon), + /* K27 */ be_nested_str_weak(wifi_arcs), + /* K28 */ be_nested_str_weak(lv_wifi_arcs), + /* K29 */ be_nested_str_weak(wifi_bars_icon), + /* K30 */ be_nested_str_weak(lv_wifi_bars_icon), + /* K31 */ be_nested_str_weak(wifi_bars), + /* K32 */ be_nested_str_weak(lv_wifi_bars), + /* K33 */ be_nested_str_weak(tasmota), + /* K34 */ be_nested_str_weak(get_option), + /* K35 */ be_const_int(0), }), be_str_weak(init), &be_const_str_solidified, - ( &(const binstruction[56]) { /* code */ + ( &(const binstruction[58]) { /* code */ 0xA4060000, // 0000 IMPORT R1 K0 0x88080101, // 0001 GETMBR R2 R0 K1 0x90060202, // 0002 SETMBR R1 K1 R2 @@ -66,17 +67,17 @@ be_local_closure(lv_tasmota_init, /* name */ 0x90060602, // 0006 SETMBR R1 K3 R2 0x88080104, // 0007 GETMBR R2 R0 K4 0x90060802, // 0008 SETMBR R1 K4 R2 - 0x4C080000, // 0009 LDNIL R2 + 0x88080105, // 0009 GETMBR R2 R0 K5 0x90060A02, // 000A SETMBR R1 K5 R2 - 0x88080106, // 000B GETMBR R2 R0 K6 + 0x4C080000, // 000B LDNIL R2 0x90060C02, // 000C SETMBR R1 K6 R2 - 0x88080106, // 000D GETMBR R2 R0 K6 + 0x88080107, // 000D GETMBR R2 R0 K7 0x90060E02, // 000E SETMBR R1 K7 R2 - 0x88080108, // 000F GETMBR R2 R0 K8 + 0x88080107, // 000F GETMBR R2 R0 K7 0x90061002, // 0010 SETMBR R1 K8 R2 - 0x88080108, // 0011 GETMBR R2 R0 K8 + 0x88080109, // 0011 GETMBR R2 R0 K9 0x90061202, // 0012 SETMBR R1 K9 R2 - 0x8808010A, // 0013 GETMBR R2 R0 K10 + 0x88080109, // 0013 GETMBR R2 R0 K9 0x90061402, // 0014 SETMBR R1 K10 R2 0x8808010B, // 0015 GETMBR R2 R0 K11 0x90061602, // 0016 SETMBR R1 K11 R2 @@ -84,35 +85,37 @@ be_local_closure(lv_tasmota_init, /* name */ 0x90061802, // 0018 SETMBR R1 K12 R2 0x8808010D, // 0019 GETMBR R2 R0 K13 0x90061A02, // 001A SETMBR R1 K13 R2 - 0x8C08030F, // 001B GETMET R2 R1 K15 - 0x7C080200, // 001C CALL R2 1 - 0x90061C02, // 001D SETMBR R1 K14 R2 - 0xB80A2200, // 001E GETNGBL R2 K17 - 0x90062002, // 001F SETMBR R1 K16 R2 - 0xB80A2600, // 0020 GETNGBL R2 K19 - 0x90062402, // 0021 SETMBR R1 K18 R2 - 0xB80A2A00, // 0022 GETNGBL R2 K21 - 0x90062802, // 0023 SETMBR R1 K20 R2 - 0xB80A2E00, // 0024 GETNGBL R2 K23 - 0x90062C02, // 0025 SETMBR R1 K22 R2 - 0xB80A3200, // 0026 GETNGBL R2 K25 - 0x90063002, // 0027 SETMBR R1 K24 R2 - 0xB80A3600, // 0028 GETNGBL R2 K27 - 0x90063402, // 0029 SETMBR R1 K26 R2 - 0xB80A3A00, // 002A GETNGBL R2 K29 - 0x90063802, // 002B SETMBR R1 K28 R2 - 0xB80A3E00, // 002C GETNGBL R2 K31 - 0x90063C02, // 002D SETMBR R1 K30 R2 + 0x8808010E, // 001B GETMBR R2 R0 K14 + 0x90061C02, // 001C SETMBR R1 K14 R2 + 0x8C080310, // 001D GETMET R2 R1 K16 + 0x7C080200, // 001E CALL R2 1 + 0x90061E02, // 001F SETMBR R1 K15 R2 + 0xB80A2400, // 0020 GETNGBL R2 K18 + 0x90062202, // 0021 SETMBR R1 K17 R2 + 0xB80A2800, // 0022 GETNGBL R2 K20 + 0x90062602, // 0023 SETMBR R1 K19 R2 + 0xB80A2C00, // 0024 GETNGBL R2 K22 + 0x90062A02, // 0025 SETMBR R1 K21 R2 + 0xB80A3000, // 0026 GETNGBL R2 K24 + 0x90062E02, // 0027 SETMBR R1 K23 R2 + 0xB80A3400, // 0028 GETNGBL R2 K26 + 0x90063202, // 0029 SETMBR R1 K25 R2 + 0xB80A3800, // 002A GETNGBL R2 K28 + 0x90063602, // 002B SETMBR R1 K27 R2 + 0xB80A3C00, // 002C GETNGBL R2 K30 + 0x90063A02, // 002D SETMBR R1 K29 R2 0xB80A4000, // 002E GETNGBL R2 K32 - 0x8C080521, // 002F GETMET R2 R2 K33 - 0x54120086, // 0030 LDINT R4 135 - 0x7C080400, // 0031 CALL R2 2 - 0x1C080522, // 0032 EQ R2 R2 K34 - 0x780A0001, // 0033 JMPF R2 #0036 - 0x8C080302, // 0034 GETMET R2 R1 K2 - 0x7C080200, // 0035 CALL R2 1 - 0x4C080000, // 0036 LDNIL R2 - 0x80040400, // 0037 RET 1 R2 + 0x90063E02, // 002F SETMBR R1 K31 R2 + 0xB80A4200, // 0030 GETNGBL R2 K33 + 0x8C080522, // 0031 GETMET R2 R2 K34 + 0x54120086, // 0032 LDINT R4 135 + 0x7C080400, // 0033 CALL R2 2 + 0x1C080523, // 0034 EQ R2 R2 K35 + 0x780A0001, // 0035 JMPF R2 #0038 + 0x8C080303, // 0036 GETMET R2 R1 K3 + 0x7C080200, // 0037 CALL R2 1 + 0x4C080000, // 0038 LDNIL R2 + 0x80040400, // 0039 RET 1 R2 }) ) ); diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota_widgets.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota_widgets.h index 518d6e719..5977e9117 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota_widgets.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota_widgets.h @@ -678,23 +678,24 @@ be_local_closure(lv_signal_arcs_init, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[12]) { /* constants */ + ( &(const bvalue[13]) { /* constants */ /* K0 */ be_nested_str_weak(init), /* K1 */ be_nested_str_weak(set_style_bg_opa), /* K2 */ be_const_int(0), /* K3 */ be_nested_str_weak(set_style_border_width), - /* K4 */ be_nested_str_weak(percentage), - /* K5 */ be_nested_str_weak(area), - /* K6 */ be_nested_str_weak(lv), - /* K7 */ be_nested_str_weak(arc_dsc), - /* K8 */ be_nested_str_weak(draw_arc_dsc), - /* K9 */ be_nested_str_weak(add_event_cb), - /* K10 */ be_nested_str_weak(widget_event), - /* K11 */ be_nested_str_weak(EVENT_DRAW_MAIN), + /* K4 */ be_nested_str_weak(set_style_pad_all), + /* K5 */ be_nested_str_weak(percentage), + /* K6 */ be_nested_str_weak(area), + /* K7 */ be_nested_str_weak(lv), + /* K8 */ be_nested_str_weak(arc_dsc), + /* K9 */ be_nested_str_weak(draw_arc_dsc), + /* K10 */ be_nested_str_weak(add_event_cb), + /* K11 */ be_nested_str_weak(widget_event), + /* K12 */ be_nested_str_weak(EVENT_DRAW_MAIN), }), be_str_weak(init), &be_const_str_solidified, - ( &(const binstruction[31]) { /* code */ + ( &(const binstruction[35]) { /* code */ 0x60080003, // 0000 GETGBL R2 G3 0x5C0C0000, // 0001 MOVE R3 R0 0x7C080200, // 0002 CALL R2 1 @@ -709,23 +710,27 @@ be_local_closure(lv_signal_arcs_init, /* name */ 0x58100002, // 000B LDCONST R4 K2 0x58140002, // 000C LDCONST R5 K2 0x7C080600, // 000D CALL R2 3 - 0x540A0063, // 000E LDINT R2 100 - 0x90020802, // 000F SETMBR R0 K4 R2 - 0xB80A0C00, // 0010 GETNGBL R2 K6 - 0x8C080505, // 0011 GETMET R2 R2 K5 - 0x7C080200, // 0012 CALL R2 1 + 0x8C080104, // 000E GETMET R2 R0 K4 + 0x58100002, // 000F LDCONST R4 K2 + 0x58140002, // 0010 LDCONST R5 K2 + 0x7C080600, // 0011 CALL R2 3 + 0x540A0063, // 0012 LDINT R2 100 0x90020A02, // 0013 SETMBR R0 K5 R2 - 0xB80A0C00, // 0014 GETNGBL R2 K6 - 0x8C080508, // 0015 GETMET R2 R2 K8 + 0xB80A0E00, // 0014 GETNGBL R2 K7 + 0x8C080506, // 0015 GETMET R2 R2 K6 0x7C080200, // 0016 CALL R2 1 - 0x90020E02, // 0017 SETMBR R0 K7 R2 - 0x8C080109, // 0018 GETMET R2 R0 K9 - 0x8810010A, // 0019 GETMBR R4 R0 K10 - 0xB8160C00, // 001A GETNGBL R5 K6 - 0x88140B0B, // 001B GETMBR R5 R5 K11 - 0x58180002, // 001C LDCONST R6 K2 - 0x7C080800, // 001D CALL R2 4 - 0x80000000, // 001E RET 0 + 0x90020C02, // 0017 SETMBR R0 K6 R2 + 0xB80A0E00, // 0018 GETNGBL R2 K7 + 0x8C080509, // 0019 GETMET R2 R2 K9 + 0x7C080200, // 001A CALL R2 1 + 0x90021002, // 001B SETMBR R0 K8 R2 + 0x8C08010A, // 001C GETMET R2 R0 K10 + 0x8810010B, // 001D GETMBR R4 R0 K11 + 0xB8160E00, // 001E GETNGBL R5 K7 + 0x88140B0C, // 001F GETMBR R5 R5 K12 + 0x58180002, // 0020 LDCONST R6 K2 + 0x7C080800, // 0021 CALL R2 4 + 0x80000000, // 0022 RET 0 }) ) ); diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_rule_matcher.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_rule_matcher.h index 81f51d586..da02fd924 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_rule_matcher.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_rule_matcher.h @@ -44,7 +44,7 @@ be_local_closure(Rule_Matcher_Key_tostring, /* name */ ********************************************************************/ be_local_closure(Rule_Matcher_Key_find_key_i, /* name */ be_nested_proto( - 10, /* nstack */ + 11, /* nstack */ 2, /* argc */ 4, /* varg */ 0, /* has upvals */ @@ -61,7 +61,7 @@ be_local_closure(Rule_Matcher_Key_find_key_i, /* name */ }), &be_const_str_find_key_i, &be_const_str_solidified, - ( &(const binstruction[29]) { /* code */ + ( &(const binstruction[31]) { /* code */ 0x58080000, // 0000 LDCONST R2 K0 0xA40E0200, // 0001 IMPORT R3 K1 0x8C100702, // 0002 GETMET R4 R3 K2 @@ -71,26 +71,28 @@ be_local_closure(Rule_Matcher_Key_find_key_i, /* name */ 0x5C180000, // 0006 MOVE R6 R0 0x601C0013, // 0007 GETGBL R7 G19 0x7C140400, // 0008 CALL R5 2 - 0x78160011, // 0009 JMPF R5 #001C + 0x78160013, // 0009 JMPF R5 #001E 0x60140010, // 000A GETGBL R5 G16 0x8C180103, // 000B GETMET R6 R0 K3 0x7C180200, // 000C CALL R6 1 0x7C140200, // 000D CALL R5 1 - 0xA8020009, // 000E EXBLK 0 #0019 + 0xA802000B, // 000E EXBLK 0 #001B 0x5C180A00, // 000F MOVE R6 R5 0x7C180000, // 0010 CALL R6 0 0x8C1C0702, // 0011 GETMET R7 R3 K2 - 0x5C240C00, // 0012 MOVE R9 R6 - 0x7C1C0400, // 0013 CALL R7 2 - 0x1C1C0E04, // 0014 EQ R7 R7 R4 - 0x781E0001, // 0015 JMPF R7 #0018 - 0xA8040001, // 0016 EXBLK 1 1 - 0x80040C00, // 0017 RET 1 R6 - 0x7001FFF5, // 0018 JMP #000F - 0x58140004, // 0019 LDCONST R5 K4 - 0xAC140200, // 001A CATCH R5 1 0 - 0xB0080000, // 001B RAISE 2 R0 R0 - 0x80000000, // 001C RET 0 + 0x60240008, // 0012 GETGBL R9 G8 + 0x5C280C00, // 0013 MOVE R10 R6 + 0x7C240200, // 0014 CALL R9 1 + 0x7C1C0400, // 0015 CALL R7 2 + 0x1C1C0E04, // 0016 EQ R7 R7 R4 + 0x781E0001, // 0017 JMPF R7 #001A + 0xA8040001, // 0018 EXBLK 1 1 + 0x80040C00, // 0019 RET 1 R6 + 0x7001FFF3, // 001A JMP #000F + 0x58140004, // 001B LDCONST R5 K4 + 0xAC140200, // 001C CATCH R5 1 0 + 0xB0080000, // 001D RAISE 2 R0 R0 + 0x80000000, // 001E RET 0 }) ) ); diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h index 471319508..57f85eceb 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h @@ -7,170 +7,11 @@ extern const bclass be_class_Tasmota; /******************************************************************** -** Solidified function: try_rule +** Solidified function: cmd ********************************************************************/ -be_local_closure(Tasmota_try_rule, /* name */ +be_local_closure(Tasmota_cmd, /* name */ be_nested_proto( - 9, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str(match), - /* K1 */ be_nested_str(trigger), - }), - &be_const_str_try_rule, - &be_const_str_solidified, - ( &(const binstruction[18]) { /* code */ - 0x8C100500, // 0000 GETMET R4 R2 K0 - 0x5C180200, // 0001 MOVE R6 R1 - 0x7C100400, // 0002 CALL R4 2 - 0x4C140000, // 0003 LDNIL R5 - 0x20140805, // 0004 NE R5 R4 R5 - 0x78160009, // 0005 JMPF R5 #0010 - 0x4C140000, // 0006 LDNIL R5 - 0x20140605, // 0007 NE R5 R3 R5 - 0x78160004, // 0008 JMPF R5 #000E - 0x5C140600, // 0009 MOVE R5 R3 - 0x5C180800, // 000A MOVE R6 R4 - 0x881C0501, // 000B GETMBR R7 R2 K1 - 0x5C200200, // 000C MOVE R8 R1 - 0x7C140600, // 000D CALL R5 3 - 0x50140200, // 000E LDBOOL R5 1 0 - 0x80040A00, // 000F RET 1 R5 - 0x50140000, // 0010 LDBOOL R5 0 0 - 0x80040A00, // 0011 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: gen_cb -********************************************************************/ -be_local_closure(Tasmota_gen_cb, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str(cb), - /* K1 */ be_nested_str(gen_cb), - }), - &be_const_str_gen_cb, - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x8C0C0501, // 0001 GETMET R3 R2 K1 - 0x5C140200, // 0002 MOVE R5 R1 - 0x7C0C0400, // 0003 CALL R3 2 - 0x80040600, // 0004 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: fast_loop -********************************************************************/ -be_local_closure(Tasmota_fast_loop, /* name */ - be_nested_proto( - 5, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(_fl), - /* K1 */ be_const_int(0), - /* K2 */ be_const_int(1), - }), - &be_const_str_fast_loop, - &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x5C080200, // 0001 MOVE R2 R1 - 0x740A0000, // 0002 JMPT R2 #0004 - 0x80000400, // 0003 RET 0 - 0x58080001, // 0004 LDCONST R2 K1 - 0x600C000C, // 0005 GETGBL R3 G12 - 0x5C100200, // 0006 MOVE R4 R1 - 0x7C0C0200, // 0007 CALL R3 1 - 0x140C0403, // 0008 LT R3 R2 R3 - 0x780E0003, // 0009 JMPF R3 #000E - 0x940C0202, // 000A GETIDX R3 R1 R2 - 0x7C0C0000, // 000B CALL R3 0 - 0x00080502, // 000C ADD R2 R2 K2 - 0x7001FFF6, // 000D JMP #0005 - 0x80000000, // 000E RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: remove_fast_loop -********************************************************************/ -be_local_closure(Tasmota_remove_fast_loop, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(_fl), - /* K1 */ be_nested_str(find), - /* K2 */ be_nested_str(remove), - }), - &be_const_str_remove_fast_loop, - &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x740A0000, // 0001 JMPT R2 #0003 - 0x80000400, // 0002 RET 0 - 0x88080100, // 0003 GETMBR R2 R0 K0 - 0x8C080501, // 0004 GETMET R2 R2 K1 - 0x5C100200, // 0005 MOVE R4 R1 - 0x7C080400, // 0006 CALL R2 2 - 0x4C0C0000, // 0007 LDNIL R3 - 0x200C0403, // 0008 NE R3 R2 R3 - 0x780E0003, // 0009 JMPF R3 #000E - 0x880C0100, // 000A GETMBR R3 R0 K0 - 0x8C0C0702, // 000B GETMET R3 R3 K2 - 0x5C140400, // 000C MOVE R5 R2 - 0x7C0C0400, // 000D CALL R3 2 - 0x80000000, // 000E RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: find_key_i -********************************************************************/ -be_local_closure(Tasmota_find_key_i, /* name */ - be_nested_proto( - 10, /* nstack */ + 8, /* nstack */ 3, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -178,46 +19,45 @@ be_local_closure(Tasmota_find_key_i, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str(string), - /* K1 */ be_nested_str(toupper), - /* K2 */ be_nested_str(keys), - /* K3 */ be_nested_str(_X3F), - /* K4 */ be_nested_str(stop_iteration), + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str(cmd_res), + /* K1 */ be_nested_str(tasmota), + /* K2 */ be_nested_str(global), + /* K3 */ be_nested_str(maxlog_level), + /* K4 */ be_const_int(2), + /* K5 */ be_const_int(1), + /* K6 */ be_nested_str(_cmd), }), - &be_const_str_find_key_i, + &be_const_str_cmd, &be_const_str_solidified, - ( &(const binstruction[30]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0x8C100701, // 0001 GETMET R4 R3 K1 - 0x5C180400, // 0002 MOVE R6 R2 - 0x7C100400, // 0003 CALL R4 2 - 0x6014000F, // 0004 GETGBL R5 G15 - 0x5C180200, // 0005 MOVE R6 R1 - 0x601C0013, // 0006 GETGBL R7 G19 - 0x7C140400, // 0007 CALL R5 2 - 0x78160013, // 0008 JMPF R5 #001D - 0x60140010, // 0009 GETGBL R5 G16 - 0x8C180302, // 000A GETMET R6 R1 K2 - 0x7C180200, // 000B CALL R6 1 - 0x7C140200, // 000C CALL R5 1 - 0xA802000B, // 000D EXBLK 0 #001A - 0x5C180A00, // 000E MOVE R6 R5 - 0x7C180000, // 000F CALL R6 0 - 0x8C1C0701, // 0010 GETMET R7 R3 K1 - 0x5C240C00, // 0011 MOVE R9 R6 - 0x7C1C0400, // 0012 CALL R7 2 - 0x1C1C0E04, // 0013 EQ R7 R7 R4 - 0x741E0001, // 0014 JMPT R7 #0017 - 0x1C1C0503, // 0015 EQ R7 R2 K3 - 0x781E0001, // 0016 JMPF R7 #0019 - 0xA8040001, // 0017 EXBLK 1 1 - 0x80040C00, // 0018 RET 1 R6 - 0x7001FFF3, // 0019 JMP #000E - 0x58140004, // 001A LDCONST R5 K4 - 0xAC140200, // 001B CATCH R5 1 0 - 0xB0080000, // 001C RAISE 2 R0 R0 - 0x80000000, // 001D RET 0 + ( &(const binstruction[27]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x50100200, // 0001 LDBOOL R4 1 0 + 0x90020004, // 0002 SETMBR R0 K0 R4 + 0xB8120200, // 0003 GETNGBL R4 K1 + 0x88100902, // 0004 GETMBR R4 R4 K2 + 0x88100903, // 0005 GETMBR R4 R4 K3 + 0x780A0004, // 0006 JMPF R2 #000C + 0x28140904, // 0007 GE R5 R4 K4 + 0x78160002, // 0008 JMPF R5 #000C + 0xB8160200, // 0009 GETNGBL R5 K1 + 0x88140B02, // 000A GETMBR R5 R5 K2 + 0x90160705, // 000B SETMBR R5 K3 K5 + 0x8C140106, // 000C GETMET R5 R0 K6 + 0x5C1C0200, // 000D MOVE R7 R1 + 0x7C140400, // 000E CALL R5 2 + 0x4C140000, // 000F LDNIL R5 + 0x88180100, // 0010 GETMBR R6 R0 K0 + 0x501C0200, // 0011 LDBOOL R7 1 0 + 0x20180C07, // 0012 NE R6 R6 R7 + 0x781A0000, // 0013 JMPF R6 #0015 + 0x88140100, // 0014 GETMBR R5 R0 K0 + 0x90020003, // 0015 SETMBR R0 K0 R3 + 0x780A0002, // 0016 JMPF R2 #001A + 0xB81A0200, // 0017 GETNGBL R6 K1 + 0x88180D02, // 0018 GETMBR R6 R6 K2 + 0x901A0604, // 0019 SETMBR R6 K3 R4 + 0x80040A00, // 001A RET 1 R5 }) ) ); @@ -270,67 +110,40 @@ be_local_closure(Tasmota_check_not_method, /* name */ /******************************************************************** -** Solidified function: run_cron +** Solidified function: remove_driver ********************************************************************/ -be_local_closure(Tasmota_run_cron, /* name */ +be_local_closure(Tasmota_remove_driver, /* name */ be_nested_proto( - 9, /* nstack */ - 1, /* argc */ + 6, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[10]) { /* constants */ - /* K0 */ be_nested_str(_crons), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str(ccronexpr), - /* K3 */ be_nested_str(now), - /* K4 */ be_nested_str(size), - /* K5 */ be_nested_str(trig), - /* K6 */ be_nested_str(next), - /* K7 */ be_nested_str(time_reached), - /* K8 */ be_nested_str(f), - /* K9 */ be_const_int(1), + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str(_drivers), + /* K1 */ be_nested_str(find), + /* K2 */ be_nested_str(pop), }), - &be_const_str_run_cron, + &be_const_str_remove_driver, &be_const_str_solidified, - ( &(const binstruction[34]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x7806001E, // 0001 JMPF R1 #0021 - 0x58040001, // 0002 LDCONST R1 K1 - 0xB80A0400, // 0003 GETNGBL R2 K2 - 0x8C080503, // 0004 GETMET R2 R2 K3 - 0x7C080200, // 0005 CALL R2 1 - 0x880C0100, // 0006 GETMBR R3 R0 K0 - 0x8C0C0704, // 0007 GETMET R3 R3 K4 - 0x7C0C0200, // 0008 CALL R3 1 - 0x140C0203, // 0009 LT R3 R1 R3 - 0x780E0015, // 000A JMPF R3 #0021 - 0x880C0100, // 000B GETMBR R3 R0 K0 - 0x940C0601, // 000C GETIDX R3 R3 R1 - 0x88100705, // 000D GETMBR R4 R3 K5 - 0x1C100901, // 000E EQ R4 R4 K1 - 0x78120003, // 000F JMPF R4 #0014 - 0x8C100706, // 0010 GETMET R4 R3 K6 - 0x7C100200, // 0011 CALL R4 1 - 0x900E0A04, // 0012 SETMBR R3 K5 R4 - 0x7002000A, // 0013 JMP #001F - 0x8C100707, // 0014 GETMET R4 R3 K7 - 0x7C100200, // 0015 CALL R4 1 - 0x78120007, // 0016 JMPF R4 #001F - 0x88100708, // 0017 GETMBR R4 R3 K8 - 0x8C140706, // 0018 GETMET R5 R3 K6 - 0x7C140200, // 0019 CALL R5 1 - 0x900E0A05, // 001A SETMBR R3 K5 R5 - 0x5C180800, // 001B MOVE R6 R4 - 0x5C1C0400, // 001C MOVE R7 R2 - 0x5C200A00, // 001D MOVE R8 R5 - 0x7C180400, // 001E CALL R6 2 - 0x00040309, // 001F ADD R1 R1 K9 - 0x7001FFE4, // 0020 JMP #0006 - 0x80000000, // 0021 RET 0 + ( &(const binstruction[14]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x780A000A, // 0001 JMPF R2 #000D + 0x88080100, // 0002 GETMBR R2 R0 K0 + 0x8C080501, // 0003 GETMET R2 R2 K1 + 0x5C100200, // 0004 MOVE R4 R1 + 0x7C080400, // 0005 CALL R2 2 + 0x4C0C0000, // 0006 LDNIL R3 + 0x200C0403, // 0007 NE R3 R2 R3 + 0x780E0003, // 0008 JMPF R3 #000D + 0x880C0100, // 0009 GETMBR R3 R0 K0 + 0x8C0C0702, // 000A GETMET R3 R3 K2 + 0x5C140400, // 000B MOVE R5 R2 + 0x7C0C0400, // 000C CALL R3 2 + 0x80000000, // 000D RET 0 }) ) ); @@ -494,95 +307,6 @@ be_local_closure(Tasmota_event, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: urlfetch -********************************************************************/ -be_local_closure(Tasmota_urlfetch, /* name */ - be_nested_proto( - 10, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[17]) { /* constants */ - /* K0 */ be_nested_str(string), - /* K1 */ be_nested_str(split), - /* K2 */ be_nested_str(_X2F), - /* K3 */ be_nested_str(pop), - /* K4 */ be_const_int(0), - /* K5 */ be_nested_str(index_X2Ehtml), - /* K6 */ be_nested_str(webclient), - /* K7 */ be_nested_str(set_follow_redirects), - /* K8 */ be_nested_str(begin), - /* K9 */ be_nested_str(GET), - /* K10 */ be_nested_str(status_X3A_X20), - /* K11 */ be_nested_str(connection_error), - /* K12 */ be_nested_str(write_file), - /* K13 */ be_nested_str(close), - /* K14 */ be_nested_str(log), - /* K15 */ be_nested_str(BRY_X3A_X20Fetched_X20), - /* K16 */ be_const_int(3), - }), - &be_const_str_urlfetch, - &be_const_str_solidified, - ( &(const binstruction[48]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x1C0C0403, // 0001 EQ R3 R2 R3 - 0x780E000D, // 0002 JMPF R3 #0011 - 0xA40E0000, // 0003 IMPORT R3 K0 - 0x8C100701, // 0004 GETMET R4 R3 K1 - 0x5C180200, // 0005 MOVE R6 R1 - 0x581C0002, // 0006 LDCONST R7 K2 - 0x7C100600, // 0007 CALL R4 3 - 0x8C100903, // 0008 GETMET R4 R4 K3 - 0x7C100200, // 0009 CALL R4 1 - 0x5C080800, // 000A MOVE R2 R4 - 0x6010000C, // 000B GETGBL R4 G12 - 0x5C140400, // 000C MOVE R5 R2 - 0x7C100200, // 000D CALL R4 1 - 0x1C100904, // 000E EQ R4 R4 K4 - 0x78120000, // 000F JMPF R4 #0011 - 0x58080005, // 0010 LDCONST R2 K5 - 0xB80E0C00, // 0011 GETNGBL R3 K6 - 0x7C0C0000, // 0012 CALL R3 0 - 0x8C100707, // 0013 GETMET R4 R3 K7 - 0x50180200, // 0014 LDBOOL R6 1 0 - 0x7C100400, // 0015 CALL R4 2 - 0x8C100708, // 0016 GETMET R4 R3 K8 - 0x5C180200, // 0017 MOVE R6 R1 - 0x7C100400, // 0018 CALL R4 2 - 0x8C100709, // 0019 GETMET R4 R3 K9 - 0x7C100200, // 001A CALL R4 1 - 0x541600C7, // 001B LDINT R5 200 - 0x20140805, // 001C NE R5 R4 R5 - 0x78160004, // 001D JMPF R5 #0023 - 0x60140008, // 001E GETGBL R5 G8 - 0x5C180800, // 001F MOVE R6 R4 - 0x7C140200, // 0020 CALL R5 1 - 0x00161405, // 0021 ADD R5 K10 R5 - 0xB0061605, // 0022 RAISE 1 K11 R5 - 0x8C14070C, // 0023 GETMET R5 R3 K12 - 0x5C1C0400, // 0024 MOVE R7 R2 - 0x7C140400, // 0025 CALL R5 2 - 0x8C18070D, // 0026 GETMET R6 R3 K13 - 0x7C180200, // 0027 CALL R6 1 - 0x8C18010E, // 0028 GETMET R6 R0 K14 - 0x60200008, // 0029 GETGBL R8 G8 - 0x5C240A00, // 002A MOVE R9 R5 - 0x7C200200, // 002B CALL R8 1 - 0x00221E08, // 002C ADD R8 K15 R8 - 0x58240010, // 002D LDCONST R9 K16 - 0x7C180600, // 002E CALL R6 3 - 0x80040800, // 002F RET 1 R4 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: exec_cmd ********************************************************************/ @@ -639,102 +363,6 @@ be_local_closure(Tasmota_exec_cmd, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: remove_cron -********************************************************************/ -be_local_closure(Tasmota_remove_cron, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str(_crons), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str(size), - /* K3 */ be_nested_str(id), - /* K4 */ be_nested_str(remove), - /* K5 */ be_const_int(1), - }), - &be_const_str_remove_cron, - &be_const_str_solidified, - ( &(const binstruction[18]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A000E, // 0001 JMPF R2 #0011 - 0x580C0001, // 0002 LDCONST R3 K1 - 0x8C100502, // 0003 GETMET R4 R2 K2 - 0x7C100200, // 0004 CALL R4 1 - 0x14100604, // 0005 LT R4 R3 R4 - 0x78120009, // 0006 JMPF R4 #0011 - 0x94100403, // 0007 GETIDX R4 R2 R3 - 0x88100903, // 0008 GETMBR R4 R4 K3 - 0x1C100801, // 0009 EQ R4 R4 R1 - 0x78120003, // 000A JMPF R4 #000F - 0x8C100504, // 000B GETMET R4 R2 K4 - 0x5C180600, // 000C MOVE R6 R3 - 0x7C100400, // 000D CALL R4 2 - 0x70020000, // 000E JMP #0010 - 0x000C0705, // 000F ADD R3 R3 K5 - 0x7001FFF1, // 0010 JMP #0003 - 0x80000000, // 0011 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: find_list_i -********************************************************************/ -be_local_closure(Tasmota_find_list_i, /* name */ - be_nested_proto( - 9, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str(string), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str(toupper), - /* K3 */ be_const_int(1), - }), - &be_const_str_find_list_i, - &be_const_str_solidified, - ( &(const binstruction[20]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0x58100001, // 0001 LDCONST R4 K1 - 0x8C140702, // 0002 GETMET R5 R3 K2 - 0x5C1C0400, // 0003 MOVE R7 R2 - 0x7C140400, // 0004 CALL R5 2 - 0x6018000C, // 0005 GETGBL R6 G12 - 0x5C1C0200, // 0006 MOVE R7 R1 - 0x7C180200, // 0007 CALL R6 1 - 0x14180806, // 0008 LT R6 R4 R6 - 0x781A0007, // 0009 JMPF R6 #0012 - 0x8C180702, // 000A GETMET R6 R3 K2 - 0x94200204, // 000B GETIDX R8 R1 R4 - 0x7C180400, // 000C CALL R6 2 - 0x1C180C05, // 000D EQ R6 R6 R5 - 0x781A0000, // 000E JMPF R6 #0010 - 0x80040800, // 000F RET 1 R4 - 0x00100903, // 0010 ADD R4 R4 K3 - 0x7001FFF2, // 0011 JMP #0005 - 0x4C180000, // 0012 LDNIL R6 - 0x80040C00, // 0013 RET 1 R6 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: set_light ********************************************************************/ @@ -781,231 +409,117 @@ be_local_closure(Tasmota_set_light, /* name */ /******************************************************************** -** Solidified function: remove_timer +** Solidified function: run_cron ********************************************************************/ -be_local_closure(Tasmota_remove_timer, /* name */ +be_local_closure(Tasmota_run_cron, /* name */ be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str(_timers), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str(size), - /* K3 */ be_nested_str(id), - /* K4 */ be_nested_str(remove), - /* K5 */ be_const_int(1), - }), - &be_const_str_remove_timer, - &be_const_str_solidified, - ( &(const binstruction[18]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A000E, // 0001 JMPF R2 #0011 - 0x580C0001, // 0002 LDCONST R3 K1 - 0x8C100502, // 0003 GETMET R4 R2 K2 - 0x7C100200, // 0004 CALL R4 1 - 0x14100604, // 0005 LT R4 R3 R4 - 0x78120009, // 0006 JMPF R4 #0011 - 0x94100403, // 0007 GETIDX R4 R2 R3 - 0x88100903, // 0008 GETMBR R4 R4 K3 - 0x1C100801, // 0009 EQ R4 R4 R1 - 0x78120003, // 000A JMPF R4 #000F - 0x8C100504, // 000B GETMET R4 R2 K4 - 0x5C180600, // 000C MOVE R6 R3 - 0x7C100400, // 000D CALL R4 2 - 0x70020000, // 000E JMP #0010 - 0x000C0705, // 000F ADD R3 R3 K5 - 0x7001FFF1, // 0010 JMP #0003 - 0x80000000, // 0011 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: remove_cmd -********************************************************************/ -be_local_closure(Tasmota_remove_cmd, /* name */ - be_nested_proto( - 5, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str(_ccmd), - /* K1 */ be_nested_str(remove), - }), - &be_const_str_remove_cmd, - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A0003, // 0001 JMPF R2 #0006 - 0x88080100, // 0002 GETMBR R2 R0 K0 - 0x8C080501, // 0003 GETMET R2 R2 K1 - 0x5C100200, // 0004 MOVE R4 R1 - 0x7C080400, // 0005 CALL R2 2 - 0x80000000, // 0006 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: remove_driver -********************************************************************/ -be_local_closure(Tasmota_remove_driver, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(_drivers), - /* K1 */ be_nested_str(find), - /* K2 */ be_nested_str(pop), - }), - &be_const_str_remove_driver, - &be_const_str_solidified, - ( &(const binstruction[14]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A000A, // 0001 JMPF R2 #000D - 0x88080100, // 0002 GETMBR R2 R0 K0 - 0x8C080501, // 0003 GETMET R2 R2 K1 - 0x5C100200, // 0004 MOVE R4 R1 - 0x7C080400, // 0005 CALL R2 2 - 0x4C0C0000, // 0006 LDNIL R3 - 0x200C0403, // 0007 NE R3 R2 R3 - 0x780E0003, // 0008 JMPF R3 #000D - 0x880C0100, // 0009 GETMBR R3 R0 K0 - 0x8C0C0702, // 000A GETMET R3 R3 K2 - 0x5C140400, // 000B MOVE R5 R2 - 0x7C0C0400, // 000C CALL R3 2 - 0x80000000, // 000D RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Tasmota_init, /* name */ - be_nested_proto( - 7, /* nstack */ + 9, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 1]) { - be_nested_proto( - 10, /* nstack */ - 4, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ - be_local_const_upval(1, 0), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str(urlfetch_cmd), - }), - &be_const_str__anonymous_, - &be_const_str_solidified, - ( &(const binstruction[ 8]) { /* code */ - 0x68100000, // 0000 GETUPV R4 U0 - 0x8C100900, // 0001 GETMET R4 R4 K0 - 0x5C180000, // 0002 MOVE R6 R0 - 0x5C1C0200, // 0003 MOVE R7 R1 - 0x5C200400, // 0004 MOVE R8 R2 - 0x5C240600, // 0005 MOVE R9 R3 - 0x7C100A00, // 0006 CALL R4 5 - 0x80000000, // 0007 RET 0 - }) - ), - }), + 0, /* has sup protos */ + NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[17]) { /* constants */ - /* K0 */ be_nested_str(global), - /* K1 */ be_nested_str(ctypes_bytes_dyn), - /* K2 */ be_nested_str(_global_addr), - /* K3 */ be_nested_str(_global_def), - /* K4 */ be_nested_str(introspect), - /* K5 */ be_nested_str(_settings_ptr), - /* K6 */ be_nested_str(get), - /* K7 */ be_const_int(0), - /* K8 */ be_nested_str(settings), - /* K9 */ be_nested_str(toptr), - /* K10 */ be_nested_str(_settings_def), - /* K11 */ be_nested_str(wd), - /* K12 */ be_nested_str(), - /* K13 */ be_nested_str(_debug_present), - /* K14 */ be_nested_str(debug), - /* K15 */ be_nested_str(add_cmd), - /* K16 */ be_nested_str(UrlFetch), + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str(_crons), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(ccronexpr), + /* K3 */ be_nested_str(now), + /* K4 */ be_nested_str(size), + /* K5 */ be_nested_str(trig), + /* K6 */ be_nested_str(next), + /* K7 */ be_nested_str(time_reached), + /* K8 */ be_nested_str(f), + /* K9 */ be_const_int(1), }), - &be_const_str_init, + &be_const_str_run_cron, &be_const_str_solidified, - ( &(const binstruction[41]) { /* code */ - 0xB8060200, // 0000 GETNGBL R1 K1 - 0x88080102, // 0001 GETMBR R2 R0 K2 - 0x880C0103, // 0002 GETMBR R3 R0 K3 - 0x7C040400, // 0003 CALL R1 2 - 0x90020001, // 0004 SETMBR R0 K0 R1 - 0xA4060800, // 0005 IMPORT R1 K4 - 0x60080015, // 0006 GETGBL R2 G21 - 0x880C0105, // 0007 GETMBR R3 R0 K5 - 0x54120003, // 0008 LDINT R4 4 - 0x7C080400, // 0009 CALL R2 2 - 0x8C080506, // 000A GETMET R2 R2 K6 - 0x58100007, // 000B LDCONST R4 K7 - 0x54160003, // 000C LDINT R5 4 - 0x7C080600, // 000D CALL R2 3 - 0x780A0006, // 000E JMPF R2 #0016 - 0xB80E0200, // 000F GETNGBL R3 K1 - 0x8C100309, // 0010 GETMET R4 R1 K9 - 0x5C180400, // 0011 MOVE R6 R2 - 0x7C100400, // 0012 CALL R4 2 - 0x8814010A, // 0013 GETMBR R5 R0 K10 - 0x7C0C0400, // 0014 CALL R3 2 - 0x90021003, // 0015 SETMBR R0 K8 R3 - 0x9002170C, // 0016 SETMBR R0 K11 K12 - 0x500C0000, // 0017 LDBOOL R3 0 0 - 0x90021A03, // 0018 SETMBR R0 K13 R3 - 0xA8020004, // 0019 EXBLK 0 #001F - 0xA40E1C00, // 001A IMPORT R3 K14 - 0x50100200, // 001B LDBOOL R4 1 0 - 0x90021A04, // 001C SETMBR R0 K13 R4 - 0xA8040001, // 001D EXBLK 1 1 - 0x70020003, // 001E JMP #0023 - 0xAC0C0000, // 001F CATCH R3 0 0 - 0x70020000, // 0020 JMP #0022 - 0x70020000, // 0021 JMP #0023 - 0xB0080000, // 0022 RAISE 2 R0 R0 - 0x8C0C010F, // 0023 GETMET R3 R0 K15 - 0x58140010, // 0024 LDCONST R5 K16 - 0x84180000, // 0025 CLOSURE R6 P0 - 0x7C0C0600, // 0026 CALL R3 3 - 0xA0000000, // 0027 CLOSE R0 - 0x80000000, // 0028 RET 0 + ( &(const binstruction[34]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x7806001E, // 0001 JMPF R1 #0021 + 0x58040001, // 0002 LDCONST R1 K1 + 0xB80A0400, // 0003 GETNGBL R2 K2 + 0x8C080503, // 0004 GETMET R2 R2 K3 + 0x7C080200, // 0005 CALL R2 1 + 0x880C0100, // 0006 GETMBR R3 R0 K0 + 0x8C0C0704, // 0007 GETMET R3 R3 K4 + 0x7C0C0200, // 0008 CALL R3 1 + 0x140C0203, // 0009 LT R3 R1 R3 + 0x780E0015, // 000A JMPF R3 #0021 + 0x880C0100, // 000B GETMBR R3 R0 K0 + 0x940C0601, // 000C GETIDX R3 R3 R1 + 0x88100705, // 000D GETMBR R4 R3 K5 + 0x1C100901, // 000E EQ R4 R4 K1 + 0x78120003, // 000F JMPF R4 #0014 + 0x8C100706, // 0010 GETMET R4 R3 K6 + 0x7C100200, // 0011 CALL R4 1 + 0x900E0A04, // 0012 SETMBR R3 K5 R4 + 0x7002000A, // 0013 JMP #001F + 0x8C100707, // 0014 GETMET R4 R3 K7 + 0x7C100200, // 0015 CALL R4 1 + 0x78120007, // 0016 JMPF R4 #001F + 0x88100708, // 0017 GETMBR R4 R3 K8 + 0x8C140706, // 0018 GETMET R5 R3 K6 + 0x7C140200, // 0019 CALL R5 1 + 0x900E0A05, // 001A SETMBR R3 K5 R5 + 0x5C180800, // 001B MOVE R6 R4 + 0x5C1C0400, // 001C MOVE R7 R2 + 0x5C200A00, // 001D MOVE R8 R5 + 0x7C180400, // 001E CALL R6 2 + 0x00040309, // 001F ADD R1 R1 K9 + 0x7001FFE4, // 0020 JMP #0006 + 0x80000000, // 0021 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_timer +********************************************************************/ +be_local_closure(Tasmota_set_timer, /* name */ + be_nested_proto( + 10, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str(check_not_method), + /* K1 */ be_nested_str(_timers), + /* K2 */ be_nested_str(push), + /* K3 */ be_nested_str(Trigger), + /* K4 */ be_nested_str(millis), + }), + &be_const_str_set_timer, + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x8C100100, // 0000 GETMET R4 R0 K0 + 0x5C180400, // 0001 MOVE R6 R2 + 0x7C100400, // 0002 CALL R4 2 + 0x88100101, // 0003 GETMBR R4 R0 K1 + 0x4C140000, // 0004 LDNIL R5 + 0x1C100805, // 0005 EQ R4 R4 R5 + 0x78120002, // 0006 JMPF R4 #000A + 0x60100012, // 0007 GETGBL R4 G18 + 0x7C100000, // 0008 CALL R4 0 + 0x90020204, // 0009 SETMBR R0 K1 R4 + 0x88100101, // 000A GETMBR R4 R0 K1 + 0x8C100902, // 000B GETMET R4 R4 K2 + 0xB81A0600, // 000C GETNGBL R6 K3 + 0x8C1C0104, // 000D GETMET R7 R0 K4 + 0x5C240200, // 000E MOVE R9 R1 + 0x7C1C0400, // 000F CALL R7 2 + 0x5C200400, // 0010 MOVE R8 R2 + 0x5C240600, // 0011 MOVE R9 R3 + 0x7C180600, // 0012 CALL R6 3 + 0x7C100400, // 0013 CALL R4 2 + 0x80000000, // 0014 RET 0 }) ) ); @@ -1067,6 +581,849 @@ be_local_closure(Tasmota_add_driver, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: next_cron +********************************************************************/ +be_local_closure(Tasmota_next_cron, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str(_crons), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(size), + /* K3 */ be_nested_str(id), + /* K4 */ be_nested_str(trig), + /* K5 */ be_const_int(1), + }), + &be_const_str_next_cron, + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x780A000D, // 0001 JMPF R2 #0010 + 0x580C0001, // 0002 LDCONST R3 K1 + 0x8C100502, // 0003 GETMET R4 R2 K2 + 0x7C100200, // 0004 CALL R4 1 + 0x14100604, // 0005 LT R4 R3 R4 + 0x78120008, // 0006 JMPF R4 #0010 + 0x94100403, // 0007 GETIDX R4 R2 R3 + 0x88100903, // 0008 GETMBR R4 R4 K3 + 0x1C100801, // 0009 EQ R4 R4 R1 + 0x78120002, // 000A JMPF R4 #000E + 0x94100403, // 000B GETIDX R4 R2 R3 + 0x88100904, // 000C GETMBR R4 R4 K4 + 0x80040800, // 000D RET 1 R4 + 0x000C0705, // 000E ADD R3 R3 K5 + 0x7001FFF2, // 000F JMP #0003 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Tasmota_init, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 10, /* nstack */ + 4, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str(urlfetch_cmd), + }), + &be_const_str__anonymous_, + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x68100000, // 0000 GETUPV R4 U0 + 0x8C100900, // 0001 GETMET R4 R4 K0 + 0x5C180000, // 0002 MOVE R6 R0 + 0x5C1C0200, // 0003 MOVE R7 R1 + 0x5C200400, // 0004 MOVE R8 R2 + 0x5C240600, // 0005 MOVE R9 R3 + 0x7C100A00, // 0006 CALL R4 5 + 0x80000000, // 0007 RET 0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[18]) { /* constants */ + /* K0 */ be_nested_str(global), + /* K1 */ be_nested_str(ctypes_bytes_dyn), + /* K2 */ be_nested_str(_global_addr), + /* K3 */ be_nested_str(_global_def), + /* K4 */ be_nested_str(introspect), + /* K5 */ be_nested_str(_settings_ptr), + /* K6 */ be_nested_str(get), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str(settings), + /* K9 */ be_nested_str(toptr), + /* K10 */ be_nested_str(_settings_def), + /* K11 */ be_nested_str(wd), + /* K12 */ be_nested_str(), + /* K13 */ be_nested_str(_debug_present), + /* K14 */ be_nested_str(contains), + /* K15 */ be_nested_str(debug), + /* K16 */ be_nested_str(add_cmd), + /* K17 */ be_nested_str(UrlFetch), + }), + &be_const_str_init, + &be_const_str_solidified, + ( &(const binstruction[34]) { /* code */ + 0xB8060200, // 0000 GETNGBL R1 K1 + 0x88080102, // 0001 GETMBR R2 R0 K2 + 0x880C0103, // 0002 GETMBR R3 R0 K3 + 0x7C040400, // 0003 CALL R1 2 + 0x90020001, // 0004 SETMBR R0 K0 R1 + 0xA4060800, // 0005 IMPORT R1 K4 + 0x60080015, // 0006 GETGBL R2 G21 + 0x880C0105, // 0007 GETMBR R3 R0 K5 + 0x54120003, // 0008 LDINT R4 4 + 0x7C080400, // 0009 CALL R2 2 + 0x8C080506, // 000A GETMET R2 R2 K6 + 0x58100007, // 000B LDCONST R4 K7 + 0x54160003, // 000C LDINT R5 4 + 0x7C080600, // 000D CALL R2 3 + 0x780A0006, // 000E JMPF R2 #0016 + 0xB80E0200, // 000F GETNGBL R3 K1 + 0x8C100309, // 0010 GETMET R4 R1 K9 + 0x5C180400, // 0011 MOVE R6 R2 + 0x7C100400, // 0012 CALL R4 2 + 0x8814010A, // 0013 GETMBR R5 R0 K10 + 0x7C0C0400, // 0014 CALL R3 2 + 0x90021003, // 0015 SETMBR R0 K8 R3 + 0x9002170C, // 0016 SETMBR R0 K11 K12 + 0xB80E0000, // 0017 GETNGBL R3 K0 + 0x8C0C070E, // 0018 GETMET R3 R3 K14 + 0x5814000F, // 0019 LDCONST R5 K15 + 0x7C0C0400, // 001A CALL R3 2 + 0x90021A03, // 001B SETMBR R0 K13 R3 + 0x8C0C0110, // 001C GETMET R3 R0 K16 + 0x58140011, // 001D LDCONST R5 K17 + 0x84180000, // 001E CLOSURE R6 P0 + 0x7C0C0600, // 001F CALL R3 3 + 0xA0000000, // 0020 CLOSE R0 + 0x80000000, // 0021 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_rule +********************************************************************/ +be_local_closure(Tasmota_add_rule, /* name */ + be_nested_proto( + 10, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str(check_not_method), + /* K1 */ be_nested_str(_rules), + /* K2 */ be_nested_str(function), + /* K3 */ be_nested_str(push), + /* K4 */ be_nested_str(Trigger), + /* K5 */ be_nested_str(Rule_Matcher), + /* K6 */ be_nested_str(parse), + /* K7 */ be_nested_str(value_error), + /* K8 */ be_nested_str(the_X20second_X20argument_X20is_X20not_X20a_X20function), + }), + &be_const_str_add_rule, + &be_const_str_solidified, + ( &(const binstruction[29]) { /* code */ + 0x8C100100, // 0000 GETMET R4 R0 K0 + 0x5C180400, // 0001 MOVE R6 R2 + 0x7C100400, // 0002 CALL R4 2 + 0x88100101, // 0003 GETMBR R4 R0 K1 + 0x4C140000, // 0004 LDNIL R5 + 0x1C100805, // 0005 EQ R4 R4 R5 + 0x78120002, // 0006 JMPF R4 #000A + 0x60100012, // 0007 GETGBL R4 G18 + 0x7C100000, // 0008 CALL R4 0 + 0x90020204, // 0009 SETMBR R0 K1 R4 + 0x60100004, // 000A GETGBL R4 G4 + 0x5C140400, // 000B MOVE R5 R2 + 0x7C100200, // 000C CALL R4 1 + 0x1C100902, // 000D EQ R4 R4 K2 + 0x7812000B, // 000E JMPF R4 #001B + 0x88100101, // 000F GETMBR R4 R0 K1 + 0x8C100903, // 0010 GETMET R4 R4 K3 + 0xB81A0800, // 0011 GETNGBL R6 K4 + 0x881C0105, // 0012 GETMBR R7 R0 K5 + 0x8C1C0F06, // 0013 GETMET R7 R7 K6 + 0x5C240200, // 0014 MOVE R9 R1 + 0x7C1C0400, // 0015 CALL R7 2 + 0x5C200400, // 0016 MOVE R8 R2 + 0x5C240600, // 0017 MOVE R9 R3 + 0x7C180600, // 0018 CALL R6 3 + 0x7C100400, // 0019 CALL R4 2 + 0x70020000, // 001A JMP #001C + 0xB0060F08, // 001B RAISE 1 K7 K8 + 0x80000000, // 001C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: try_rule +********************************************************************/ +be_local_closure(Tasmota_try_rule, /* name */ + be_nested_proto( + 9, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str(match), + /* K1 */ be_nested_str(trigger), + }), + &be_const_str_try_rule, + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x8C100500, // 0000 GETMET R4 R2 K0 + 0x5C180200, // 0001 MOVE R6 R1 + 0x7C100400, // 0002 CALL R4 2 + 0x4C140000, // 0003 LDNIL R5 + 0x20140805, // 0004 NE R5 R4 R5 + 0x78160009, // 0005 JMPF R5 #0010 + 0x4C140000, // 0006 LDNIL R5 + 0x20140605, // 0007 NE R5 R3 R5 + 0x78160004, // 0008 JMPF R5 #000E + 0x5C140600, // 0009 MOVE R5 R3 + 0x5C180800, // 000A MOVE R6 R4 + 0x881C0501, // 000B GETMBR R7 R2 K1 + 0x5C200200, // 000C MOVE R8 R1 + 0x7C140600, // 000D CALL R5 3 + 0x50140200, // 000E LDBOOL R5 1 0 + 0x80040A00, // 000F RET 1 R5 + 0x50140000, // 0010 LDBOOL R5 0 0 + 0x80040A00, // 0011 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_op +********************************************************************/ +be_local_closure(Tasmota_find_op, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str(_find_op), + /* K1 */ be_const_int(0), + /* K2 */ be_const_int(1), + /* K3 */ be_const_int(2147483647), + }), + &be_const_str_find_op, + &be_const_str_solidified, + ( &(const binstruction[31]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5C100200, // 0001 MOVE R4 R1 + 0x7C080400, // 0002 CALL R2 2 + 0x280C0501, // 0003 GE R3 R2 K1 + 0x780E0011, // 0004 JMPF R3 #0017 + 0x540E7FFE, // 0005 LDINT R3 32767 + 0x2C0C0403, // 0006 AND R3 R2 R3 + 0x5412000F, // 0007 LDINT R4 16 + 0x3C100404, // 0008 SHR R4 R2 R4 + 0x60140012, // 0009 GETGBL R5 G18 + 0x7C140000, // 000A CALL R5 0 + 0x04180702, // 000B SUB R6 R3 K2 + 0x401A0206, // 000C CONNECT R6 K1 R6 + 0x94180206, // 000D GETIDX R6 R1 R6 + 0x40180A06, // 000E CONNECT R6 R5 R6 + 0x04180902, // 000F SUB R6 R4 K2 + 0x40180606, // 0010 CONNECT R6 R3 R6 + 0x94180206, // 0011 GETIDX R6 R1 R6 + 0x40180A06, // 0012 CONNECT R6 R5 R6 + 0x40180903, // 0013 CONNECT R6 R4 K3 + 0x94180206, // 0014 GETIDX R6 R1 R6 + 0x40180A06, // 0015 CONNECT R6 R5 R6 + 0x80040A00, // 0016 RET 1 R5 + 0x600C0012, // 0017 GETGBL R3 G18 + 0x7C0C0000, // 0018 CALL R3 0 + 0x40100601, // 0019 CONNECT R4 R3 R1 + 0x4C100000, // 001A LDNIL R4 + 0x40100604, // 001B CONNECT R4 R3 R4 + 0x4C100000, // 001C LDNIL R4 + 0x40100604, // 001D CONNECT R4 R3 R4 + 0x80040600, // 001E RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_cmd +********************************************************************/ +be_local_closure(Tasmota_remove_cmd, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str(_ccmd), + /* K1 */ be_nested_str(remove), + }), + &be_const_str_remove_cmd, + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x780A0003, // 0001 JMPF R2 #0006 + 0x88080100, // 0002 GETMBR R2 R0 K0 + 0x8C080501, // 0003 GETMET R2 R2 K1 + 0x5C100200, // 0004 MOVE R4 R1 + 0x7C080400, // 0005 CALL R2 2 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: gc +********************************************************************/ +be_local_closure(Tasmota_gc, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str(gc), + /* K1 */ be_nested_str(collect), + /* K2 */ be_nested_str(allocated), + }), + &be_const_str_gc, + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x7C080200, // 0002 CALL R2 1 + 0x8C080302, // 0003 GETMET R2 R1 K2 + 0x7C080200, // 0004 CALL R2 1 + 0x80040400, // 0005 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_list_i +********************************************************************/ +be_local_closure(Tasmota_find_list_i, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str(string), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(toupper), + /* K3 */ be_const_int(1), + }), + &be_const_str_find_list_i, + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0x58100001, // 0001 LDCONST R4 K1 + 0x8C140702, // 0002 GETMET R5 R3 K2 + 0x5C1C0400, // 0003 MOVE R7 R2 + 0x7C140400, // 0004 CALL R5 2 + 0x6018000C, // 0005 GETGBL R6 G12 + 0x5C1C0200, // 0006 MOVE R7 R1 + 0x7C180200, // 0007 CALL R6 1 + 0x14180806, // 0008 LT R6 R4 R6 + 0x781A0007, // 0009 JMPF R6 #0012 + 0x8C180702, // 000A GETMET R6 R3 K2 + 0x94200204, // 000B GETIDX R8 R1 R4 + 0x7C180400, // 000C CALL R6 2 + 0x1C180C05, // 000D EQ R6 R6 R5 + 0x781A0000, // 000E JMPF R6 #0010 + 0x80040800, // 000F RET 1 R4 + 0x00100903, // 0010 ADD R4 R4 K3 + 0x7001FFF2, // 0011 JMP #0005 + 0x4C180000, // 0012 LDNIL R6 + 0x80040C00, // 0013 RET 1 R6 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_fast_loop +********************************************************************/ +be_local_closure(Tasmota_remove_fast_loop, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str(_fl), + /* K1 */ be_nested_str(find), + /* K2 */ be_nested_str(remove), + }), + &be_const_str_remove_fast_loop, + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x740A0000, // 0001 JMPT R2 #0003 + 0x80000400, // 0002 RET 0 + 0x88080100, // 0003 GETMBR R2 R0 K0 + 0x8C080501, // 0004 GETMET R2 R2 K1 + 0x5C100200, // 0005 MOVE R4 R1 + 0x7C080400, // 0006 CALL R2 2 + 0x4C0C0000, // 0007 LDNIL R3 + 0x200C0403, // 0008 NE R3 R2 R3 + 0x780E0003, // 0009 JMPF R3 #000E + 0x880C0100, // 000A GETMBR R3 R0 K0 + 0x8C0C0702, // 000B GETMET R3 R3 K2 + 0x5C140400, // 000C MOVE R5 R2 + 0x7C0C0400, // 000D CALL R3 2 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: exec_rules +********************************************************************/ +be_local_closure(Tasmota_exec_rules, /* name */ + be_nested_proto( + 14, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str(cmd_res), + /* K1 */ be_nested_str(_rules), + /* K2 */ be_nested_str(json), + /* K3 */ be_nested_str(load), + /* K4 */ be_nested_str(log), + /* K5 */ be_nested_str(BRY_X3A_X20ERROR_X2C_X20bad_X20json_X3A_X20), + /* K6 */ be_const_int(3), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str(try_rule), + /* K9 */ be_nested_str(trig), + /* K10 */ be_nested_str(f), + /* K11 */ be_const_int(1), + }), + &be_const_str_exec_rules, + &be_const_str_solidified, + ( &(const binstruction[50]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x88100101, // 0001 GETMBR R4 R0 K1 + 0x74120002, // 0002 JMPT R4 #0006 + 0x4C100000, // 0003 LDNIL R4 + 0x20100604, // 0004 NE R4 R3 R4 + 0x78120029, // 0005 JMPF R4 #0030 + 0xA4120400, // 0006 IMPORT R4 K2 + 0x4C140000, // 0007 LDNIL R5 + 0x90020005, // 0008 SETMBR R0 K0 R5 + 0x50140000, // 0009 LDBOOL R5 0 0 + 0x8C180903, // 000A GETMET R6 R4 K3 + 0x5C200200, // 000B MOVE R8 R1 + 0x7C180400, // 000C CALL R6 2 + 0x4C1C0000, // 000D LDNIL R7 + 0x1C1C0C07, // 000E EQ R7 R6 R7 + 0x781E0004, // 000F JMPF R7 #0015 + 0x8C1C0104, // 0010 GETMET R7 R0 K4 + 0x00260A01, // 0011 ADD R9 K5 R1 + 0x58280006, // 0012 LDCONST R10 K6 + 0x7C1C0600, // 0013 CALL R7 3 + 0x5C180200, // 0014 MOVE R6 R1 + 0x780A0014, // 0015 JMPF R2 #002B + 0x881C0101, // 0016 GETMBR R7 R0 K1 + 0x781E0012, // 0017 JMPF R7 #002B + 0x581C0007, // 0018 LDCONST R7 K7 + 0x6020000C, // 0019 GETGBL R8 G12 + 0x88240101, // 001A GETMBR R9 R0 K1 + 0x7C200200, // 001B CALL R8 1 + 0x14200E08, // 001C LT R8 R7 R8 + 0x7822000C, // 001D JMPF R8 #002B + 0x88200101, // 001E GETMBR R8 R0 K1 + 0x94201007, // 001F GETIDX R8 R8 R7 + 0x8C240108, // 0020 GETMET R9 R0 K8 + 0x5C2C0C00, // 0021 MOVE R11 R6 + 0x88301109, // 0022 GETMBR R12 R8 K9 + 0x8834110A, // 0023 GETMBR R13 R8 K10 + 0x7C240800, // 0024 CALL R9 4 + 0x74260001, // 0025 JMPT R9 #0028 + 0x74160000, // 0026 JMPT R5 #0028 + 0x50140001, // 0027 LDBOOL R5 0 1 + 0x50140200, // 0028 LDBOOL R5 1 0 + 0x001C0F0B, // 0029 ADD R7 R7 K11 + 0x7001FFED, // 002A JMP #0019 + 0x4C1C0000, // 002B LDNIL R7 + 0x201C0607, // 002C NE R7 R3 R7 + 0x781E0000, // 002D JMPF R7 #002F + 0x90020006, // 002E SETMBR R0 K0 R6 + 0x80040A00, // 002F RET 1 R5 + 0x50100000, // 0030 LDBOOL R4 0 0 + 0x80040800, // 0031 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: run_deferred +********************************************************************/ +be_local_closure(Tasmota_run_deferred, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str(_timers), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(size), + /* K3 */ be_nested_str(time_reached), + /* K4 */ be_nested_str(trig), + /* K5 */ be_nested_str(f), + /* K6 */ be_nested_str(remove), + /* K7 */ be_const_int(1), + }), + &be_const_str_run_deferred, + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x78060015, // 0001 JMPF R1 #0018 + 0x58040001, // 0002 LDCONST R1 K1 + 0x88080100, // 0003 GETMBR R2 R0 K0 + 0x8C080502, // 0004 GETMET R2 R2 K2 + 0x7C080200, // 0005 CALL R2 1 + 0x14080202, // 0006 LT R2 R1 R2 + 0x780A000F, // 0007 JMPF R2 #0018 + 0x88080100, // 0008 GETMBR R2 R0 K0 + 0x94080401, // 0009 GETIDX R2 R2 R1 + 0x8C0C0103, // 000A GETMET R3 R0 K3 + 0x88140504, // 000B GETMBR R5 R2 K4 + 0x7C0C0400, // 000C CALL R3 2 + 0x780E0007, // 000D JMPF R3 #0016 + 0x880C0505, // 000E GETMBR R3 R2 K5 + 0x88100100, // 000F GETMBR R4 R0 K0 + 0x8C100906, // 0010 GETMET R4 R4 K6 + 0x5C180200, // 0011 MOVE R6 R1 + 0x7C100400, // 0012 CALL R4 2 + 0x5C100600, // 0013 MOVE R4 R3 + 0x7C100000, // 0014 CALL R4 0 + 0x70020000, // 0015 JMP #0017 + 0x00040307, // 0016 ADD R1 R1 K7 + 0x7001FFEA, // 0017 JMP #0003 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: compile +********************************************************************/ +be_local_closure(Tasmota_compile, /* name */ + be_nested_proto( + 12, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[14]) { /* constants */ + /* K0 */ be_nested_str(string), + /* K1 */ be_nested_str(endswith), + /* K2 */ be_nested_str(_X2Ebe), + /* K3 */ be_nested_str(BRY_X3A_X20file_X20_X27_X25s_X27_X20does_X20not_X20have_X20_X27_X2Ebe_X27_X20extension), + /* K4 */ be_nested_str(find), + /* K5 */ be_nested_str(_X23), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str(BRY_X3A_X20cannot_X20compile_X20file_X20in_X20read_X2Donly_X20archive), + /* K8 */ be_nested_str(file), + /* K9 */ be_nested_str(BRY_X3A_X20empty_X20compiled_X20file), + /* K10 */ be_nested_str(BRY_X3A_X20failed_X20to_X20load_X20_X27_X25s_X27_X20_X28_X25s_X20_X2D_X20_X25s_X29), + /* K11 */ be_nested_str(c), + /* K12 */ be_nested_str(save), + /* K13 */ be_nested_str(BRY_X3A_X20could_X20not_X20save_X20compiled_X20file_X20_X25s_X20_X28_X25s_X29), + }), + &be_const_str_compile, + &be_const_str_solidified, + ( &(const binstruction[84]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x8C0C0501, // 0001 GETMET R3 R2 K1 + 0x5C140200, // 0002 MOVE R5 R1 + 0x58180002, // 0003 LDCONST R6 K2 + 0x7C0C0600, // 0004 CALL R3 3 + 0x740E0007, // 0005 JMPT R3 #000E + 0x600C0001, // 0006 GETGBL R3 G1 + 0x60100018, // 0007 GETGBL R4 G24 + 0x58140003, // 0008 LDCONST R5 K3 + 0x5C180200, // 0009 MOVE R6 R1 + 0x7C100400, // 000A CALL R4 2 + 0x7C0C0200, // 000B CALL R3 1 + 0x500C0000, // 000C LDBOOL R3 0 0 + 0x80040600, // 000D RET 1 R3 + 0x8C0C0504, // 000E GETMET R3 R2 K4 + 0x5C140200, // 000F MOVE R5 R1 + 0x58180005, // 0010 LDCONST R6 K5 + 0x7C0C0600, // 0011 CALL R3 3 + 0x240C0706, // 0012 GT R3 R3 K6 + 0x780E0006, // 0013 JMPF R3 #001B + 0x600C0001, // 0014 GETGBL R3 G1 + 0x60100018, // 0015 GETGBL R4 G24 + 0x58140007, // 0016 LDCONST R5 K7 + 0x7C100200, // 0017 CALL R4 1 + 0x7C0C0200, // 0018 CALL R3 1 + 0x500C0000, // 0019 LDBOOL R3 0 0 + 0x80040600, // 001A RET 1 R3 + 0x4C0C0000, // 001B LDNIL R3 + 0xA8020011, // 001C EXBLK 0 #002F + 0x6010000D, // 001D GETGBL R4 G13 + 0x5C140200, // 001E MOVE R5 R1 + 0x58180008, // 001F LDCONST R6 K8 + 0x7C100400, // 0020 CALL R4 2 + 0x5C0C0800, // 0021 MOVE R3 R4 + 0x4C100000, // 0022 LDNIL R4 + 0x1C100604, // 0023 EQ R4 R3 R4 + 0x78120007, // 0024 JMPF R4 #002D + 0x60100001, // 0025 GETGBL R4 G1 + 0x60140018, // 0026 GETGBL R5 G24 + 0x58180009, // 0027 LDCONST R6 K9 + 0x7C140200, // 0028 CALL R5 1 + 0x7C100200, // 0029 CALL R4 1 + 0x50100000, // 002A LDBOOL R4 0 0 + 0xA8040001, // 002B EXBLK 1 1 + 0x80040800, // 002C RET 1 R4 + 0xA8040001, // 002D EXBLK 1 1 + 0x7002000D, // 002E JMP #003D + 0xAC100002, // 002F CATCH R4 0 2 + 0x7002000A, // 0030 JMP #003C + 0x60180001, // 0031 GETGBL R6 G1 + 0x601C0018, // 0032 GETGBL R7 G24 + 0x5820000A, // 0033 LDCONST R8 K10 + 0x5C240200, // 0034 MOVE R9 R1 + 0x5C280800, // 0035 MOVE R10 R4 + 0x5C2C0A00, // 0036 MOVE R11 R5 + 0x7C1C0800, // 0037 CALL R7 4 + 0x7C180200, // 0038 CALL R6 1 + 0x50180000, // 0039 LDBOOL R6 0 0 + 0x80040C00, // 003A RET 1 R6 + 0x70020000, // 003B JMP #003D + 0xB0080000, // 003C RAISE 2 R0 R0 + 0x0010030B, // 003D ADD R4 R1 K11 + 0xA8020005, // 003E EXBLK 0 #0045 + 0x8C14010C, // 003F GETMET R5 R0 K12 + 0x5C1C0800, // 0040 MOVE R7 R4 + 0x5C200600, // 0041 MOVE R8 R3 + 0x7C140600, // 0042 CALL R5 3 + 0xA8040001, // 0043 EXBLK 1 1 + 0x7002000C, // 0044 JMP #0052 + 0xAC140001, // 0045 CATCH R5 0 1 + 0x70020009, // 0046 JMP #0051 + 0x60180001, // 0047 GETGBL R6 G1 + 0x601C0018, // 0048 GETGBL R7 G24 + 0x5820000D, // 0049 LDCONST R8 K13 + 0x5C240800, // 004A MOVE R9 R4 + 0x5C280A00, // 004B MOVE R10 R5 + 0x7C1C0600, // 004C CALL R7 3 + 0x7C180200, // 004D CALL R6 1 + 0x50180000, // 004E LDBOOL R6 0 0 + 0x80040C00, // 004F RET 1 R6 + 0x70020000, // 0050 JMP #0052 + 0xB0080000, // 0051 RAISE 2 R0 R0 + 0x50140200, // 0052 LDBOOL R5 1 0 + 0x80040A00, // 0053 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_timer +********************************************************************/ +be_local_closure(Tasmota_remove_timer, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str(_timers), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(size), + /* K3 */ be_nested_str(id), + /* K4 */ be_nested_str(remove), + /* K5 */ be_const_int(1), + }), + &be_const_str_remove_timer, + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x780A000E, // 0001 JMPF R2 #0011 + 0x580C0001, // 0002 LDCONST R3 K1 + 0x8C100502, // 0003 GETMET R4 R2 K2 + 0x7C100200, // 0004 CALL R4 1 + 0x14100604, // 0005 LT R4 R3 R4 + 0x78120009, // 0006 JMPF R4 #0011 + 0x94100403, // 0007 GETIDX R4 R2 R3 + 0x88100903, // 0008 GETMBR R4 R4 K3 + 0x1C100801, // 0009 EQ R4 R4 R1 + 0x78120003, // 000A JMPF R4 #000F + 0x8C100504, // 000B GETMET R4 R2 K4 + 0x5C180600, // 000C MOVE R6 R3 + 0x7C100400, // 000D CALL R4 2 + 0x70020000, // 000E JMP #0010 + 0x000C0705, // 000F ADD R3 R3 K5 + 0x7001FFF1, // 0010 JMP #0003 + 0x80000000, // 0011 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_rule +********************************************************************/ +be_local_closure(Tasmota_remove_rule, /* name */ + be_nested_proto( + 7, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str(_rules), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(trig), + /* K3 */ be_nested_str(rule), + /* K4 */ be_nested_str(id), + /* K5 */ be_nested_str(remove), + /* K6 */ be_const_int(1), + }), + &be_const_str_remove_rule, + &be_const_str_solidified, + ( &(const binstruction[27]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x780E0017, // 0001 JMPF R3 #001A + 0x580C0001, // 0002 LDCONST R3 K1 + 0x6010000C, // 0003 GETGBL R4 G12 + 0x88140100, // 0004 GETMBR R5 R0 K0 + 0x7C100200, // 0005 CALL R4 1 + 0x14100604, // 0006 LT R4 R3 R4 + 0x78120011, // 0007 JMPF R4 #001A + 0x88100100, // 0008 GETMBR R4 R0 K0 + 0x94100803, // 0009 GETIDX R4 R4 R3 + 0x88100902, // 000A GETMBR R4 R4 K2 + 0x88100903, // 000B GETMBR R4 R4 K3 + 0x1C100801, // 000C EQ R4 R4 R1 + 0x78120009, // 000D JMPF R4 #0018 + 0x88100100, // 000E GETMBR R4 R0 K0 + 0x94100803, // 000F GETIDX R4 R4 R3 + 0x88100904, // 0010 GETMBR R4 R4 K4 + 0x1C100802, // 0011 EQ R4 R4 R2 + 0x78120004, // 0012 JMPF R4 #0018 + 0x88100100, // 0013 GETMBR R4 R0 K0 + 0x8C100905, // 0014 GETMET R4 R4 K5 + 0x5C180600, // 0015 MOVE R6 R3 + 0x7C100400, // 0016 CALL R4 2 + 0x70020000, // 0017 JMP #0019 + 0x000C0706, // 0018 ADD R3 R3 K6 + 0x7001FFE8, // 0019 JMP #0003 + 0x80000000, // 001A RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: exec_tele ********************************************************************/ @@ -1194,11 +1551,263 @@ be_local_closure(Tasmota_add_cmd, /* name */ /******************************************************************** -** Solidified function: find_op +** Solidified function: wire_scan ********************************************************************/ -be_local_closure(Tasmota_find_op, /* name */ +be_local_closure(Tasmota_wire_scan, /* name */ be_nested_proto( - 7, /* nstack */ + 6, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str(i2c_enabled), + /* K1 */ be_nested_str(wire1), + /* K2 */ be_nested_str(enabled), + /* K3 */ be_nested_str(detect), + /* K4 */ be_nested_str(wire2), + }), + &be_const_str_wire_scan, + &be_const_str_solidified, + ( &(const binstruction[33]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x200C0403, // 0001 NE R3 R2 R3 + 0x780E0005, // 0002 JMPF R3 #0009 + 0x8C0C0100, // 0003 GETMET R3 R0 K0 + 0x5C140400, // 0004 MOVE R5 R2 + 0x7C0C0400, // 0005 CALL R3 2 + 0x740E0001, // 0006 JMPT R3 #0009 + 0x4C0C0000, // 0007 LDNIL R3 + 0x80040600, // 0008 RET 1 R3 + 0x880C0101, // 0009 GETMBR R3 R0 K1 + 0x8C0C0702, // 000A GETMET R3 R3 K2 + 0x7C0C0200, // 000B CALL R3 1 + 0x780E0006, // 000C JMPF R3 #0014 + 0x880C0101, // 000D GETMBR R3 R0 K1 + 0x8C0C0703, // 000E GETMET R3 R3 K3 + 0x5C140200, // 000F MOVE R5 R1 + 0x7C0C0400, // 0010 CALL R3 2 + 0x780E0001, // 0011 JMPF R3 #0014 + 0x880C0101, // 0012 GETMBR R3 R0 K1 + 0x80040600, // 0013 RET 1 R3 + 0x880C0104, // 0014 GETMBR R3 R0 K4 + 0x8C0C0702, // 0015 GETMET R3 R3 K2 + 0x7C0C0200, // 0016 CALL R3 1 + 0x780E0006, // 0017 JMPF R3 #001F + 0x880C0104, // 0018 GETMBR R3 R0 K4 + 0x8C0C0703, // 0019 GETMET R3 R3 K3 + 0x5C140200, // 001A MOVE R5 R1 + 0x7C0C0400, // 001B CALL R3 2 + 0x780E0001, // 001C JMPF R3 #001F + 0x880C0104, // 001D GETMBR R3 R0 K4 + 0x80040600, // 001E RET 1 R3 + 0x4C0C0000, // 001F LDNIL R3 + 0x80040600, // 0020 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_key_i +********************************************************************/ +be_local_closure(Tasmota_find_key_i, /* name */ + be_nested_proto( + 10, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str(string), + /* K1 */ be_nested_str(toupper), + /* K2 */ be_nested_str(keys), + /* K3 */ be_nested_str(_X3F), + /* K4 */ be_nested_str(stop_iteration), + }), + &be_const_str_find_key_i, + &be_const_str_solidified, + ( &(const binstruction[30]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0x8C100701, // 0001 GETMET R4 R3 K1 + 0x5C180400, // 0002 MOVE R6 R2 + 0x7C100400, // 0003 CALL R4 2 + 0x6014000F, // 0004 GETGBL R5 G15 + 0x5C180200, // 0005 MOVE R6 R1 + 0x601C0013, // 0006 GETGBL R7 G19 + 0x7C140400, // 0007 CALL R5 2 + 0x78160013, // 0008 JMPF R5 #001D + 0x60140010, // 0009 GETGBL R5 G16 + 0x8C180302, // 000A GETMET R6 R1 K2 + 0x7C180200, // 000B CALL R6 1 + 0x7C140200, // 000C CALL R5 1 + 0xA802000B, // 000D EXBLK 0 #001A + 0x5C180A00, // 000E MOVE R6 R5 + 0x7C180000, // 000F CALL R6 0 + 0x8C1C0701, // 0010 GETMET R7 R3 K1 + 0x5C240C00, // 0011 MOVE R9 R6 + 0x7C1C0400, // 0012 CALL R7 2 + 0x1C1C0E04, // 0013 EQ R7 R7 R4 + 0x741E0001, // 0014 JMPT R7 #0017 + 0x1C1C0503, // 0015 EQ R7 R2 K3 + 0x781E0001, // 0016 JMPF R7 #0019 + 0xA8040001, // 0017 EXBLK 1 1 + 0x80040C00, // 0018 RET 1 R6 + 0x7001FFF3, // 0019 JMP #000E + 0x58140004, // 001A LDCONST R5 K4 + 0xAC140200, // 001B CATCH R5 1 0 + 0xB0080000, // 001C RAISE 2 R0 R0 + 0x80000000, // 001D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: urlfetch +********************************************************************/ +be_local_closure(Tasmota_urlfetch, /* name */ + be_nested_proto( + 10, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[17]) { /* constants */ + /* K0 */ be_nested_str(string), + /* K1 */ be_nested_str(split), + /* K2 */ be_nested_str(_X2F), + /* K3 */ be_nested_str(pop), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str(index_X2Ehtml), + /* K6 */ be_nested_str(webclient), + /* K7 */ be_nested_str(set_follow_redirects), + /* K8 */ be_nested_str(begin), + /* K9 */ be_nested_str(GET), + /* K10 */ be_nested_str(status_X3A_X20), + /* K11 */ be_nested_str(connection_error), + /* K12 */ be_nested_str(write_file), + /* K13 */ be_nested_str(close), + /* K14 */ be_nested_str(log), + /* K15 */ be_nested_str(BRY_X3A_X20Fetched_X20), + /* K16 */ be_const_int(3), + }), + &be_const_str_urlfetch, + &be_const_str_solidified, + ( &(const binstruction[48]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0403, // 0001 EQ R3 R2 R3 + 0x780E000D, // 0002 JMPF R3 #0011 + 0xA40E0000, // 0003 IMPORT R3 K0 + 0x8C100701, // 0004 GETMET R4 R3 K1 + 0x5C180200, // 0005 MOVE R6 R1 + 0x581C0002, // 0006 LDCONST R7 K2 + 0x7C100600, // 0007 CALL R4 3 + 0x8C100903, // 0008 GETMET R4 R4 K3 + 0x7C100200, // 0009 CALL R4 1 + 0x5C080800, // 000A MOVE R2 R4 + 0x6010000C, // 000B GETGBL R4 G12 + 0x5C140400, // 000C MOVE R5 R2 + 0x7C100200, // 000D CALL R4 1 + 0x1C100904, // 000E EQ R4 R4 K4 + 0x78120000, // 000F JMPF R4 #0011 + 0x58080005, // 0010 LDCONST R2 K5 + 0xB80E0C00, // 0011 GETNGBL R3 K6 + 0x7C0C0000, // 0012 CALL R3 0 + 0x8C100707, // 0013 GETMET R4 R3 K7 + 0x50180200, // 0014 LDBOOL R6 1 0 + 0x7C100400, // 0015 CALL R4 2 + 0x8C100708, // 0016 GETMET R4 R3 K8 + 0x5C180200, // 0017 MOVE R6 R1 + 0x7C100400, // 0018 CALL R4 2 + 0x8C100709, // 0019 GETMET R4 R3 K9 + 0x7C100200, // 001A CALL R4 1 + 0x541600C7, // 001B LDINT R5 200 + 0x20140805, // 001C NE R5 R4 R5 + 0x78160004, // 001D JMPF R5 #0023 + 0x60140008, // 001E GETGBL R5 G8 + 0x5C180800, // 001F MOVE R6 R4 + 0x7C140200, // 0020 CALL R5 1 + 0x00161405, // 0021 ADD R5 K10 R5 + 0xB0061605, // 0022 RAISE 1 K11 R5 + 0x8C14070C, // 0023 GETMET R5 R3 K12 + 0x5C1C0400, // 0024 MOVE R7 R2 + 0x7C140400, // 0025 CALL R5 2 + 0x8C18070D, // 0026 GETMET R6 R3 K13 + 0x7C180200, // 0027 CALL R6 1 + 0x8C18010E, // 0028 GETMET R6 R0 K14 + 0x60200008, // 0029 GETGBL R8 G8 + 0x5C240A00, // 002A MOVE R9 R5 + 0x7C200200, // 002B CALL R8 1 + 0x00221E08, // 002C ADD R8 K15 R8 + 0x58240010, // 002D LDCONST R9 K16 + 0x7C180600, // 002E CALL R6 3 + 0x80040800, // 002F RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: fast_loop +********************************************************************/ +be_local_closure(Tasmota_fast_loop, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str(_fl), + /* K1 */ be_const_int(0), + /* K2 */ be_const_int(1), + }), + &be_const_str_fast_loop, + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x5C080200, // 0001 MOVE R2 R1 + 0x740A0000, // 0002 JMPT R2 #0004 + 0x80000400, // 0003 RET 0 + 0x58080001, // 0004 LDCONST R2 K1 + 0x600C000C, // 0005 GETGBL R3 G12 + 0x5C100200, // 0006 MOVE R4 R1 + 0x7C0C0200, // 0007 CALL R3 1 + 0x140C0403, // 0008 LT R3 R2 R3 + 0x780E0003, // 0009 JMPF R3 #000E + 0x940C0202, // 000A GETIDX R3 R1 R2 + 0x7C0C0000, // 000B CALL R3 0 + 0x00080502, // 000C ADD R2 R2 K2 + 0x7001FFF6, // 000D JMP #0005 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: gen_cb +********************************************************************/ +be_local_closure(Tasmota_gen_cb, /* name */ + be_nested_proto( + 6, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1206,46 +1815,162 @@ be_local_closure(Tasmota_find_op, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str(_find_op), - /* K1 */ be_const_int(0), - /* K2 */ be_const_int(1), - /* K3 */ be_const_int(2147483647), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str(cb), + /* K1 */ be_nested_str(gen_cb), }), - &be_const_str_find_op, + &be_const_str_gen_cb, &be_const_str_solidified, - ( &(const binstruction[31]) { /* code */ + ( &(const binstruction[ 5]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x8C0C0501, // 0001 GETMET R3 R2 K1 + 0x5C140200, // 0002 MOVE R5 R1 + 0x7C0C0400, // 0003 CALL R3 2 + 0x80040600, // 0004 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: time_str +********************************************************************/ +be_local_closure(Tasmota_time_str, /* name */ + be_nested_proto( + 11, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str(time_dump), + /* K1 */ be_nested_str(_X2504d_X2D_X2502d_X2D_X2502dT_X2502d_X3A_X2502d_X3A_X2502d), + /* K2 */ be_nested_str(year), + /* K3 */ be_nested_str(month), + /* K4 */ be_nested_str(day), + /* K5 */ be_nested_str(hour), + /* K6 */ be_nested_str(min), + /* K7 */ be_nested_str(sec), + }), + &be_const_str_time_str, + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ 0x8C080100, // 0000 GETMET R2 R0 K0 0x5C100200, // 0001 MOVE R4 R1 0x7C080400, // 0002 CALL R2 2 - 0x280C0501, // 0003 GE R3 R2 K1 - 0x780E0011, // 0004 JMPF R3 #0017 - 0x540E7FFE, // 0005 LDINT R3 32767 - 0x2C0C0403, // 0006 AND R3 R2 R3 - 0x5412000F, // 0007 LDINT R4 16 - 0x3C100404, // 0008 SHR R4 R2 R4 - 0x60140012, // 0009 GETGBL R5 G18 - 0x7C140000, // 000A CALL R5 0 - 0x04180702, // 000B SUB R6 R3 K2 - 0x401A0206, // 000C CONNECT R6 K1 R6 - 0x94180206, // 000D GETIDX R6 R1 R6 - 0x40180A06, // 000E CONNECT R6 R5 R6 - 0x04180902, // 000F SUB R6 R4 K2 - 0x40180606, // 0010 CONNECT R6 R3 R6 - 0x94180206, // 0011 GETIDX R6 R1 R6 - 0x40180A06, // 0012 CONNECT R6 R5 R6 - 0x40180903, // 0013 CONNECT R6 R4 K3 - 0x94180206, // 0014 GETIDX R6 R1 R6 - 0x40180A06, // 0015 CONNECT R6 R5 R6 - 0x80040A00, // 0016 RET 1 R5 - 0x600C0012, // 0017 GETGBL R3 G18 - 0x7C0C0000, // 0018 CALL R3 0 - 0x40100601, // 0019 CONNECT R4 R3 R1 - 0x4C100000, // 001A LDNIL R4 - 0x40100604, // 001B CONNECT R4 R3 R4 - 0x4C100000, // 001C LDNIL R4 - 0x40100604, // 001D CONNECT R4 R3 R4 - 0x80040600, // 001E RET 1 R3 + 0x600C0018, // 0003 GETGBL R3 G24 + 0x58100001, // 0004 LDCONST R4 K1 + 0x94140502, // 0005 GETIDX R5 R2 K2 + 0x94180503, // 0006 GETIDX R6 R2 K3 + 0x941C0504, // 0007 GETIDX R7 R2 K4 + 0x94200505, // 0008 GETIDX R8 R2 K5 + 0x94240506, // 0009 GETIDX R9 R2 K6 + 0x94280507, // 000A GETIDX R10 R2 K7 + 0x7C0C0E00, // 000B CALL R3 7 + 0x80040600, // 000C RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_fast_loop +********************************************************************/ +be_local_closure(Tasmota_add_fast_loop, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str(check_not_method), + /* K1 */ be_nested_str(_fl), + /* K2 */ be_nested_str(function), + /* K3 */ be_nested_str(value_error), + /* K4 */ be_nested_str(argument_X20must_X20be_X20a_X20function), + /* K5 */ be_nested_str(global), + /* K6 */ be_nested_str(fast_loop_enabled), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str(push), + }), + &be_const_str_add_fast_loop, + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5C100200, // 0001 MOVE R4 R1 + 0x7C080400, // 0002 CALL R2 2 + 0x88080101, // 0003 GETMBR R2 R0 K1 + 0x4C0C0000, // 0004 LDNIL R3 + 0x1C080403, // 0005 EQ R2 R2 R3 + 0x780A0002, // 0006 JMPF R2 #000A + 0x60080012, // 0007 GETGBL R2 G18 + 0x7C080000, // 0008 CALL R2 0 + 0x90020202, // 0009 SETMBR R0 K1 R2 + 0x60080004, // 000A GETGBL R2 G4 + 0x5C0C0200, // 000B MOVE R3 R1 + 0x7C080200, // 000C CALL R2 1 + 0x20080502, // 000D NE R2 R2 K2 + 0x780A0000, // 000E JMPF R2 #0010 + 0xB0060704, // 000F RAISE 1 K3 K4 + 0x88080105, // 0010 GETMBR R2 R0 K5 + 0x900A0D07, // 0011 SETMBR R2 K6 K7 + 0x88080101, // 0012 GETMBR R2 R0 K1 + 0x8C080508, // 0013 GETMET R2 R2 K8 + 0x5C100200, // 0014 MOVE R4 R1 + 0x7C080400, // 0015 CALL R2 2 + 0x80000000, // 0016 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_light +********************************************************************/ +be_local_closure(Tasmota_get_light, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str(tasmota_X2Eget_light_X28_X29_X20is_X20deprecated_X2C_X20use_X20light_X2Eget_X28_X29), + /* K1 */ be_nested_str(light), + /* K2 */ be_nested_str(get), + }), + &be_const_str_get_light, + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0x60080001, // 0000 GETGBL R2 G1 + 0x580C0000, // 0001 LDCONST R3 K0 + 0x7C080200, // 0002 CALL R2 1 + 0xA40A0200, // 0003 IMPORT R2 K1 + 0x4C0C0000, // 0004 LDNIL R3 + 0x200C0203, // 0005 NE R3 R1 R3 + 0x780E0004, // 0006 JMPF R3 #000C + 0x8C0C0502, // 0007 GETMET R3 R2 K2 + 0x5C140200, // 0008 MOVE R5 R1 + 0x7C0C0400, // 0009 CALL R3 2 + 0x80040600, // 000A RET 1 R3 + 0x70020002, // 000B JMP #000F + 0x8C0C0502, // 000C GETMET R3 R2 K2 + 0x7C0C0200, // 000D CALL R3 1 + 0x80040600, // 000E RET 1 R3 + 0x80000000, // 000F RET 0 }) ) ); @@ -1310,131 +2035,109 @@ be_local_closure(Tasmota_add_cron, /* name */ /******************************************************************** -** Solidified function: remove_rule +** Solidified function: hs2rgb ********************************************************************/ -be_local_closure(Tasmota_remove_rule, /* name */ +be_local_closure(Tasmota_hs2rgb, /* name */ + be_nested_proto( + 17, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str(tasmota), + /* K2 */ be_nested_str(scale_uint), + /* K3 */ be_const_int(1), + /* K4 */ be_const_int(2), + /* K5 */ be_const_int(3), + }), + &be_const_str_hs2rgb, + &be_const_str_solidified, + ( &(const binstruction[68]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0403, // 0001 EQ R3 R2 R3 + 0x780E0000, // 0002 JMPF R3 #0004 + 0x540A00FE, // 0003 LDINT R2 255 + 0x540E00FE, // 0004 LDINT R3 255 + 0x541200FE, // 0005 LDINT R4 255 + 0x541600FE, // 0006 LDINT R5 255 + 0x541A0167, // 0007 LDINT R6 360 + 0x10040206, // 0008 MOD R1 R1 R6 + 0x24180500, // 0009 GT R6 R2 K0 + 0x781A0031, // 000A JMPF R6 #003D + 0x541A003B, // 000B LDINT R6 60 + 0x0C180206, // 000C DIV R6 R1 R6 + 0x541E003B, // 000D LDINT R7 60 + 0x101C0207, // 000E MOD R7 R1 R7 + 0x542200FE, // 000F LDINT R8 255 + 0x04201002, // 0010 SUB R8 R8 R2 + 0xB8260200, // 0011 GETNGBL R9 K1 + 0x8C241302, // 0012 GETMET R9 R9 K2 + 0x5C2C0E00, // 0013 MOVE R11 R7 + 0x58300000, // 0014 LDCONST R12 K0 + 0x5436003B, // 0015 LDINT R13 60 + 0x543A00FE, // 0016 LDINT R14 255 + 0x5C3C1000, // 0017 MOVE R15 R8 + 0x7C240C00, // 0018 CALL R9 6 + 0xB82A0200, // 0019 GETNGBL R10 K1 + 0x8C281502, // 001A GETMET R10 R10 K2 + 0x5C300E00, // 001B MOVE R12 R7 + 0x58340000, // 001C LDCONST R13 K0 + 0x543A003B, // 001D LDINT R14 60 + 0x5C3C1000, // 001E MOVE R15 R8 + 0x544200FE, // 001F LDINT R16 255 + 0x7C280C00, // 0020 CALL R10 6 + 0x1C2C0D00, // 0021 EQ R11 R6 K0 + 0x782E0002, // 0022 JMPF R11 #0026 + 0x5C141400, // 0023 MOVE R5 R10 + 0x5C101000, // 0024 MOVE R4 R8 + 0x70020016, // 0025 JMP #003D + 0x1C2C0D03, // 0026 EQ R11 R6 K3 + 0x782E0002, // 0027 JMPF R11 #002B + 0x5C0C1200, // 0028 MOVE R3 R9 + 0x5C101000, // 0029 MOVE R4 R8 + 0x70020011, // 002A JMP #003D + 0x1C2C0D04, // 002B EQ R11 R6 K4 + 0x782E0002, // 002C JMPF R11 #0030 + 0x5C0C1000, // 002D MOVE R3 R8 + 0x5C101400, // 002E MOVE R4 R10 + 0x7002000C, // 002F JMP #003D + 0x1C2C0D05, // 0030 EQ R11 R6 K5 + 0x782E0002, // 0031 JMPF R11 #0035 + 0x5C0C1000, // 0032 MOVE R3 R8 + 0x5C141200, // 0033 MOVE R5 R9 + 0x70020007, // 0034 JMP #003D + 0x542E0003, // 0035 LDINT R11 4 + 0x1C2C0C0B, // 0036 EQ R11 R6 R11 + 0x782E0002, // 0037 JMPF R11 #003B + 0x5C0C1400, // 0038 MOVE R3 R10 + 0x5C141000, // 0039 MOVE R5 R8 + 0x70020001, // 003A JMP #003D + 0x5C141000, // 003B MOVE R5 R8 + 0x5C101200, // 003C MOVE R4 R9 + 0x541A000F, // 003D LDINT R6 16 + 0x38180606, // 003E SHL R6 R3 R6 + 0x541E0007, // 003F LDINT R7 8 + 0x381C0A07, // 0040 SHL R7 R5 R7 + 0x30180C07, // 0041 OR R6 R6 R7 + 0x30180C04, // 0042 OR R6 R6 R4 + 0x80040C00, // 0043 RET 1 R6 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_cron +********************************************************************/ +be_local_closure(Tasmota_remove_cron, /* name */ be_nested_proto( 7, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_nested_str(_rules), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str(trig), - /* K3 */ be_nested_str(rule), - /* K4 */ be_nested_str(id), - /* K5 */ be_nested_str(remove), - /* K6 */ be_const_int(1), - }), - &be_const_str_remove_rule, - &be_const_str_solidified, - ( &(const binstruction[27]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x780E0017, // 0001 JMPF R3 #001A - 0x580C0001, // 0002 LDCONST R3 K1 - 0x6010000C, // 0003 GETGBL R4 G12 - 0x88140100, // 0004 GETMBR R5 R0 K0 - 0x7C100200, // 0005 CALL R4 1 - 0x14100604, // 0006 LT R4 R3 R4 - 0x78120011, // 0007 JMPF R4 #001A - 0x88100100, // 0008 GETMBR R4 R0 K0 - 0x94100803, // 0009 GETIDX R4 R4 R3 - 0x88100902, // 000A GETMBR R4 R4 K2 - 0x88100903, // 000B GETMBR R4 R4 K3 - 0x1C100801, // 000C EQ R4 R4 R1 - 0x78120009, // 000D JMPF R4 #0018 - 0x88100100, // 000E GETMBR R4 R0 K0 - 0x94100803, // 000F GETIDX R4 R4 R3 - 0x88100904, // 0010 GETMBR R4 R4 K4 - 0x1C100802, // 0011 EQ R4 R4 R2 - 0x78120004, // 0012 JMPF R4 #0018 - 0x88100100, // 0013 GETMBR R4 R0 K0 - 0x8C100905, // 0014 GETMET R4 R4 K5 - 0x5C180600, // 0015 MOVE R6 R3 - 0x7C100400, // 0016 CALL R4 2 - 0x70020000, // 0017 JMP #0019 - 0x000C0706, // 0018 ADD R3 R3 K6 - 0x7001FFE8, // 0019 JMP #0003 - 0x80000000, // 001A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: wire_scan -********************************************************************/ -be_local_closure(Tasmota_wire_scan, /* name */ - be_nested_proto( - 6, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str(i2c_enabled), - /* K1 */ be_nested_str(wire1), - /* K2 */ be_nested_str(enabled), - /* K3 */ be_nested_str(detect), - /* K4 */ be_nested_str(wire2), - }), - &be_const_str_wire_scan, - &be_const_str_solidified, - ( &(const binstruction[33]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x200C0403, // 0001 NE R3 R2 R3 - 0x780E0005, // 0002 JMPF R3 #0009 - 0x8C0C0100, // 0003 GETMET R3 R0 K0 - 0x5C140400, // 0004 MOVE R5 R2 - 0x7C0C0400, // 0005 CALL R3 2 - 0x740E0001, // 0006 JMPT R3 #0009 - 0x4C0C0000, // 0007 LDNIL R3 - 0x80040600, // 0008 RET 1 R3 - 0x880C0101, // 0009 GETMBR R3 R0 K1 - 0x8C0C0702, // 000A GETMET R3 R3 K2 - 0x7C0C0200, // 000B CALL R3 1 - 0x780E0006, // 000C JMPF R3 #0014 - 0x880C0101, // 000D GETMBR R3 R0 K1 - 0x8C0C0703, // 000E GETMET R3 R3 K3 - 0x5C140200, // 000F MOVE R5 R1 - 0x7C0C0400, // 0010 CALL R3 2 - 0x780E0001, // 0011 JMPF R3 #0014 - 0x880C0101, // 0012 GETMBR R3 R0 K1 - 0x80040600, // 0013 RET 1 R3 - 0x880C0104, // 0014 GETMBR R3 R0 K4 - 0x8C0C0702, // 0015 GETMET R3 R3 K2 - 0x7C0C0200, // 0016 CALL R3 1 - 0x780E0006, // 0017 JMPF R3 #001F - 0x880C0104, // 0018 GETMBR R3 R0 K4 - 0x8C0C0703, // 0019 GETMET R3 R3 K3 - 0x5C140200, // 001A MOVE R5 R1 - 0x7C0C0400, // 001B CALL R3 2 - 0x780E0001, // 001C JMPF R3 #001F - 0x880C0104, // 001D GETMBR R3 R0 K4 - 0x80040600, // 001E RET 1 R3 - 0x4C0C0000, // 001F LDNIL R3 - 0x80040600, // 0020 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_light -********************************************************************/ -be_local_closure(Tasmota_get_light, /* name */ - be_nested_proto( - 6, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1442,138 +2145,35 @@ be_local_closure(Tasmota_get_light, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(tasmota_X2Eget_light_X28_X29_X20is_X20deprecated_X2C_X20use_X20light_X2Eget_X28_X29), - /* K1 */ be_nested_str(light), - /* K2 */ be_nested_str(get), - }), - &be_const_str_get_light, - &be_const_str_solidified, - ( &(const binstruction[16]) { /* code */ - 0x60080001, // 0000 GETGBL R2 G1 - 0x580C0000, // 0001 LDCONST R3 K0 - 0x7C080200, // 0002 CALL R2 1 - 0xA40A0200, // 0003 IMPORT R2 K1 - 0x4C0C0000, // 0004 LDNIL R3 - 0x200C0203, // 0005 NE R3 R1 R3 - 0x780E0004, // 0006 JMPF R3 #000C - 0x8C0C0502, // 0007 GETMET R3 R2 K2 - 0x5C140200, // 0008 MOVE R5 R1 - 0x7C0C0400, // 0009 CALL R3 2 - 0x80040600, // 000A RET 1 R3 - 0x70020002, // 000B JMP #000F - 0x8C0C0502, // 000C GETMET R3 R2 K2 - 0x7C0C0200, // 000D CALL R3 1 - 0x80040600, // 000E RET 1 R3 - 0x80000000, // 000F RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: cmd -********************************************************************/ -be_local_closure(Tasmota_cmd, /* name */ - be_nested_proto( - 8, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_nested_str(cmd_res), - /* K1 */ be_nested_str(tasmota), - /* K2 */ be_nested_str(global), - /* K3 */ be_nested_str(maxlog_level), - /* K4 */ be_const_int(2), + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str(_crons), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(size), + /* K3 */ be_nested_str(id), + /* K4 */ be_nested_str(remove), /* K5 */ be_const_int(1), - /* K6 */ be_nested_str(_cmd), }), - &be_const_str_cmd, + &be_const_str_remove_cron, &be_const_str_solidified, - ( &(const binstruction[27]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x50100200, // 0001 LDBOOL R4 1 0 - 0x90020004, // 0002 SETMBR R0 K0 R4 - 0xB8120200, // 0003 GETNGBL R4 K1 - 0x88100902, // 0004 GETMBR R4 R4 K2 - 0x88100903, // 0005 GETMBR R4 R4 K3 - 0x780A0004, // 0006 JMPF R2 #000C - 0x28140904, // 0007 GE R5 R4 K4 - 0x78160002, // 0008 JMPF R5 #000C - 0xB8160200, // 0009 GETNGBL R5 K1 - 0x88140B02, // 000A GETMBR R5 R5 K2 - 0x90160705, // 000B SETMBR R5 K3 K5 - 0x8C140106, // 000C GETMET R5 R0 K6 - 0x5C1C0200, // 000D MOVE R7 R1 - 0x7C140400, // 000E CALL R5 2 - 0x4C140000, // 000F LDNIL R5 - 0x88180100, // 0010 GETMBR R6 R0 K0 - 0x501C0200, // 0011 LDBOOL R7 1 0 - 0x20180C07, // 0012 NE R6 R6 R7 - 0x781A0000, // 0013 JMPF R6 #0015 - 0x88140100, // 0014 GETMBR R5 R0 K0 - 0x90020003, // 0015 SETMBR R0 K0 R3 - 0x780A0002, // 0016 JMPF R2 #001A - 0xB81A0200, // 0017 GETNGBL R6 K1 - 0x88180D02, // 0018 GETMBR R6 R6 K2 - 0x901A0604, // 0019 SETMBR R6 K3 R4 - 0x80040A00, // 001A RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_timer -********************************************************************/ -be_local_closure(Tasmota_set_timer, /* name */ - be_nested_proto( - 10, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str(check_not_method), - /* K1 */ be_nested_str(_timers), - /* K2 */ be_nested_str(push), - /* K3 */ be_nested_str(Trigger), - /* K4 */ be_nested_str(millis), - }), - &be_const_str_set_timer, - &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x8C100100, // 0000 GETMET R4 R0 K0 - 0x5C180400, // 0001 MOVE R6 R2 - 0x7C100400, // 0002 CALL R4 2 - 0x88100101, // 0003 GETMBR R4 R0 K1 - 0x4C140000, // 0004 LDNIL R5 - 0x1C100805, // 0005 EQ R4 R4 R5 - 0x78120002, // 0006 JMPF R4 #000A - 0x60100012, // 0007 GETGBL R4 G18 - 0x7C100000, // 0008 CALL R4 0 - 0x90020204, // 0009 SETMBR R0 K1 R4 - 0x88100101, // 000A GETMBR R4 R0 K1 - 0x8C100902, // 000B GETMET R4 R4 K2 - 0xB81A0600, // 000C GETNGBL R6 K3 - 0x8C1C0104, // 000D GETMET R7 R0 K4 - 0x5C240200, // 000E MOVE R9 R1 - 0x7C1C0400, // 000F CALL R7 2 - 0x5C200400, // 0010 MOVE R8 R2 - 0x5C240600, // 0011 MOVE R9 R3 - 0x7C180600, // 0012 CALL R6 3 - 0x7C100400, // 0013 CALL R4 2 - 0x80000000, // 0014 RET 0 + ( &(const binstruction[18]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x780A000E, // 0001 JMPF R2 #0011 + 0x580C0001, // 0002 LDCONST R3 K1 + 0x8C100502, // 0003 GETMET R4 R2 K2 + 0x7C100200, // 0004 CALL R4 1 + 0x14100604, // 0005 LT R4 R3 R4 + 0x78120009, // 0006 JMPF R4 #0011 + 0x94100403, // 0007 GETIDX R4 R2 R3 + 0x88100903, // 0008 GETMBR R4 R4 K3 + 0x1C100801, // 0009 EQ R4 R4 R1 + 0x78120003, // 000A JMPF R4 #000F + 0x8C100504, // 000B GETMET R4 R2 K4 + 0x5C180600, // 000C MOVE R6 R3 + 0x7C100400, // 000D CALL R4 2 + 0x70020000, // 000E JMP #0010 + 0x000C0705, // 000F ADD R3 R3 K5 + 0x7001FFF1, // 0010 JMP #0003 + 0x80000000, // 0011 RET 0 }) ) ); @@ -1811,7 +2411,7 @@ be_local_closure(Tasmota_load, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str(BRY_X3A_X20failed_X20to_X20run_X20compiled_X20code_X20_X27_X25s_X27_X20_X2D_X20_X25s), + /* K0 */ be_nested_str(BRY_X3A_X20failed_X20to_X20run_X20compiled_X20code_X20_X28_X25s_X20_X2D_X20_X25s_X29), /* K1 */ be_nested_str(_debug_present), /* K2 */ be_nested_str(debug), /* K3 */ be_nested_str(traceback), @@ -1853,32 +2453,31 @@ be_local_closure(Tasmota_load, /* name */ ), }), 1, /* has constants */ - ( &(const bvalue[21]) { /* constants */ + ( &(const bvalue[20]) { /* constants */ /* K0 */ be_nested_str(string), /* K1 */ be_nested_str(path), /* K2 */ be_const_int(0), - /* K3 */ be_nested_str(_X2F), - /* K4 */ be_nested_str(split), - /* K5 */ be_nested_str(_X23), - /* K6 */ be_const_int(1), - /* K7 */ be_nested_str(find), - /* K8 */ be_nested_str(_X2E), - /* K9 */ be_nested_str(_X2Ebe), - /* K10 */ be_nested_str(_X2Ebec), - /* K11 */ be_nested_str(io_error), - /* K12 */ be_nested_str(file_X20extension_X20is_X20not_X20_X27_X2Ebe_X27_X20or_X20_X27_X2Ebec_X27), - /* K13 */ be_nested_str(last_modified), - /* K14 */ be_nested_str(c), - /* K15 */ be_nested_str(wd), - /* K16 */ be_nested_str(), - /* K17 */ be_nested_str(BRY_X3A_X20corrupt_X20bytecode_X20_X27_X25s_X27), - /* K18 */ be_nested_str(BRY_X3A_X20bytecode_X20has_X20wrong_X20version_X20_X27_X25s_X27_X20_X28_X25i_X29), - /* K19 */ be_nested_str(save), - /* K20 */ be_nested_str(BRY_X3A_X20could_X20not_X20save_X20compiled_X20file_X20_X25s_X20_X28_X25s_X29), + /* K3 */ be_nested_str(startswith), + /* K4 */ be_nested_str(_X2F), + /* K5 */ be_nested_str(find), + /* K6 */ be_nested_str(_X23), + /* K7 */ be_const_int(1), + /* K8 */ be_const_int(2147483647), + /* K9 */ be_nested_str(_X2E), + /* K10 */ be_nested_str(_X2Ebe), + /* K11 */ be_nested_str(endswith), + /* K12 */ be_nested_str(_X2Ebec), + /* K13 */ be_nested_str(c), + /* K14 */ be_nested_str(BRY_X3A_X20file_X20extension_X20is_X20not_X20_X27_X2Ebe_X27_X20nor_X20_X27_X2Ebec_X27), + /* K15 */ be_nested_str(exists), + /* K16 */ be_nested_str(wd), + /* K17 */ be_nested_str(), + /* K18 */ be_nested_str(BRY_X3A_X20corrupt_X20bytecode_X20_X27_X25s_X27), + /* K19 */ be_nested_str(BRY_X3A_X20bytecode_X20has_X20wrong_X20version_X20_X27_X25s_X27_X20_X28_X25s_X29), }), &be_const_str_load, &be_const_str_solidified, - ( &(const binstruction[180]) { /* code */ + ( &(const binstruction[164]) { /* code */ 0x84080000, // 0000 CLOSURE R2 P0 0x840C0001, // 0001 CLOSURE R3 P1 0x84100002, // 0002 CLOSURE R4 P2 @@ -1895,443 +2494,154 @@ be_local_closure(Tasmota_load, /* name */ 0x50280000, // 000D LDBOOL R10 0 0 0xA0000000, // 000E CLOSE R0 0x80041400, // 000F RET 1 R10 - 0x94280302, // 0010 GETIDX R10 R1 K2 - 0x20281503, // 0011 NE R10 R10 K3 - 0x782A0000, // 0012 JMPF R10 #0014 - 0x00060601, // 0013 ADD R1 K3 R1 - 0x8C281104, // 0014 GETMET R10 R8 K4 - 0x5C300200, // 0015 MOVE R12 R1 - 0x58340005, // 0016 LDCONST R13 K5 - 0x7C280600, // 0017 CALL R10 3 - 0x942C1502, // 0018 GETIDX R11 R10 K2 - 0x5431FFFE, // 0019 LDINT R12 -1 - 0x9430140C, // 001A GETIDX R12 R10 R12 - 0x6034000C, // 001B GETGBL R13 G12 - 0x5C381400, // 001C MOVE R14 R10 - 0x7C340200, // 001D CALL R13 1 - 0x24341B06, // 001E GT R13 R13 K6 - 0x8C381107, // 001F GETMET R14 R8 K7 - 0x5C401800, // 0020 MOVE R16 R12 - 0x58440008, // 0021 LDCONST R17 K8 - 0x7C380600, // 0022 CALL R14 3 - 0x14381D02, // 0023 LT R14 R14 K2 - 0x783A0001, // 0024 JMPF R14 #0027 - 0x00040309, // 0025 ADD R1 R1 K9 - 0x00301909, // 0026 ADD R12 R12 K9 - 0x5439FFFC, // 0027 LDINT R14 -3 - 0x543DFFFE, // 0028 LDINT R15 -1 - 0x40381C0F, // 0029 CONNECT R14 R14 R15 - 0x9438180E, // 002A GETIDX R14 R12 R14 - 0x1C381D09, // 002B EQ R14 R14 K9 - 0x543DFFFB, // 002C LDINT R15 -4 - 0x5441FFFE, // 002D LDINT R16 -1 - 0x403C1E10, // 002E CONNECT R15 R15 R16 - 0x943C180F, // 002F GETIDX R15 R12 R15 - 0x1C3C1F0A, // 0030 EQ R15 R15 K10 - 0x5C401C00, // 0031 MOVE R16 R14 - 0x74420002, // 0032 JMPT R16 #0036 - 0x5C401E00, // 0033 MOVE R16 R15 - 0x74420000, // 0034 JMPT R16 #0036 - 0xB006170C, // 0035 RAISE 1 K11 K12 - 0x8C40130D, // 0036 GETMET R16 R9 K13 - 0x5C480200, // 0037 MOVE R18 R1 - 0x7C400400, // 0038 CALL R16 2 - 0x783E0001, // 0039 JMPF R15 #003C - 0x5C440200, // 003A MOVE R17 R1 - 0x70020000, // 003B JMP #003D - 0x0044030E, // 003C ADD R17 R1 K14 - 0x783E0006, // 003D JMPF R15 #0045 - 0x4C480000, // 003E LDNIL R18 - 0x1C482012, // 003F EQ R18 R16 R18 - 0x784A0002, // 0040 JMPF R18 #0044 - 0x50480000, // 0041 LDBOOL R18 0 0 - 0xA0000000, // 0042 CLOSE R0 - 0x80042400, // 0043 RET 1 R18 - 0x70020014, // 0044 JMP #005A - 0x8C48130D, // 0045 GETMET R18 R9 K13 - 0x5C502200, // 0046 MOVE R20 R17 - 0x7C480400, // 0047 CALL R18 2 - 0x4C4C0000, // 0048 LDNIL R19 - 0x1C4C2013, // 0049 EQ R19 R16 R19 - 0x784E0005, // 004A JMPF R19 #0051 - 0x4C4C0000, // 004B LDNIL R19 - 0x1C4C2413, // 004C EQ R19 R18 R19 - 0x784E0002, // 004D JMPF R19 #0051 - 0x504C0000, // 004E LDBOOL R19 0 0 - 0xA0000000, // 004F CLOSE R0 - 0x80042600, // 0050 RET 1 R19 - 0x4C4C0000, // 0051 LDNIL R19 - 0x204C2413, // 0052 NE R19 R18 R19 - 0x784E0005, // 0053 JMPF R19 #005A - 0x4C4C0000, // 0054 LDNIL R19 - 0x1C4C2013, // 0055 EQ R19 R16 R19 - 0x744E0001, // 0056 JMPT R19 #0059 - 0x284C2410, // 0057 GE R19 R18 R16 - 0x784E0000, // 0058 JMPF R19 #005A - 0x503C0200, // 0059 LDBOOL R15 1 0 - 0x78360005, // 005A JMPF R13 #0061 - 0x00481705, // 005B ADD R18 R11 K5 - 0x90021E12, // 005C SETMBR R0 K15 R18 - 0x5C480400, // 005D MOVE R18 R2 - 0x884C010F, // 005E GETMBR R19 R0 K15 - 0x7C480200, // 005F CALL R18 1 - 0x70020000, // 0060 JMP #0062 - 0x90021F10, // 0061 SETMBR R0 K15 K16 - 0x4C480000, // 0062 LDNIL R18 - 0x783E0025, // 0063 JMPF R15 #008A - 0x5C4C0800, // 0064 MOVE R19 R4 - 0x5C502200, // 0065 MOVE R20 R17 - 0x7C4C0200, // 0066 CALL R19 1 - 0x50500200, // 0067 LDBOOL R20 1 0 - 0x4C540000, // 0068 LDNIL R21 - 0x1C542615, // 0069 EQ R21 R19 R21 - 0x78560007, // 006A JMPF R21 #0073 - 0x60540001, // 006B GETGBL R21 G1 - 0x60580018, // 006C GETGBL R22 G24 - 0x585C0011, // 006D LDCONST R23 K17 - 0x5C602200, // 006E MOVE R24 R17 - 0x7C580400, // 006F CALL R22 2 - 0x7C540200, // 0070 CALL R21 1 - 0x50500000, // 0071 LDBOOL R20 0 0 - 0x7002000A, // 0072 JMP #007E - 0x54560003, // 0073 LDINT R21 4 - 0x20542615, // 0074 NE R21 R19 R21 + 0x8C281103, // 0010 GETMET R10 R8 K3 + 0x5C300200, // 0011 MOVE R12 R1 + 0x58340004, // 0012 LDCONST R13 K4 + 0x7C280600, // 0013 CALL R10 3 + 0x742A0000, // 0014 JMPT R10 #0016 + 0x00060801, // 0015 ADD R1 K4 R1 + 0x8C281105, // 0016 GETMET R10 R8 K5 + 0x5C300200, // 0017 MOVE R12 R1 + 0x58340006, // 0018 LDCONST R13 K6 + 0x7C280600, // 0019 CALL R10 3 + 0x242C1502, // 001A GT R11 R10 K2 + 0x782E0003, // 001B JMPF R11 #0020 + 0x04301507, // 001C SUB R12 R10 K7 + 0x4032040C, // 001D CONNECT R12 K2 R12 + 0x9430020C, // 001E GETIDX R12 R1 R12 + 0x70020000, // 001F JMP #0021 + 0x5C300200, // 0020 MOVE R12 R1 + 0x782E0003, // 0021 JMPF R11 #0026 + 0x00341507, // 0022 ADD R13 R10 K7 + 0x40341B08, // 0023 CONNECT R13 R13 K8 + 0x9434020D, // 0024 GETIDX R13 R1 R13 + 0x70020000, // 0025 JMP #0027 + 0x5C340200, // 0026 MOVE R13 R1 + 0x8C381105, // 0027 GETMET R14 R8 K5 + 0x5C401A00, // 0028 MOVE R16 R13 + 0x58440009, // 0029 LDCONST R17 K9 + 0x7C380600, // 002A CALL R14 3 + 0x14381D02, // 002B LT R14 R14 K2 + 0x783A0001, // 002C JMPF R14 #002F + 0x0004030A, // 002D ADD R1 R1 K10 + 0x00341B0A, // 002E ADD R13 R13 K10 + 0x8C38110B, // 002F GETMET R14 R8 K11 + 0x5C401A00, // 0030 MOVE R16 R13 + 0x5844000A, // 0031 LDCONST R17 K10 + 0x7C380600, // 0032 CALL R14 3 + 0x8C3C110B, // 0033 GETMET R15 R8 K11 + 0x5C441A00, // 0034 MOVE R17 R13 + 0x5848000C, // 0035 LDCONST R18 K12 + 0x7C3C0600, // 0036 CALL R15 3 + 0x783E0001, // 0037 JMPF R15 #003A + 0x5C400200, // 0038 MOVE R16 R1 + 0x70020000, // 0039 JMP #003B + 0x0040030D, // 003A ADD R16 R1 K13 + 0x5C441C00, // 003B MOVE R17 R14 + 0x74460007, // 003C JMPT R17 #0045 + 0x5C441E00, // 003D MOVE R17 R15 + 0x74460005, // 003E JMPT R17 #0045 + 0x60440001, // 003F GETGBL R17 G1 + 0x5848000E, // 0040 LDCONST R18 K14 + 0x7C440200, // 0041 CALL R17 1 + 0x50440000, // 0042 LDBOOL R17 0 0 + 0xA0000000, // 0043 CLOSE R0 + 0x80042200, // 0044 RET 1 R17 + 0x50440000, // 0045 LDBOOL R17 0 0 + 0x783E0008, // 0046 JMPF R15 #0050 + 0x8C48130F, // 0047 GETMET R18 R9 K15 + 0x5C502000, // 0048 MOVE R20 R16 + 0x7C480400, // 0049 CALL R18 2 + 0x744A0002, // 004A JMPT R18 #004E + 0x50480000, // 004B LDBOOL R18 0 0 + 0xA0000000, // 004C CLOSE R0 + 0x80042400, // 004D RET 1 R18 + 0x50440200, // 004E LDBOOL R17 1 0 + 0x70020014, // 004F JMP #0065 + 0x8C48130F, // 0050 GETMET R18 R9 K15 + 0x5C500200, // 0051 MOVE R20 R1 + 0x7C480400, // 0052 CALL R18 2 + 0x784A0007, // 0053 JMPF R18 #005C + 0x8C48130F, // 0054 GETMET R18 R9 K15 + 0x5C502000, // 0055 MOVE R20 R16 + 0x7C480400, // 0056 CALL R18 2 + 0x784A0002, // 0057 JMPF R18 #005B + 0x5C480A00, // 0058 MOVE R18 R5 + 0x5C4C2000, // 0059 MOVE R19 R16 + 0x7C480200, // 005A CALL R18 1 + 0x70020008, // 005B JMP #0065 + 0x8C48130F, // 005C GETMET R18 R9 K15 + 0x5C502000, // 005D MOVE R20 R16 + 0x7C480400, // 005E CALL R18 2 + 0x784A0001, // 005F JMPF R18 #0062 + 0x50440200, // 0060 LDBOOL R17 1 0 + 0x70020002, // 0061 JMP #0065 + 0x50480000, // 0062 LDBOOL R18 0 0 + 0xA0000000, // 0063 CLOSE R0 + 0x80042400, // 0064 RET 1 R18 + 0x782E0005, // 0065 JMPF R11 #006C + 0x00481906, // 0066 ADD R18 R12 K6 + 0x90022012, // 0067 SETMBR R0 K16 R18 + 0x5C480400, // 0068 MOVE R18 R2 + 0x884C0110, // 0069 GETMBR R19 R0 K16 + 0x7C480200, // 006A CALL R18 1 + 0x70020000, // 006B JMP #006D + 0x90022111, // 006C SETMBR R0 K16 K17 + 0x4C480000, // 006D LDNIL R18 + 0x78460025, // 006E JMPF R17 #0095 + 0x5C4C0800, // 006F MOVE R19 R4 + 0x5C502000, // 0070 MOVE R20 R16 + 0x7C4C0200, // 0071 CALL R19 1 + 0x50500200, // 0072 LDBOOL R20 1 0 + 0x4C540000, // 0073 LDNIL R21 + 0x1C542615, // 0074 EQ R21 R19 R21 0x78560007, // 0075 JMPF R21 #007E 0x60540001, // 0076 GETGBL R21 G1 0x60580018, // 0077 GETGBL R22 G24 0x585C0012, // 0078 LDCONST R23 K18 - 0x5C602200, // 0079 MOVE R24 R17 - 0x5C642600, // 007A MOVE R25 R19 - 0x7C580600, // 007B CALL R22 3 - 0x7C540200, // 007C CALL R21 1 - 0x50500000, // 007D LDBOOL R20 0 0 - 0x78520003, // 007E JMPF R20 #0083 - 0x5C540C00, // 007F MOVE R21 R6 - 0x5C582200, // 0080 MOVE R22 R17 - 0x7C540200, // 0081 CALL R21 1 - 0x5C482A00, // 0082 MOVE R18 R21 - 0x4C540000, // 0083 LDNIL R21 - 0x1C542415, // 0084 EQ R21 R18 R21 - 0x78560003, // 0085 JMPF R21 #008A - 0x5C540A00, // 0086 MOVE R21 R5 - 0x5C582200, // 0087 MOVE R22 R17 - 0x7C540200, // 0088 CALL R21 1 - 0x503C0000, // 0089 LDBOOL R15 0 0 - 0x783A0006, // 008A JMPF R14 #0092 - 0x4C4C0000, // 008B LDNIL R19 - 0x1C4C2413, // 008C EQ R19 R18 R19 - 0x784E0003, // 008D JMPF R19 #0092 - 0x5C4C0C00, // 008E MOVE R19 R6 - 0x5C500200, // 008F MOVE R20 R1 - 0x7C4C0200, // 0090 CALL R19 1 - 0x5C482600, // 0091 MOVE R18 R19 - 0x4C4C0000, // 0092 LDNIL R19 - 0x204C2413, // 0093 NE R19 R18 R19 - 0x784E0015, // 0094 JMPF R19 #00AB - 0x5C4C1E00, // 0095 MOVE R19 R15 - 0x744E0013, // 0096 JMPT R19 #00AB - 0x5C4C1A00, // 0097 MOVE R19 R13 - 0x744E0011, // 0098 JMPT R19 #00AB - 0xA8020005, // 0099 EXBLK 0 #00A0 - 0x8C4C0113, // 009A GETMET R19 R0 K19 - 0x5C542200, // 009B MOVE R21 R17 - 0x5C582400, // 009C MOVE R22 R18 - 0x7C4C0600, // 009D CALL R19 3 - 0xA8040001, // 009E EXBLK 1 1 - 0x7002000A, // 009F JMP #00AB - 0xAC4C0001, // 00A0 CATCH R19 0 1 - 0x70020007, // 00A1 JMP #00AA - 0x60500001, // 00A2 GETGBL R20 G1 - 0x60540018, // 00A3 GETGBL R21 G24 - 0x58580014, // 00A4 LDCONST R22 K20 - 0x5C5C2200, // 00A5 MOVE R23 R17 - 0x5C602600, // 00A6 MOVE R24 R19 - 0x7C540600, // 00A7 CALL R21 3 - 0x7C500200, // 00A8 CALL R20 1 - 0x70020000, // 00A9 JMP #00AB - 0xB0080000, // 00AA RAISE 2 R0 R0 - 0x5C4C0E00, // 00AB MOVE R19 R7 - 0x5C502400, // 00AC MOVE R20 R18 - 0x7C4C0200, // 00AD CALL R19 1 - 0x78360002, // 00AE JMPF R13 #00B2 - 0x5C500600, // 00AF MOVE R20 R3 - 0x00541705, // 00B0 ADD R21 R11 K5 - 0x7C500200, // 00B1 CALL R20 1 - 0xA0000000, // 00B2 CLOSE R0 - 0x80042600, // 00B3 RET 1 R19 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: next_cron -********************************************************************/ -be_local_closure(Tasmota_next_cron, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str(_crons), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str(size), - /* K3 */ be_nested_str(id), - /* K4 */ be_nested_str(trig), - /* K5 */ be_const_int(1), - }), - &be_const_str_next_cron, - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A000D, // 0001 JMPF R2 #0010 - 0x580C0001, // 0002 LDCONST R3 K1 - 0x8C100502, // 0003 GETMET R4 R2 K2 - 0x7C100200, // 0004 CALL R4 1 - 0x14100604, // 0005 LT R4 R3 R4 - 0x78120008, // 0006 JMPF R4 #0010 - 0x94100403, // 0007 GETIDX R4 R2 R3 - 0x88100903, // 0008 GETMBR R4 R4 K3 - 0x1C100801, // 0009 EQ R4 R4 R1 - 0x78120002, // 000A JMPF R4 #000E - 0x94100403, // 000B GETIDX R4 R2 R3 - 0x88100904, // 000C GETMBR R4 R4 K4 - 0x80040800, // 000D RET 1 R4 - 0x000C0705, // 000E ADD R3 R3 K5 - 0x7001FFF2, // 000F JMP #0003 - 0x80000000, // 0010 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: time_str -********************************************************************/ -be_local_closure(Tasmota_time_str, /* name */ - be_nested_proto( - 11, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str(time_dump), - /* K1 */ be_nested_str(_X2504d_X2D_X2502d_X2D_X2502dT_X2502d_X3A_X2502d_X3A_X2502d), - /* K2 */ be_nested_str(year), - /* K3 */ be_nested_str(month), - /* K4 */ be_nested_str(day), - /* K5 */ be_nested_str(hour), - /* K6 */ be_nested_str(min), - /* K7 */ be_nested_str(sec), - }), - &be_const_str_time_str, - &be_const_str_solidified, - ( &(const binstruction[13]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x5C100200, // 0001 MOVE R4 R1 - 0x7C080400, // 0002 CALL R2 2 - 0x600C0018, // 0003 GETGBL R3 G24 - 0x58100001, // 0004 LDCONST R4 K1 - 0x94140502, // 0005 GETIDX R5 R2 K2 - 0x94180503, // 0006 GETIDX R6 R2 K3 - 0x941C0504, // 0007 GETIDX R7 R2 K4 - 0x94200505, // 0008 GETIDX R8 R2 K5 - 0x94240506, // 0009 GETIDX R9 R2 K6 - 0x94280507, // 000A GETIDX R10 R2 K7 - 0x7C0C0E00, // 000B CALL R3 7 - 0x80040600, // 000C RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: exec_rules -********************************************************************/ -be_local_closure(Tasmota_exec_rules, /* name */ - be_nested_proto( - 14, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[12]) { /* constants */ - /* K0 */ be_nested_str(cmd_res), - /* K1 */ be_nested_str(_rules), - /* K2 */ be_nested_str(json), - /* K3 */ be_nested_str(load), - /* K4 */ be_nested_str(log), - /* K5 */ be_nested_str(BRY_X3A_X20ERROR_X2C_X20bad_X20json_X3A_X20), - /* K6 */ be_const_int(3), - /* K7 */ be_const_int(0), - /* K8 */ be_nested_str(try_rule), - /* K9 */ be_nested_str(trig), - /* K10 */ be_nested_str(f), - /* K11 */ be_const_int(1), - }), - &be_const_str_exec_rules, - &be_const_str_solidified, - ( &(const binstruction[50]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x88100101, // 0001 GETMBR R4 R0 K1 - 0x74120002, // 0002 JMPT R4 #0006 - 0x4C100000, // 0003 LDNIL R4 - 0x20100604, // 0004 NE R4 R3 R4 - 0x78120029, // 0005 JMPF R4 #0030 - 0xA4120400, // 0006 IMPORT R4 K2 - 0x4C140000, // 0007 LDNIL R5 - 0x90020005, // 0008 SETMBR R0 K0 R5 - 0x50140000, // 0009 LDBOOL R5 0 0 - 0x8C180903, // 000A GETMET R6 R4 K3 - 0x5C200200, // 000B MOVE R8 R1 - 0x7C180400, // 000C CALL R6 2 - 0x4C1C0000, // 000D LDNIL R7 - 0x1C1C0C07, // 000E EQ R7 R6 R7 - 0x781E0004, // 000F JMPF R7 #0015 - 0x8C1C0104, // 0010 GETMET R7 R0 K4 - 0x00260A01, // 0011 ADD R9 K5 R1 - 0x58280006, // 0012 LDCONST R10 K6 - 0x7C1C0600, // 0013 CALL R7 3 - 0x5C180200, // 0014 MOVE R6 R1 - 0x780A0014, // 0015 JMPF R2 #002B - 0x881C0101, // 0016 GETMBR R7 R0 K1 - 0x781E0012, // 0017 JMPF R7 #002B - 0x581C0007, // 0018 LDCONST R7 K7 - 0x6020000C, // 0019 GETGBL R8 G12 - 0x88240101, // 001A GETMBR R9 R0 K1 - 0x7C200200, // 001B CALL R8 1 - 0x14200E08, // 001C LT R8 R7 R8 - 0x7822000C, // 001D JMPF R8 #002B - 0x88200101, // 001E GETMBR R8 R0 K1 - 0x94201007, // 001F GETIDX R8 R8 R7 - 0x8C240108, // 0020 GETMET R9 R0 K8 - 0x5C2C0C00, // 0021 MOVE R11 R6 - 0x88301109, // 0022 GETMBR R12 R8 K9 - 0x8834110A, // 0023 GETMBR R13 R8 K10 - 0x7C240800, // 0024 CALL R9 4 - 0x74260001, // 0025 JMPT R9 #0028 - 0x74160000, // 0026 JMPT R5 #0028 - 0x50140001, // 0027 LDBOOL R5 0 1 - 0x50140200, // 0028 LDBOOL R5 1 0 - 0x001C0F0B, // 0029 ADD R7 R7 K11 - 0x7001FFED, // 002A JMP #0019 - 0x4C1C0000, // 002B LDNIL R7 - 0x201C0607, // 002C NE R7 R3 R7 - 0x781E0000, // 002D JMPF R7 #002F - 0x90020006, // 002E SETMBR R0 K0 R6 - 0x80040A00, // 002F RET 1 R5 - 0x50100000, // 0030 LDBOOL R4 0 0 - 0x80040800, // 0031 RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: add_rule -********************************************************************/ -be_local_closure(Tasmota_add_rule, /* name */ - be_nested_proto( - 10, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_nested_str(check_not_method), - /* K1 */ be_nested_str(_rules), - /* K2 */ be_nested_str(function), - /* K3 */ be_nested_str(push), - /* K4 */ be_nested_str(Trigger), - /* K5 */ be_nested_str(Rule_Matcher), - /* K6 */ be_nested_str(parse), - /* K7 */ be_nested_str(value_error), - /* K8 */ be_nested_str(the_X20second_X20argument_X20is_X20not_X20a_X20function), - }), - &be_const_str_add_rule, - &be_const_str_solidified, - ( &(const binstruction[29]) { /* code */ - 0x8C100100, // 0000 GETMET R4 R0 K0 - 0x5C180400, // 0001 MOVE R6 R2 - 0x7C100400, // 0002 CALL R4 2 - 0x88100101, // 0003 GETMBR R4 R0 K1 - 0x4C140000, // 0004 LDNIL R5 - 0x1C100805, // 0005 EQ R4 R4 R5 - 0x78120002, // 0006 JMPF R4 #000A - 0x60100012, // 0007 GETGBL R4 G18 - 0x7C100000, // 0008 CALL R4 0 - 0x90020204, // 0009 SETMBR R0 K1 R4 - 0x60100004, // 000A GETGBL R4 G4 - 0x5C140400, // 000B MOVE R5 R2 - 0x7C100200, // 000C CALL R4 1 - 0x1C100902, // 000D EQ R4 R4 K2 - 0x7812000B, // 000E JMPF R4 #001B - 0x88100101, // 000F GETMBR R4 R0 K1 - 0x8C100903, // 0010 GETMET R4 R4 K3 - 0xB81A0800, // 0011 GETNGBL R6 K4 - 0x881C0105, // 0012 GETMBR R7 R0 K5 - 0x8C1C0F06, // 0013 GETMET R7 R7 K6 - 0x5C240200, // 0014 MOVE R9 R1 - 0x7C1C0400, // 0015 CALL R7 2 - 0x5C200400, // 0016 MOVE R8 R2 - 0x5C240600, // 0017 MOVE R9 R3 - 0x7C180600, // 0018 CALL R6 3 - 0x7C100400, // 0019 CALL R4 2 - 0x70020000, // 001A JMP #001C - 0xB0060F08, // 001B RAISE 1 K7 K8 - 0x80000000, // 001C RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: gc -********************************************************************/ -be_local_closure(Tasmota_gc, /* name */ - be_nested_proto( - 4, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(gc), - /* K1 */ be_nested_str(collect), - /* K2 */ be_nested_str(allocated), - }), - &be_const_str_gc, - &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080301, // 0001 GETMET R2 R1 K1 - 0x7C080200, // 0002 CALL R2 1 - 0x8C080302, // 0003 GETMET R2 R1 K2 - 0x7C080200, // 0004 CALL R2 1 - 0x80040400, // 0005 RET 1 R2 + 0x5C602000, // 0079 MOVE R24 R16 + 0x7C580400, // 007A CALL R22 2 + 0x7C540200, // 007B CALL R21 1 + 0x50500000, // 007C LDBOOL R20 0 0 + 0x7002000A, // 007D JMP #0089 + 0x54560003, // 007E LDINT R21 4 + 0x20542615, // 007F NE R21 R19 R21 + 0x78560007, // 0080 JMPF R21 #0089 + 0x60540001, // 0081 GETGBL R21 G1 + 0x60580018, // 0082 GETGBL R22 G24 + 0x585C0013, // 0083 LDCONST R23 K19 + 0x5C602000, // 0084 MOVE R24 R16 + 0x5C642600, // 0085 MOVE R25 R19 + 0x7C580600, // 0086 CALL R22 3 + 0x7C540200, // 0087 CALL R21 1 + 0x50500000, // 0088 LDBOOL R20 0 0 + 0x78520003, // 0089 JMPF R20 #008E + 0x5C540C00, // 008A MOVE R21 R6 + 0x5C582000, // 008B MOVE R22 R16 + 0x7C540200, // 008C CALL R21 1 + 0x5C482A00, // 008D MOVE R18 R21 + 0x4C540000, // 008E LDNIL R21 + 0x1C542415, // 008F EQ R21 R18 R21 + 0x78560003, // 0090 JMPF R21 #0095 + 0x5C540A00, // 0091 MOVE R21 R5 + 0x5C582000, // 0092 MOVE R22 R16 + 0x7C540200, // 0093 CALL R21 1 + 0x50440000, // 0094 LDBOOL R17 0 0 + 0x5C4C2200, // 0095 MOVE R19 R17 + 0x744E0003, // 0096 JMPT R19 #009B + 0x5C4C0C00, // 0097 MOVE R19 R6 + 0x5C500200, // 0098 MOVE R20 R1 + 0x7C4C0200, // 0099 CALL R19 1 + 0x5C482600, // 009A MOVE R18 R19 + 0x5C4C0E00, // 009B MOVE R19 R7 + 0x5C502400, // 009C MOVE R20 R18 + 0x7C4C0200, // 009D CALL R19 1 + 0x782E0002, // 009E JMPF R11 #00A2 + 0x5C500600, // 009F MOVE R20 R3 + 0x00541906, // 00A0 ADD R21 R12 K6 + 0x7C500200, // 00A1 CALL R20 1 + 0xA0000000, // 00A2 CLOSE R0 + 0x80042600, // 00A3 RET 1 R19 }) ) ); @@ -2406,275 +2716,65 @@ be_local_closure(Tasmota_urlfetch_cmd, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: add_fast_loop -********************************************************************/ -be_local_closure(Tasmota_add_fast_loop, /* name */ - be_nested_proto( - 5, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_nested_str(check_not_method), - /* K1 */ be_nested_str(_fl), - /* K2 */ be_nested_str(function), - /* K3 */ be_nested_str(value_error), - /* K4 */ be_nested_str(argument_X20must_X20be_X20a_X20function), - /* K5 */ be_nested_str(global), - /* K6 */ be_nested_str(fast_loop_enabled), - /* K7 */ be_const_int(1), - /* K8 */ be_nested_str(push), - }), - &be_const_str_add_fast_loop, - &be_const_str_solidified, - ( &(const binstruction[23]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x5C100200, // 0001 MOVE R4 R1 - 0x7C080400, // 0002 CALL R2 2 - 0x88080101, // 0003 GETMBR R2 R0 K1 - 0x4C0C0000, // 0004 LDNIL R3 - 0x1C080403, // 0005 EQ R2 R2 R3 - 0x780A0002, // 0006 JMPF R2 #000A - 0x60080012, // 0007 GETGBL R2 G18 - 0x7C080000, // 0008 CALL R2 0 - 0x90020202, // 0009 SETMBR R0 K1 R2 - 0x60080004, // 000A GETGBL R2 G4 - 0x5C0C0200, // 000B MOVE R3 R1 - 0x7C080200, // 000C CALL R2 1 - 0x20080502, // 000D NE R2 R2 K2 - 0x780A0000, // 000E JMPF R2 #0010 - 0xB0060704, // 000F RAISE 1 K3 K4 - 0x88080105, // 0010 GETMBR R2 R0 K5 - 0x900A0D07, // 0011 SETMBR R2 K6 K7 - 0x88080101, // 0012 GETMBR R2 R0 K1 - 0x8C080508, // 0013 GETMET R2 R2 K8 - 0x5C100200, // 0014 MOVE R4 R1 - 0x7C080400, // 0015 CALL R2 2 - 0x80000000, // 0016 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: run_deferred -********************************************************************/ -be_local_closure(Tasmota_run_deferred, /* name */ - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str(_timers), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str(size), - /* K3 */ be_nested_str(time_reached), - /* K4 */ be_nested_str(trig), - /* K5 */ be_nested_str(f), - /* K6 */ be_nested_str(remove), - /* K7 */ be_const_int(1), - }), - &be_const_str_run_deferred, - &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x78060015, // 0001 JMPF R1 #0018 - 0x58040001, // 0002 LDCONST R1 K1 - 0x88080100, // 0003 GETMBR R2 R0 K0 - 0x8C080502, // 0004 GETMET R2 R2 K2 - 0x7C080200, // 0005 CALL R2 1 - 0x14080202, // 0006 LT R2 R1 R2 - 0x780A000F, // 0007 JMPF R2 #0018 - 0x88080100, // 0008 GETMBR R2 R0 K0 - 0x94080401, // 0009 GETIDX R2 R2 R1 - 0x8C0C0103, // 000A GETMET R3 R0 K3 - 0x88140504, // 000B GETMBR R5 R2 K4 - 0x7C0C0400, // 000C CALL R3 2 - 0x780E0007, // 000D JMPF R3 #0016 - 0x880C0505, // 000E GETMBR R3 R2 K5 - 0x88100100, // 000F GETMBR R4 R0 K0 - 0x8C100906, // 0010 GETMET R4 R4 K6 - 0x5C180200, // 0011 MOVE R6 R1 - 0x7C100400, // 0012 CALL R4 2 - 0x5C100600, // 0013 MOVE R4 R3 - 0x7C100000, // 0014 CALL R4 0 - 0x70020000, // 0015 JMP #0017 - 0x00040307, // 0016 ADD R1 R1 K7 - 0x7001FFEA, // 0017 JMP #0003 - 0x80000000, // 0018 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: hs2rgb -********************************************************************/ -be_local_closure(Tasmota_hs2rgb, /* name */ - be_nested_proto( - 17, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str(tasmota), - /* K2 */ be_nested_str(scale_uint), - /* K3 */ be_const_int(1), - /* K4 */ be_const_int(2), - /* K5 */ be_const_int(3), - }), - &be_const_str_hs2rgb, - &be_const_str_solidified, - ( &(const binstruction[68]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x1C0C0403, // 0001 EQ R3 R2 R3 - 0x780E0000, // 0002 JMPF R3 #0004 - 0x540A00FE, // 0003 LDINT R2 255 - 0x540E00FE, // 0004 LDINT R3 255 - 0x541200FE, // 0005 LDINT R4 255 - 0x541600FE, // 0006 LDINT R5 255 - 0x541A0167, // 0007 LDINT R6 360 - 0x10040206, // 0008 MOD R1 R1 R6 - 0x24180500, // 0009 GT R6 R2 K0 - 0x781A0031, // 000A JMPF R6 #003D - 0x541A003B, // 000B LDINT R6 60 - 0x0C180206, // 000C DIV R6 R1 R6 - 0x541E003B, // 000D LDINT R7 60 - 0x101C0207, // 000E MOD R7 R1 R7 - 0x542200FE, // 000F LDINT R8 255 - 0x04201002, // 0010 SUB R8 R8 R2 - 0xB8260200, // 0011 GETNGBL R9 K1 - 0x8C241302, // 0012 GETMET R9 R9 K2 - 0x5C2C0E00, // 0013 MOVE R11 R7 - 0x58300000, // 0014 LDCONST R12 K0 - 0x5436003B, // 0015 LDINT R13 60 - 0x543A00FE, // 0016 LDINT R14 255 - 0x5C3C1000, // 0017 MOVE R15 R8 - 0x7C240C00, // 0018 CALL R9 6 - 0xB82A0200, // 0019 GETNGBL R10 K1 - 0x8C281502, // 001A GETMET R10 R10 K2 - 0x5C300E00, // 001B MOVE R12 R7 - 0x58340000, // 001C LDCONST R13 K0 - 0x543A003B, // 001D LDINT R14 60 - 0x5C3C1000, // 001E MOVE R15 R8 - 0x544200FE, // 001F LDINT R16 255 - 0x7C280C00, // 0020 CALL R10 6 - 0x1C2C0D00, // 0021 EQ R11 R6 K0 - 0x782E0002, // 0022 JMPF R11 #0026 - 0x5C141400, // 0023 MOVE R5 R10 - 0x5C101000, // 0024 MOVE R4 R8 - 0x70020016, // 0025 JMP #003D - 0x1C2C0D03, // 0026 EQ R11 R6 K3 - 0x782E0002, // 0027 JMPF R11 #002B - 0x5C0C1200, // 0028 MOVE R3 R9 - 0x5C101000, // 0029 MOVE R4 R8 - 0x70020011, // 002A JMP #003D - 0x1C2C0D04, // 002B EQ R11 R6 K4 - 0x782E0002, // 002C JMPF R11 #0030 - 0x5C0C1000, // 002D MOVE R3 R8 - 0x5C101400, // 002E MOVE R4 R10 - 0x7002000C, // 002F JMP #003D - 0x1C2C0D05, // 0030 EQ R11 R6 K5 - 0x782E0002, // 0031 JMPF R11 #0035 - 0x5C0C1000, // 0032 MOVE R3 R8 - 0x5C141200, // 0033 MOVE R5 R9 - 0x70020007, // 0034 JMP #003D - 0x542E0003, // 0035 LDINT R11 4 - 0x1C2C0C0B, // 0036 EQ R11 R6 R11 - 0x782E0002, // 0037 JMPF R11 #003B - 0x5C0C1400, // 0038 MOVE R3 R10 - 0x5C141000, // 0039 MOVE R5 R8 - 0x70020001, // 003A JMP #003D - 0x5C141000, // 003B MOVE R5 R8 - 0x5C101200, // 003C MOVE R4 R9 - 0x541A000F, // 003D LDINT R6 16 - 0x38180606, // 003E SHL R6 R3 R6 - 0x541E0007, // 003F LDINT R7 8 - 0x381C0A07, // 0040 SHL R7 R5 R7 - 0x30180C07, // 0041 OR R6 R6 R7 - 0x30180C04, // 0042 OR R6 R6 R4 - 0x80040C00, // 0043 RET 1 R6 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Tasmota ********************************************************************/ be_local_class(Tasmota, 13, NULL, - be_nested_map(50, + be_nested_map(51, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key(hs2rgb, 34), be_const_closure(Tasmota_hs2rgb_closure) }, - { be_const_key(gen_cb, 22), be_const_closure(Tasmota_gen_cb_closure) }, - { be_const_key(fast_loop, 44), be_const_closure(Tasmota_fast_loop_closure) }, - { be_const_key(remove_fast_loop, -1), be_const_closure(Tasmota_remove_fast_loop_closure) }, - { be_const_key(global, -1), be_const_var(9) }, - { be_const_key(try_rule, 17), be_const_closure(Tasmota_try_rule_closure) }, - { be_const_key(wd, -1), be_const_var(11) }, - { be_const_key(check_not_method, -1), be_const_closure(Tasmota_check_not_method_closure) }, - { be_const_key(run_deferred, -1), be_const_closure(Tasmota_run_deferred_closure) }, - { be_const_key(exec_cmd, -1), be_const_closure(Tasmota_exec_cmd_closure) }, - { be_const_key(urlfetch, -1), be_const_closure(Tasmota_urlfetch_closure) }, + { be_const_key(cmd, -1), be_const_closure(Tasmota_cmd_closure) }, + { be_const_key(wd, 47), be_const_var(11) }, + { be_const_key(_crons, 13), be_const_var(3) }, { be_const_key(urlfetch_cmd, -1), be_const_closure(Tasmota_urlfetch_cmd_closure) }, - { be_const_key(remove_cron, 24), be_const_closure(Tasmota_remove_cron_closure) }, - { be_const_key(find_list_i, 23), be_const_closure(Tasmota_find_list_i_closure) }, + { be_const_key(load, -1), be_const_closure(Tasmota_load_closure) }, + { be_const_key(global, -1), be_const_var(9) }, + { be_const_key(event, -1), be_const_closure(Tasmota_event_closure) }, + { be_const_key(exec_cmd, 12), be_const_closure(Tasmota_exec_cmd_closure) }, + { be_const_key(remove_cron, -1), be_const_closure(Tasmota_remove_cron_closure) }, + { be_const_key(hs2rgb, 21), be_const_closure(Tasmota_hs2rgb_closure) }, + { be_const_key(remove_driver, 30), be_const_closure(Tasmota_remove_driver_closure) }, + { be_const_key(add_driver, -1), be_const_closure(Tasmota_add_driver_closure) }, + { be_const_key(remove_cmd, -1), be_const_closure(Tasmota_remove_cmd_closure) }, { be_const_key(gc, -1), be_const_closure(Tasmota_gc_closure) }, - { be_const_key(remove_timer, -1), be_const_closure(Tasmota_remove_timer_closure) }, - { be_const_key(_timers, -1), be_const_var(2) }, - { be_const_key(init, 48), be_const_closure(Tasmota_init_closure) }, - { be_const_key(remove_driver, -1), be_const_closure(Tasmota_remove_driver_closure) }, - { be_const_key(wire1, -1), be_const_var(6) }, - { be_const_key(_fl, -1), be_const_var(0) }, - { be_const_key(add_driver, 14), be_const_closure(Tasmota_add_driver_closure) }, - { be_const_key(exec_tele, -1), be_const_closure(Tasmota_exec_tele_closure) }, - { be_const_key(_ccmd, -1), be_const_var(4) }, - { be_const_key(time_str, 36), be_const_closure(Tasmota_time_str_closure) }, - { be_const_key(_debug_present, -1), be_const_var(12) }, - { be_const_key(find_key_i, 31), be_const_closure(Tasmota_find_key_i_closure) }, - { be_const_key(add_cron, -1), be_const_closure(Tasmota_add_cron_closure) }, - { be_const_key(remove_rule, 6), be_const_closure(Tasmota_remove_rule_closure) }, - { be_const_key(add_cmd, 39), be_const_closure(Tasmota_add_cmd_closure) }, - { be_const_key(wire_scan, -1), be_const_closure(Tasmota_wire_scan_closure) }, - { be_const_key(get_light, 40), be_const_closure(Tasmota_get_light_closure) }, - { be_const_key(cmd, 9), be_const_closure(Tasmota_cmd_closure) }, - { be_const_key(set_timer, 11), be_const_closure(Tasmota_set_timer_closure) }, - { be_const_key(load, 32), be_const_closure(Tasmota_load_closure) }, - { be_const_key(_drivers, -1), be_const_var(5) }, + { be_const_key(_fl, 25), be_const_var(0) }, + { be_const_key(init, -1), be_const_closure(Tasmota_init_closure) }, + { be_const_key(_drivers, 48), be_const_var(5) }, + { be_const_key(try_rule, -1), be_const_closure(Tasmota_try_rule_closure) }, + { be_const_key(get_light, -1), be_const_closure(Tasmota_get_light_closure) }, { be_const_key(cmd_res, -1), be_const_var(8) }, - { be_const_key(next_cron, -1), be_const_closure(Tasmota_next_cron_closure) }, - { be_const_key(wire2, -1), be_const_var(7) }, - { be_const_key(_crons, -1), be_const_var(3) }, - { be_const_key(find_op, 41), be_const_closure(Tasmota_find_op_closure) }, + { be_const_key(exec_rules, -1), be_const_closure(Tasmota_exec_rules_closure) }, + { be_const_key(_ccmd, -1), be_const_var(4) }, + { be_const_key(find_list_i, 33), be_const_closure(Tasmota_find_list_i_closure) }, + { be_const_key(remove_fast_loop, -1), be_const_closure(Tasmota_remove_fast_loop_closure) }, + { be_const_key(check_not_method, 20), be_const_closure(Tasmota_check_not_method_closure) }, + { be_const_key(exec_tele, -1), be_const_closure(Tasmota_exec_tele_closure) }, + { be_const_key(run_deferred, -1), be_const_closure(Tasmota_run_deferred_closure) }, + { be_const_key(compile, -1), be_const_closure(Tasmota_compile_closure) }, + { be_const_key(wire2, 42), be_const_var(7) }, + { be_const_key(remove_rule, 34), be_const_closure(Tasmota_remove_rule_closure) }, + { be_const_key(set_timer, -1), be_const_closure(Tasmota_set_timer_closure) }, + { be_const_key(gen_cb, -1), be_const_closure(Tasmota_gen_cb_closure) }, + { be_const_key(wire1, -1), be_const_var(6) }, + { be_const_key(wire_scan, -1), be_const_closure(Tasmota_wire_scan_closure) }, + { be_const_key(find_key_i, -1), be_const_closure(Tasmota_find_key_i_closure) }, + { be_const_key(urlfetch, -1), be_const_closure(Tasmota_urlfetch_closure) }, + { be_const_key(_debug_present, 9), be_const_var(12) }, { be_const_key(settings, -1), be_const_var(10) }, - { be_const_key(exec_rules, 20), be_const_closure(Tasmota_exec_rules_closure) }, + { be_const_key(fast_loop, -1), be_const_closure(Tasmota_fast_loop_closure) }, + { be_const_key(next_cron, 31), be_const_closure(Tasmota_next_cron_closure) }, + { be_const_key(_rules, 8), be_const_var(1) }, + { be_const_key(time_str, -1), be_const_closure(Tasmota_time_str_closure) }, + { be_const_key(remove_timer, -1), be_const_closure(Tasmota_remove_timer_closure) }, + { be_const_key(add_fast_loop, -1), be_const_closure(Tasmota_add_fast_loop_closure) }, + { be_const_key(run_cron, 18), be_const_closure(Tasmota_run_cron_closure) }, + { be_const_key(add_cron, -1), be_const_closure(Tasmota_add_cron_closure) }, + { be_const_key(_timers, -1), be_const_var(2) }, + { be_const_key(find_op, -1), be_const_closure(Tasmota_find_op_closure) }, { be_const_key(add_rule, -1), be_const_closure(Tasmota_add_rule_closure) }, - { be_const_key(remove_cmd, 45), be_const_closure(Tasmota_remove_cmd_closure) }, - { be_const_key(set_light, -1), be_const_closure(Tasmota_set_light_closure) }, - { be_const_key(add_fast_loop, 8), be_const_closure(Tasmota_add_fast_loop_closure) }, - { be_const_key(_rules, -1), be_const_var(1) }, - { be_const_key(run_cron, 47), be_const_closure(Tasmota_run_cron_closure) }, - { be_const_key(event, 0), be_const_closure(Tasmota_event_closure) }, + { be_const_key(add_cmd, 4), be_const_closure(Tasmota_add_cmd_closure) }, + { be_const_key(set_light, 3), be_const_closure(Tasmota_set_light_closure) }, })), (bstring*) &be_const_str_Tasmota ); diff --git a/lib/libesp32_div/NimBLE-Arduino/.gitignore b/lib/libesp32_div/NimBLE-Arduino/.gitignore deleted file mode 100644 index 111405a1c..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/.gitignore +++ /dev/null @@ -1 +0,0 @@ -docs/doxydocs diff --git a/lib/libesp32_div/NimBLE-Arduino/CHANGELOG.md b/lib/libesp32_div/NimBLE-Arduino/CHANGELOG.md deleted file mode 100644 index 43fbc62cf..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/CHANGELOG.md +++ /dev/null @@ -1,311 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -## [1.4.1] - 2022-10-23 - -### Fixed - - Compile warning removed for esp32c3 - - NimBLEDevice::getPower incorrect value when power level is -3db. - - Failed pairing when already in progress. - -### Changed - - Revert previous change that forced writing with response when subscribing in favor of allowing the application to decide. - -### Added - - Added NimBLEHIDDevice::batteryLevel. - - Added NimBLEDevice::setDeviceName allowing for changing the device name while the BLE stack is active. - - CI build tests. - - Missing items in CHANGELOG that were not recorded correctly - -## [1.4.0] - 2022-07-10 - -### Fixed -- Fixed missing data from long notification values. -- Fixed NimbleCharacteristicCallbacks::onRead not being called when a non-long read command is received. - -### Changed -- Updated NimBLE core to use the v1.4.0 branch of esp-nimble. -- AD flags are no longer set in the advertisements of non-connectable beacons, freeing up 3 bytes of advertisement room. -- Config option CONFIG_BT_NIMBLE_DEBUG replaced with CONFIG_BT_NIMBLE_LOG_LEVEL (see src/nimconfig.h for usage) -- Config option CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT renamed to CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT -- Config option CONFIG_BT_NIMBLE_TASK_STACK_SIZE renamed to CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE - -### Added -- Preliminary support for non-esp devices, NRF51 and NRF52 devices supported with [n-able arduino core](https://github.com/h2zero/n-able-Arduino) -- Alias added for `NimBLEServerCallbacks::onMTUChange` to `onMtuChanged` in order to support porting code from original library. -- `NimBLEAttValue` Class added to reduce and control RAM footprint of characteristic/descriptor values and support conversions from Arduino Strings and many other data types. -- Bluetooth 5 extended advertising support for capable devices. CODED Phy, 2M Phy, extended advertising data, and multi-advertising are supported, periodic advertising will be implemented in the future. - -## [1.3.8] - 2022-04-27 - -### Fixed -- Fix compile error with ESP32S3. -- Prevent a potential crash when retrieving characteristics from a service if the result was successful but no characteristics found. - -### Changed -- Save resources when retrieving descriptors if the characteristic handle is the same as the end handle (no descriptors). -- Subscribing to characteristic notifications/indications will now always use write with response, as per BLE specifications. -- `NimBLEClient::discoverAttributes` now returns a bool value to indicate success/failure - -## [1.3.7] - 2022-02-15 - -### Fixed - -- Crash when retrieving an attribute that does not exist on the peer. -- Memory leak when deleting client instances. -- Compilation errors for esp32s3 - -## [1.3.6] - 2022-01-18 - -### Changed -- When retrieving attributes from a server fails with a 128bit UUID containing the ble base UUID another attempt will be made with the 16bit version of the UUID. - -### Fixed -- Memory leak when services are changed on server devices. -- Rare crashing that occurs when BLE commands are sent from ISR context using IPC. -- Crashing caused by uninitialized disconnect timer in client. -- Potential crash due to uninitialized advertising callback pointer. - -## [1.3.5] - 2022-01-14 - -### Added -- CONFIG_NIMBLE_CPP_DEBUG_LEVEL macro in nimconfig.h to allow setting the log level separately from the Arduino core log level. - -### Fixed -- Memory leak when initializing/deinitializing the BLE stack caused by new FreeRTOS timers be created on each initialization. - -## [1.3.4] - 2022-01-09 - -### Fixed -- Workaround for latest Arduino-esp32 core that causes tasks not to block when required, which caused functions to return prematurely resulting in exceptions/crashing. -- The wrong length value was being used to set the values read from peer attributes. This has been corrected to use the proper value size. - -## [1.3.3] - 2021-11-24 - -### Fixed -- Workaround added for FreeRTOS bug that affected timers, causing scan and advertising timer expirations to not correctly trigger callbacks. - -## [1.3.2] - 2021-11-20 - -### Fixed -- Added missing macros for scan filter. - -### Added -- `NimBLEClient::getLastError` : Gets the error code of the last function call that produces a return code from the stack. - -## [1.3.1] - 2021-08-04 - -### Fixed -- Corrected a compiler/linker error when an application or a library uses bluetooth classic due to the redefinition of `btInUse`. - -## [1.3.0] - 2021-08-02 - -### Added -- `NimBLECharacteristic::removeDescriptor`: Dynamically remove a descriptor from a characteristic. Takes effect after all connections are closed and sends a service changed indication. -- `NimBLEService::removeCharacteristic`: Dynamically remove a characteristic from a service. Takes effect after all connections are closed and sends a service changed indication -- `NimBLEServerCallbacks::onMTUChange`: This is callback is called when the MTU is updated after connection with a client. -- ESP32C3 support - -- Whitelist API: - - `NimBLEDevice::whiteListAdd`: Add a device to the whitelist. - - `NimBLEDevice::whiteListRemove`: Remove a device from the whitelist. - - `NimBLEDevice::onWhiteList`: Check if the device is on the whitelist. - - `NimBLEDevice::getWhiteListCount`: Gets the size of the whitelist - - `NimBLEDevice::getWhiteListAddress`: Get the address of a device on the whitelist by index value. - -- Bond management API: - - `NimBLEDevice::getNumBonds`: Gets the number of bonds stored. - - `NimBLEDevice::isBonded`: Checks if the device is bonded. - - `NimBLEDevice::deleteAllBonds`: Deletes all bonds. - - `NimBLEDevice::getBondedAddress`: Gets the address of a bonded device by the index value. - -- `NimBLECharacteristic::getCallbacks` to retrieve the current callback handler. -- Connection Information class: `NimBLEConnInfo`. -- `NimBLEScan::clearDuplicateCache`: This can be used to reset the cache of advertised devices so they will be immediately discovered again. - -### Changed -- FreeRTOS files have been removed as they are not used by the library. -- Services, characteristics and descriptors can now be created statically and added after. -- Excess logging and some asserts removed. -- Use ESP_LOGx macros to enable using local log level filtering. - -### Fixed -- `NimBLECharacteristicCallbacks::onSubscribe` Is now called after the connection is added to the vector. -- Corrected bonding failure when reinitializing the BLE stack. -- Writing to a characteristic with a std::string value now correctly writes values with null characters. -- Retrieving remote descriptors now uses the characteristic end handle correctly. -- Missing data in long writes to remote descriptors. -- Hanging on task notification when sending an indication from the characteristic callback. -- BLE controller memory could be released when using Arduino as a component. -- Compile errors with NimBLE release 1.3.0. - -## [1.2.0] - 2021-02-08 - -### Added -- `NimBLECharacteristic::getDescriptorByHandle`: Return the BLE Descriptor for the given handle. - -- `NimBLEDescriptor::getStringValue`: Get the value of this descriptor as a string. - -- `NimBLEServer::getServiceByHandle`: Get a service by its handle. - -- `NimBLEService::getCharacteristicByHandle`: Get a pointer to the characteristic object with the specified handle. - -- `NimBLEService::getCharacteristics`: Get the vector containing pointers to each characteristic associated with this service. -Overloads to get a vector containing pointers to all the characteristics in a service with the UUID. (supports multiple same UUID's in a service) - - `NimBLEService::getCharacteristics(const char *uuid)` - - `NimBLEService::getCharacteristics(const NimBLEUUID &uuid)` - -- `NimBLEAdvertisementData` New methods: - - `NimBLEAdvertisementData::addTxPower`: Adds transmission power to the advertisement. - - `NimBLEAdvertisementData::setPreferredParams`: Adds connection parameters to the advertisement. - - `NimBLEAdvertisementData::setURI`: Adds URI data to the advertisement. - -- `NimBLEAdvertising` New methods: - - `NimBLEAdvertising::setName`: Set the name advertised. - - `NimBLEAdvertising::setManufacturerData`: Adds manufacturer data to the advertisement. - - `NimBLEAdvertising::setURI`: Adds URI data to the advertisement. - - `NimBLEAdvertising::setServiceData`: Adds service data to the advertisement. - - `NimBLEAdvertising::addTxPower`: Adds transmission power to the advertisement. - - `NimBLEAdvertising::reset`: Stops the current advertising and resets the advertising data to the default values. - -- `NimBLEDevice::setScanFilterMode`: Set the controller duplicate filter mode for filtering scanned devices. - -- `NimBLEDevice::setScanDuplicateCacheSize`: Sets the number of advertisements filtered before the cache is reset. - -- `NimBLEScan::setMaxResults`: This allows for setting a maximum number of advertised devices stored in the results vector. - -- `NimBLEAdvertisedDevice` New data retrieval methods added: - - `haveAdvInterval/getAdvInterval`: checks if the interval is advertised / gets the advertisement interval value. - - - `haveConnParams/getMinInterval/getMaxInterval`: checks if the parameters are advertised / get min value / get max value. - - - `haveURI/getURI`: checks if a URI is advertised / gets the URI data. - - - `haveTargetAddress/getTargetAddressCount/getTargetAddress(index)`: checks if a target address is present / gets a count of the addresses targeted / gets the address of the target at index. - -### Changed -- `nimconfig.h` (Arduino) is now easier to use. - -- `NimBLEServer::getServiceByUUID` Now takes an extra parameter of instanceID to support multiple services with the same UUID. - -- `NimBLEService::getCharacteristic` Now takes an extra parameter of instanceID to support multiple characteristics with the same UUID. - -- `NimBLEAdvertising` Transmission power is no longer advertised by default and can be added to the advertisement by calling `NimBLEAdvertising::addTxPower` - -- `NimBLEAdvertising` Custom scan response data can now be used without custom advertisement. - -- `NimBLEScan` Now uses the controller duplicate filter. - -- `NimBLEAdvertisedDevice` Has been refactored to store the complete advertisement payload and no longer parses the data from each advertisement. -Instead the data will be parsed on-demand when the user application asks for specific data. - -### Fixed -- `NimBLEHIDDevice` Characteristics now use encryption, this resolves an issue with communicating with devices requiring encryption for HID devices. - - -## [1.1.0] - 2021-01-20 - -### Added -- `NimBLEDevice::setOwnAddrType` added to enable the use of random and random-resolvable addresses, by asukiaaa - -- New examples for securing and authenticating client/server connections, by mblasee. - -- `NimBLEAdvertising::SetMinPreferred` and `NimBLEAdvertising::SetMinPreferred` re-added. - -- Conditional checks added for command line config options in `nimconfig.h` to support custom configuration in platformio. - -- `NimBLEClient::setValue` Now takes an extra bool parameter `response` to enable the use of write with response (default = false). - -- `NimBLEClient::getCharacteristic(uint16_t handle)` Enabling the use of the characteristic handle to be used to find -the NimBLERemoteCharacteristic object. - -- `NimBLEHIDDevice` class added by wakwak-koba. - -- `NimBLEServerCallbacks::onDisconnect` overloaded callback added to provide a ble_gap_conn_desc parameter for the application -to obtain information about the disconnected client. - -- Conditional checks in `nimconfig.h` for command line defined macros to support platformio config settings. - -### Changed -- `NimBLEAdvertising::start` now returns a bool value to indicate success/failure. - -- Some asserts were removed in `NimBLEAdvertising::start` and replaced with better return code handling and logging. - -- If a host reset event occurs, scanning and advertising will now only be restarted if their previous duration was indefinite. - -- `NimBLERemoteCharacteristic::subscribe` and `NimBLERemoteCharacteristic::registerForNotify` will now set the callback -regardless of the existence of the CCCD and return true unless the descriptor write operation failed. - -- Advertising tx power level is now sent in the advertisement packet instead of scan response. - -- `NimBLEScan` When the scan ends the scan stopped flag is now set before calling the scan complete callback (if used) -this allows the starting of a new scan from the callback function. - -### Fixed -- Sometimes `NimBLEClient::connect` would hang on the task block if no event arrived to unblock. -A time limit has been added to timeout appropriately. - -- When getting descriptors for a characteristic the end handle of the service was used as a proxy for the characteristic end -handle. This would be rejected by some devices and has been changed to use the next characteristic handle as the end when possible. - -- An exception could occur when deleting a client instance if a notification arrived while the attribute vectors were being -deleted. A flag has been added to prevent this. - -- An exception could occur after a host reset event when the host re-synced if the tasks that were stopped during the event did -not finish processing. A yield has been added after re-syncing to allow tasks to finish before proceeding. - -- Occasionally the controller would fail to send a disconnected event causing the client to indicate it is connected -and would be unable to reconnect. A timer has been added to reset the host/controller if it expires. - -- Occasionally the call to start scanning would get stuck in a loop on BLE_HS_EBUSY, this loop has been removed. - -- 16bit and 32bit UUID's in some cases were not discovered or compared correctly if the device -advertised them as 16/32bit but resolved them to 128bits. Both are now checked. - -- `FreeRTOS` compile errors resolved in latest Arduino core and IDF v3.3. - -- Multiple instances of `time()` called inside critical sections caused sporadic crashes, these have been moved out of critical regions. - -- Advertisement type now correctly set when using non-connectable (advertiser only) mode. - -- Advertising payload length correction, now accounts for appearance. - -- (Arduino) Ensure controller mode is set to BLE Only. - - -## [1.0.2] - 2020-09-13 - -### Changed - -- `NimBLEAdvertising::start` Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a -callback that is invoked when advertising ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API). - -- (Arduino) Maximum BLE connections can now be altered by only changing the value of `CONFIG_BT_NIMBLE_MAX_CONNECTIONS` in `nimconfig.h`. -Any changes to the controller max connection settings in `sdkconfig.h` will now have no effect when using this library. - -- (Arduino) Revert the previous change to fix the advertising start delay. Instead a replacement fix that routes all BLE controller commands from -a task running on core 0 (same as the controller) has been implemented. This improves response times and reliability for all BLE functions. - - -## [1.0.1] - 2020-09-02 - -### Added - -- Empty `NimBLEAddress` constructor: `NimBLEAddress()` produces an address of 00:00:00:00:00:00 type 0. -- Documentation of the difference of NimBLEAddress::getNative vs the original bluedroid library. - -### Changed - -- notify_callback typedef is now defined as std::function to enable the use of std::bind to call a class member function. - -### Fixed - -- Fix advertising start delay when first called. - - -## [1.0.0] - 2020-08-22 - -First stable release. - -All the original library functionality is complete and many extras added with full documentation. diff --git a/lib/libesp32_div/NimBLE-Arduino/LICENSE b/lib/libesp32_div/NimBLE-Arduino/LICENSE deleted file mode 100644 index 4abe69699..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/LICENSE +++ /dev/null @@ -1,219 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {2020} {Ryan Powell} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -This product bundles queue.h 8.5, which is available under the "3-clause BSD" -license. For details, see porting/nimble/include/os/queue.h - -This product partly derives from FreeBSD, which is available under the -"3-clause BSD" license. For details, see: - * porting/nimble/src/os_mbuf.c - -This product bundles Gary S. Brown's CRC32 implementation, which is available -under the following license: - COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or - code or tables extracted from it, as desired without restriction. - -This product bundles tinycrypt, which is available under the "3-clause BSD" -license. For details, and bundled files see: - * ext/tinycrypt/LICENSE - -This product partly derives from esp32-snippets; Copyright 2017 Neil Kolban. \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/README.md b/lib/libesp32_div/NimBLE-Arduino/README.md deleted file mode 100644 index 86b28e3f9..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/README.md +++ /dev/null @@ -1,72 +0,0 @@ -[Latest release ![Release Version](https://img.shields.io/github/release/h2zero/NimBLE-Arduino.svg?style=plastic) -![Release Date](https://img.shields.io/github/release-date/h2zero/NimBLE-Arduino.svg?style=plastic)](https://github.com/h2zero/NimBLE-Arduino/releases/latest/) - -Need help? Have questions or suggestions? Join the [![Gitter](https://badges.gitter.im/NimBLE-Arduino/community.svg)](https://gitter.im/NimBLE-Arduino/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) -
- -# NimBLE-Arduino -A fork of the NimBLE stack refactored for compilation in the Ardruino IDE. - -**As of release 1.4.0 Nordic Semiconductor nRF51 and nRF52 series devices are now supported** - -## Supported MCU's - - Espressif: ESP32, ESP32C3, ESP32S3 - - Nordic: nRF51, nRF52 series (**Requires** using [n-able arduino core](https://github.com/h2zero/n-able-Arduino)) - -**Note for ESP-IDF users: This repo will not compile correctly in ESP-IDF. An ESP-IDF component version of this library can be [found here.](https://github.com/h2zero/esp-nimble-cpp)** - -This library **significantly** reduces resource usage and improves performance for ESP32 BLE applications as compared with the bluedroid based library. The goal is to maintain, as much as reasonable, compatibility with the original library but refactored to use the NimBLE stack. In addition, this library will be more actively developed and maintained to provide improved capabilities and stability over the original. -
- -For Nordic devices, this library provides access to a completely open source and configurable BLE stack. No softdevice to work around, allowing for full debugging and resource management, continuous updates, with a cross platform API. - -# Arduino installation -**Arduino Library manager:** Go to `sketch` -> `Include Library` -> `Manage Libraries`, search for NimBLE and install. - -**Alternatively:** Download as .zip and extract to Arduino/libraries folder, or in Arduino IDE from Sketch menu -> Include library -> Add .Zip library. - -`#include "NimBLEDevice.h"` at the beginning of your sketch. - -# Platformio installation -* Open platformio.ini, a project configuration file located in the root of PlatformIO project. -* Add the following line to the lib_deps option of [env:] section: -``` -h2zero/NimBLE-Arduino@^1.4.0 -``` -* Build a project, PlatformIO will automatically install dependencies. - -# Using -This library is intended to be compatible with the original ESP32 BLE functions and types with minor changes. - -If you have not used the original Bluedroid library please refer to the [New user guide](docs/New_user_guide.md). - -If you are familiar with the original library, see: [The migration guide](docs/Migration_guide.md) for details about breaking changes and migration. - -Also see [Improvements_and_updates](docs/Improvements_and_updates.md) for information about non-breaking changes. - -[Full API documentation and class list can be found here.](https://h2zero.github.io/NimBLE-Arduino/) - -For added performance and optimizations see [Usage tips](docs/Usage_tips.md). - -Check the Refactored_original_examples in the examples folder for highlights of the differences with the original library. - -More advanced examples highlighting many available features are in examples/ NimBLE_Server, NimBLE_Client. - -Beacon examples provided by @beegee-tokyo are in examples/ BLE_Beacon_Scanner, BLE_EddystoneTLM_Beacon, BLE_EddystoneURL_Beacon. - -Change the settings in the `src/nimconfig.h` file to customize NimBLE to your project, -such as increasing max connections, default is 3, absolute maximum connections is 9. -
- -# Development Status -This Library is tracking the esp-nimble repo, nimble-1.4.0-idf branch, currently [@3df0d20.](https://github.com/espressif/esp-nimble) - -Also tracking the NimBLE related changes in ESP-IDF, master branch, currently [@95db4bb.](https://github.com/espressif/esp-idf/tree/master/components/bt/host/nimble) -
- -# Acknowledgments -* [nkolban](https://github.com/nkolban) and [chegewara](https://github.com/chegewara) for the [original esp32 BLE library](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils) this project was derived from. -* [beegee-tokyo](https://github.com/beegee-tokyo) for contributing your time to test/debug and contributing the beacon examples. -* [Jeroen88](https://github.com/Jeroen88) for the amazing help debugging and improving the client code. -
- diff --git a/lib/libesp32_div/NimBLE-Arduino/docs/Bluetooth 5 features.md b/lib/libesp32_div/NimBLE-Arduino/docs/Bluetooth 5 features.md deleted file mode 100644 index 3737b0d7e..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/docs/Bluetooth 5 features.md +++ /dev/null @@ -1,28 +0,0 @@ -# Bluetooth 5.x features - -## About extended advertising -Extended advertising allows for much more capability and flexibility. - -* Allows for 251 bytes of advertisement data and up to 1650 bytes when chained (configuration dependant) vs 31. - -* New PHY's (physical layers) that allow for faster data rate (2M PHY) or long range/slower data rates (CODED PHY) as well as the original 1M PHY. - -* New periodic advertising, allowing the scanning device to sync with the advertisements of a beacon. This allows for the scanning device to sleep or perform other tasks before the next expected advertisement is sent, preserving cpu cycles and power (To be implemented). -
- -## Enabling extended advertising -Extended advertising is supported when enabled with the config option `CONFIG_BT_NIMBLE_EXT_ADV` set to a value of 1. This is done in menuconfig under `Component config > Bluetooth > NimBLE options > Enable extended advertising`, or set in `nimconfig.h` for Arduino, or in `build_flags` in PlatformIO. - -When enabled the following will occur: -* `NimBLEScan::start` method will scan on both the 1M PHY and the coded PHY standards automatically. - -* `NimBLEClient::connect` will use the primary PHY the device is listening on, unless specified (see below). - -* `NimBLEClient::setConnectPhy` becomes available to specify the PHY's to connect with (default is all). - -* `NimBLEAdvertising` is no longer available for use and is replaced by `NimBLEExtAdvertising`. `NimBLEDevice::getAdvertising` will now return an instance of `NimBLEExtAdvertising`. - -* `NimBLEAdvertisementData` is no longer available for use and is replaced by `NimBLEExtAdvertisement`. This new class is where everything about the advertisement is configured, including the advertisement intervals and advertisement ended callback. - - - diff --git a/lib/libesp32_div/NimBLE-Arduino/docs/Command_line_config.md b/lib/libesp32_div/NimBLE-Arduino/docs/Command_line_config.md deleted file mode 100644 index f6f6b5ac5..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/docs/Command_line_config.md +++ /dev/null @@ -1,180 +0,0 @@ -# Arduino command line and platformio config options - -`CONFIG_BT_NIMBLE_MAX_CONNECTIONS` - -Sets the number of simultaneous connections (esp controller max is 9) -- Default value is 3 -
- -`CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED` - -Enable/disable storing the timestamp when an attribute value is updated -This allows for checking the last update time using getTimeStamp() or getValue(time_t*) -If disabled, the timestamp returned from these functions will be 0. -Disabling timestamps will reduce the memory used for each value. -1 = Enabled, 0 = Disabled; Default = Disabled -
- -`CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH` - -Set the default allocation size (bytes) for each attribute. -If not specified when the constructor is called. This is also the size used when a remote -characteristic or descriptor is constructed before a value is read/notifed. -Increasing this will reduce reallocations but increase memory footprint. -Default value is 20. Range: 1 : 512 (BLE_ATT_ATTR_MAX_LEN) -
- -`CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU` - -Sets the default MTU size. -- Default value is 255 -
- -`CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME` - -Set the default device name -- Default value is "nimble" -
- -`CONFIG_BT_NIMBLE_DEBUG` - -If defined, enables debug log messages from the NimBLE host -- Uses approx. 32kB of flash memory. -
- -`CONFIG_NIMBLE_CPP_LOG_LEVEL` - -Define to set the debug log message level from the NimBLE CPP Wrapper. -If not defined it will use the same value as the Arduino core debug level. -Values: 0 = NONE, 1 = ERROR, 2 = WARNING, 3 = INFO, 4+ = DEBUG -
- -`CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT` - -If defined, NimBLE host return codes will be printed as text in debug log messages. -- Uses approx. 7kB of flash memory. -
- -`CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT` - -If defined, GAP event codes will be printed as text in debug log messages. -- Uses approx. 1kB of flash memory. -
- -`CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT` - -If defined, advertisment types will be printed as text while scanning in debug log messages. -- Uses approx. 250 bytes of flash memory. -
- -`CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE` - -Set the default appearance. -- Default value is 0x00 -
- -`CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED` - -If defined, NimBLE Client functions will not be included. -- Reduces flash size by approx. 7kB. -
- -`CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED` - -If defined, NimBLE Scan functions will not be included. -- Reduces flash size by approx. 26kB. -
- -`CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED` - -If defined NimBLE Server functions will not be included. -- Reduces flash size by approx. 16kB. -
- -`CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED` - -If defined, NimBLE Advertising functions will not be included. -- Reduces flash size by approx. 5kB. -
- -`CONFIG_BT_NIMBLE_MAX_BONDS` - -Sets the number of devices allowed to store/bond with -- Default value is 3 -
- -`CONFIG_BT_NIMBLE_MAX_CCCDS` - -Sets the maximum number of CCCD subscriptions to store -- Default value is 8 -
- -`CONFIG_BT_NIMBLE_RPA_TIMEOUT` - -Sets the random address refresh time in seconds. -- Default value is 900 -
- -`CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT` - -Set the number of msys blocks For prepare write & prepare responses. This may need to be increased if -you are sending large blocks of data with a low MTU. E.g: 512 bytes with 23 MTU will fail. -- Default value is 12 -
- -`CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL` - -Sets the NimBLE stack to use external PSRAM will be loaded -- Must be defined with a value of 1; Default is CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1 -
- -`CONFIG_BT_NIMBLE_PINNED_TO_CORE` - -Sets the core the NimBLE host stack will run on -- Options: 0 or 1 -
- -`CONFIG_BT_NIMBLE_TASK_STACK_SIZE` - -Set the task stack size for the NimBLE core. -- Default is 4096 -
- -`CONFIG_NIMBLE_STACK_USE_MEM_POOLS` - - Enable the use of memory pools for stack operations. This will use slightly more RAM but may provide more stability. - -- Options: 0 or 1, default is disabled (0) -
- -### Extended advertising settings, For use with ESP32C3, ESP32S3, ESP32H2 ONLY! - -`CONFIG_BT_NIMBLE_EXT_ADV` - -Set to 1 to enable extended advertising features. -
- -`CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES` - -Sets the max number of extended advertising instances -- Range: 0 - 4 -- Default is 1 -
- -`CONFIG_BT_NIMBLE_MAX_EXT_ADV_DATA_LEN` - -Set the max extended advertising data size, -- Range: 31 - 1650 -- Default is 255 -
- -`CONFIG_BT_NIMBLE_ENABLE_PERIODIC_ADV` - -Set to 1 to enable periodic advertising. -
- -`CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS` - -Set the maximum number of periodically synced devices. -- Range: 1 - 8 -- Default is 1 diff --git a/lib/libesp32_div/NimBLE-Arduino/docs/Improvements_and_updates.md b/lib/libesp32_div/NimBLE-Arduino/docs/Improvements_and_updates.md deleted file mode 100644 index e353f6d17..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/docs/Improvements_and_updates.md +++ /dev/null @@ -1,148 +0,0 @@ -# Improvements and updates - -Many improvements have been made to this library vs the original, this is a brief overview of the most significant changes. Refer to the [class documentation](https://h2zero.github.io/esp-nimble-cpp/annotated.html) for further information on class specifics. - -* [Server](#server) -* [Advertising](#advertising) -* [Client](#client) -* [General](#general) -
- - -# Server - -`NimBLEService::NimBLEService::createCharacteristic` takes a 3rd parameter to specify the maximum data size that can be stored by the characteristic. This allows for limiting the RAM use of the characteristic in cases where small amounts of data are expected. -
- -`NimBLECharacteristic::setValue(const T &s)` -`NimBLEDescriptor::setValue(const T &s)` - -Now use the `NimbleAttValue` class and templates to accommodate standard and custom types/values. - -**Example** -``` -struct my_struct { - uint8_t one; - uint16_t two; - uint32_t four; - uint64_t eight; - float flt; -} myStruct; - - myStruct.one = 1; - myStruct.two = 2; - myStruct.four = 4; - myStruct.eight = 8; - myStruct.flt = 1234.56; - - pCharacteristic->setValue(myStruct); - - // Arduino String support - String myString = "Hello"; - pCharacteristic->setValue(myString); - ``` -This will send the struct to the receiving client when read or a notification sent. - -`NimBLECharacteristic::getValue` now takes an optional timestamp parameter which will update it's value with the time the last value was received. In addition an overloaded template has been added to retrieve the value as a type specified by the user. - -**Example** -``` - time_t timestamp; - myStruct = pCharacteristic->getValue(×tamp); // timestamp optional -``` -
- -**Advertising will automatically start when a client disconnects.** - -A new method `NimBLEServer::advertiseOnDisconnect(bool)` has been implemented to control this, true(default) = enabled. -
- -`NimBLEServer::removeService` takes an additional parameter `bool deleteSvc` that if true will delete the service and all characteristics / descriptors belonging to it and invalidating any pointers to them. - -If false the service is only removed from visibility by clients. The pointers to the service and it's characteristics / descriptors will remain valid and the service can be re-added in the future using `NimBLEServer::addService`. -
- - -# Advertising -`NimBLEAdvertising::start` - -Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a callback that is invoked when advertising ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API). - -This provides an opportunity to update the advertisement data if desired. - -Also now returns a bool value to indicate if advertising successfully started or not. -
- - -# Client - -`NimBLERemoteCharacteristic::readValue(time_t\*, bool)` -`NimBLERemoteDescriptor::readValue(bool)` - -Have been added as templates to allow reading the values as any specified type. - -**Example** -``` -struct my_struct{ - uint8_t one; - uint16_t two; - uint32_t four; - uint64_t eight; - float flt; -}myStruct; - - time_t timestamp; - myStruct = pRemoteCharacteristic->readValue(×tamp); // timestamp optional -``` -
- -`NimBLERemoteCharacteristic::registerForNotify` -Has been **deprecated** as now the internally stored characteristic value is updated when notification/indication is received. - -`NimBLERemoteCharacteristic::subscribe` and `NimBLERemoteCharacteristic::unsubscribe` have been implemented to replace it. -A callback is no longer required to get the most recent value unless timing is important. Instead, the application can call `NimBLERemoteCharacteristic::getValue` to get the last updated value any time. -
- -The `notify_callback` function is now defined as a `std::function` to take advantage of using `std::bind` to specify a class member function for the callback. - -Example: -``` -using namespace std::placeholders; -notify_callback callback = std::bind(&::, this, _1, _2, _3, _4); - -->subscribe(true, callback); -``` - -`NimBLERemoteCharacteristic::readValue` and `NimBLERemoteCharacteristic::getValue` take an optional timestamp parameter which will update it's value with -the time the last value was received. - -> NimBLEClient::getService -> NimBLERemoteService::getCharacteristic -> NimBLERemoteCharacteristic::getDescriptor - -These methods will now check the respective vectors for the attribute object and, if not found, will retrieve (only) -the specified attribute from the peripheral. - -These changes allow more control for the user to manage the resources used for the attributes. -
- -`NimBLEClient::connect()` can now be called without an address or advertised device parameter. This will connect to the device with the address previously set when last connected or set with `NimBLEDevice::setPeerAddress()`. - - -# General -To reduce resource use all instances of `std::map` have been replaced with `std::vector`. - -Use of `FreeRTOS::Semaphore` has been removed as it was consuming too much ram, the related files have been left in place to accomodate application use. - -Operators `==`, `!=` and `std::string` have been added to `NimBLEAddress` and `NimBLEUUID` for easier comparison and logging. - -New constructor for `NimBLEUUID(uint32_t, uint16_t, uint16_t, uint64_t)` added to lower memory use vs string construction. See: [#21](https://github.com/h2zero/NimBLE-Arduino/pull/21). - -Security/pairing operations are now handled in the respective `NimBLEClientCallbacks` and `NimBLEServerCallbacks` classes, `NimBLESecurity`(deprecated) remains for backward compatibility. - -Configuration options have been added to add or remove debugging information, when disabled (default) significantly reduces binary size. -In ESP-IDF the options are in menuconfig: `Main menu -> ESP-NimBLE-cpp configuration`. -For Arduino the options must be commented / uncommented in nimconfig.h. - -Characteristics and descriptors now use the `NimBLEAttValue` class to store their data. This is a polymorphic container class capable of converting to/from many different types efficiently. See: [#286](https://github.com/h2zero/NimBLE-Arduino/pull/286) - diff --git a/lib/libesp32_div/NimBLE-Arduino/docs/Migration_guide.md b/lib/libesp32_div/NimBLE-Arduino/docs/Migration_guide.md deleted file mode 100644 index 2ddc1b3c6..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/docs/Migration_guide.md +++ /dev/null @@ -1,379 +0,0 @@ -# Migrating from Bluedroid to NimBLE - -This guide describes the required changes to existing projects migrating from the original bluedroid API to NimBLE. - -**The changes listed here are only the required changes that must be made**, and a short overview of options for migrating existing applications. - -For more information on the improvements and additions please refer to the [class documentation](https://h2zero.github.io/NimBLE-Arduino/annotated.html) and [Improvements and updates](Improvements_and_updates.md) - -* [General Changes](#general-information) -* [Server](#server-api) - * [Services](#services) - * [characteristics](#characteristics) - * [descriptors](#descriptors) - * [Security](#server-security) -* [Advertising](#advertising-api) -* [Client](#client-api) - * [Remote Services](#remote-services) - * [Remote characteristics](#remote-characteristics) - * [Security](#client-security) -* [General Security](#security-api) -* [Configuration](#arduino-configuration) -
- - -## General Information - -### Header Files -All classes are accessible by including `NimBLEDevice.h` in your application, no further headers need to be included. - -(Mainly for Arduino) You may choose to include `NimBLELog.h` in your application if you want to use the `NIMBLE_LOGx` macros for debugging. These macros are used the same way as the `ESP_LOGx` macros. -
- -### Class Names -Class names remain the same as the original with the addition of a "Nim" prefix. -For example `BLEDevice` is now `NimBLEDevice` and `BLEServer` is now `NimBLEServer` etc. - -For convenience definitions have been added to allow applications to use either name for all classes this means **no class names need to be changed in existing code** and makes migrating easier. -
- -### BLE Addresses -`BLEAddress` (`NimBLEAddress`) When constructing an address the constructor now takes an *(optional)* `uint8_t type` parameter to specify the address type. Default is (0) Public static address. - -For example `BLEAddress addr(11:22:33:44:55:66, 1)` will create the address object with an address type of: 1 (Random). - -As this parameter is optional no changes to existing code are needed, it is mentioned here for information. - -`BLEAddress::getNative` (`NimBLEAddress::getNative`) returns a uint8_t pointer to the native address byte array. In this library the address bytes are stored in reverse order from the original library. This is due to the way the NimBLE stack expects addresses to be presented to it. All other functions such as `toString` are -not affected as the endian change is made within them. -
- - -## Server API -Creating a `BLEServer` instance is the same as original, no changes required. -For example `BLEDevice::createServer()` will work just as it did before. - -`BLEServerCallbacks` (`NimBLEServerCallbacks`) has new methods for handling security operations. -**Note:** All callback methods have default implementations which allows the application to implement only the methods applicable. -
- - -### Services -Creating a `BLEService` (`NimBLEService`) instance is the same as original, no changes required. -For example `BLEServer::createService(SERVICE_UUID)` will work just as it did before. - - -### Characteristics -`BLEService::createCharacteristic` (`NimBLEService::createCharacteristic`) is used the same way as originally except the properties parameter has changed. - -When creating a characteristic the properties are now set with `NIMBLE_PROPERTY::XXXX` instead of `BLECharacteristic::XXXX`. - -#### Originally -> BLECharacteristic::PROPERTY_READ | -> BLECharacteristic::PROPERTY_WRITE - -#### Is Now -> NIMBLE_PROPERTY::READ | -> NIMBLE_PROPERTY::WRITE -
- -#### The full list of properties -> NIMBLE_PROPERTY::READ -> NIMBLE_PROPERTY::READ_ENC -> NIMBLE_PROPERTY::READ_AUTHEN -> NIMBLE_PROPERTY::READ_AUTHOR -> NIMBLE_PROPERTY::WRITE -> NIMBLE_PROPERTY::WRITE_NR -> NIMBLE_PROPERTY::WRITE_ENC -> NIMBLE_PROPERTY::WRITE_AUTHEN -> NIMBLE_PROPERTY::WRITE_AUTHOR -> NIMBLE_PROPERTY::BROADCAST -> NIMBLE_PROPERTY::NOTIFY -> NIMBLE_PROPERTY::INDICATE - -
- -**Example:** -``` -BLECharacteristic *pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID, - BLECharacteristic::PROPERTY_READ | - BLECharacteristic::PROPERTY_WRITE - ); - -``` -Needs to be changed to: -``` -BLECharacteristic *pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID, - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE - ); -``` -
- -`BLECharacteristicCallbacks` (`NimBLECharacteristicCallbacks`) has a new method `NimBLECharacteristicCallbacks::onSubscribe` which is called when a client subscribes to notifications/indications. - -**Note:** All callback methods have default implementations which allows the application to implement only the methods applicable. -
- -> BLECharacteristic::getData - -**Has been removed from the API.** -Originally this returned a `uint8_t*` to the internal data, which is volatile. -To prevent possibly throwing exceptions this has been removed and `NimBLECharacteristic::getValue` should be used -to get a copy of the data first which can then safely be accessed via pointer. - -**Example:** -``` -std::string value = pCharacteristic->getValue(); -uint8_t *pData = (uint8_t*)value.data(); -``` -Alternatively use the `getValue` template: -``` -my_struct_t myStruct = pChr->getValue(); -``` -
- - -### Descriptors - -Descriptors are now created using the `NimBLECharacteristic::createDescriptor` method. - -BLE2902 or NimBLE2902 class has been removed. -NimBLE automatically creates the 0x2902 descriptor if a characteristic has a notification or indication property assigned to it. - -It was no longer useful to have a class for the 0x2902 descriptor as a new callback `NimBLECharacteristicCallbacks::onSubscribe` was added -to handle callback functionality and the client subscription status is handled internally. - -**Note:** Attempting to create a 0x2902 descriptor will trigger an assert to notify the error, -allowing the creation of it would cause a fault in the NimBLE stack. - -All other descriptors are now created just as characteristics are by using the `NimBLECharacteristic::createDescriptor` method (except 0x2904, see below). -Which are defined as: -``` -NimBLEDescriptor* createDescriptor(const char* uuid, - uint32_t properties = - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE, - uint16_t max_len = 100); - -NimBLEDescriptor* createDescriptor(NimBLEUUID uuid, - uint32_t properties = - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE, - uint16_t max_len = 100); -``` -##### Example -``` -pDescriptor = pCharacteristic->createDescriptor("ABCD", - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE | - NIMBLE_PROPERTY::WRITE_ENC, - 25); -``` -Would create a descriptor with the UUID 0xABCD, publicly readable but only writable if paired/bonded (encrypted) and has a max value length of 25 bytes. -
- -For the 0x2904, there is a special class that is created when you call `createDescriptor("2904"). - -The pointer returned is of the base class `NimBLEDescriptor` but the call will create the derived class of `NimBLE2904` so you must cast the returned pointer to -`NimBLE2904` to access the specific class methods. - -##### Example -``` -p2904 = (NimBLE2904*)pCharacteristic->createDescriptor("2904"); -``` -
- - -### Server Security -Security is set on the characteristic or descriptor properties by applying one of the following: -> NIMBLE_PROPERTY::READ_ENC -> NIMBLE_PROPERTY::READ_AUTHEN -> NIMBLE_PROPERTY::READ_AUTHOR -> NIMBLE_PROPERTY::WRITE_ENC -> NIMBLE_PROPERTY::WRITE_AUTHEN -> NIMBLE_PROPERTY::WRITE_AUTHOR - -
- -When a peer wants to read or write a characteristic or descriptor with any of these properties applied it will trigger the pairing process. By default the "just-works" pairing will be performed automatically. - -This can be changed to use passkey authentication or numeric comparison. See [Security API](#security-api) for details. -
- - -## Advertising API -Advertising works the same as the original API except: - -Calling `NimBLEAdvertising::setAdvertisementData` will entirely replace any data set with `NimBLEAdvertising::addServiceUUID`, or -`NimBLEAdvertising::setAppearance` or similar methods. You should set all the data you wish to advertise within the `NimBLEAdvertisementData` instead. -
- -> BLEAdvertising::start (NimBLEAdvertising::start) - -Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a callback that is invoked when advertising ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API). -This provides an opportunity to update the advertisement data if desired. -
- - -## Client API - -Client instances are created just as before with `BLEDevice::createClient` (`NimBLEDevice::createClient`). - -Multiple client instances can be created, up to the maximum number of connections set in the config file (default: 3). To delete a client instance you must use `NimBLEDevice::deleteClient`. - -`BLEClient::connect`(`NimBLEClient::connect`) Has had it's parameters altered. -Defined as: -> NimBLEClient::connect(bool deleteServices = true); -> NimBLEClient::connect(NimBLEAdvertisedDevice\* device, bool deleteServices = true); -> NimBLEClient::connect(NimBLEAddress address, bool deleteServices = true); - -The type parameter has been removed and a new bool parameter has been added to indicate if the client should delete the attribute database previously retrieved (if applicable) for the peripheral, default value is true. - -If set to false the client will use the attribute database it retrieved from the peripheral when previously connected. - -This allows for faster connections and power saving if the devices dropped connection and are reconnecting. -
- -> `BLEClient::getServices` (`NimBLEClient::getServices`) - -This method now takes an optional (bool) parameter to indicate if the services should be retrieved from the server (true) or the currently known database returned (false : default). -Also now returns a pointer to `std::vector` instead of `std::map`. -
- -**Removed:** the automatic discovery of all peripheral attributes as they consumed time and resources for data the user may not be interested in. - -**Added:** `NimBLEClient::discoverAttributes` for the user to discover all the peripheral attributes to replace the the removed automatic functionality. -
- - -### Remote Services -`BLERemoteService` (`NimBLERemoteService`) Methods remain mostly unchanged with the exceptions of: - -> BLERemoteService::getCharacteristicsByHandle - -This method has been removed. -
- -> `BLERemoteService::getCharacteristics` (`NimBLERemoteService::getCharacteristics`) - -This method now takes an optional (bool) parameter to indicate if the characteristics should be retrieved from the server (true) or -the currently known database returned (false : default). -Also now returns a pointer to `std::vector` instead of `std::map`. -
- - -### Remote Characteristics -`BLERemoteCharacteristic` (`NimBLERemoteCharacteristic`) - There have been a few changes to the methods in this class: - -> `BLERemoteCharacteristic::writeValue` (`NimBLERemoteCharacteristic::writeValue`) -> `BLERemoteCharacteristic::registerForNotify` (`NimBLERemoteCharacteristic::registerForNotify`) - -Now return true or false to indicate success or failure so you can choose to disconnect or try again. -
- -> `BLERemoteCharacteristic::registerForNotify` (`NimBLERemoteCharacteristic::registerForNotify`) - -Is now **deprecated**. -> `NimBLERemoteCharacteristic::subscribe` -> `NimBLERemoteCharacteristic::unsubscribe` - -Are the new methods added to replace it. -
- -> `BLERemoteCharacteristic::readUInt8` (`NimBLERemoteCharacteristic::readUInt8`) -> `BLERemoteCharacteristic::readUInt16` (`NimBLERemoteCharacteristic::readUInt16`) -> `BLERemoteCharacteristic::readUInt32` (`NimBLERemoteCharacteristic::readUInt32`) -> `BLERemoteCharacteristic::readFloat` (`NimBLERemoteCharacteristic::readFloat`) - -Are **deprecated** a template: `NimBLERemoteCharacteristic::readValue(time_t\*, bool)` has been added to replace them. -
- -> `BLERemoteCharacteristic::readRawData` - -**Has been removed from the API** -Originally it stored an unnecessary copy of the data and was returning a `uint8_t` pointer to volatile internal data. -The user application should use `NimBLERemoteCharacteristic::readValue` or `NimBLERemoteCharacteristic::getValue`. -To obtain a copy of the data, then cast the returned std::string to the type required such as: -``` -std::string value = pChr->readValue(); -uint8_t *data = (uint8_t*)value.data(); -``` -Alternatively use the `readValue` template: -``` -my_struct_t myStruct = pChr->readValue(); -``` -
- -> `BLERemoteCharacteristic::getDescriptors` (`NimBLERemoteCharacteristic::getDescriptors`) - -This method now takes an optional (bool) parameter to indicate if the descriptors should be retrieved from the server (true) or -the currently known database returned (false : default). -Also now returns a pointer to `std::vector` instead of `std::map`. -
- - -### Client Security -The client will automatically initiate security when the peripheral responds that it's required. -The default configuration will use "just-works" pairing with no bonding, if you wish to enable bonding see below. -
- - -## Security API -Security operations have been moved to `BLEDevice` (`NimBLEDevice`). - -Also security callback methods are now incorporated in the `NimBLEServerCallbacks` / `NimBLEClientCallbacks` classes. -However backward compatibility with the original `BLESecurity` (`NimBLESecurity`) class is retained to minimize application code changes. - -The callback methods are: - -> `bool onConfirmPIN(uint32_t pin)` - -Receives the pin when using numeric comparison authentication, `return true;` to accept. -
- -> `uint32_t onPassKeyRequest()` - -For server callback; return the passkey expected from the client. -For client callback; return the passkey to send to the server. -
- -> `void onAuthenticationComplete(ble_gap_conn_desc\* desc)` - -Authentication complete, success or failed information is in `desc`. -
- -Security settings and IO capabilities are now set by the following methods of NimBLEDevice. -> `NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc)` -> `NimBLEDevice::setSecurityAuth(uint8_t auth_req)` - -Sets the authorization mode for this device. -
- -> `NimBLEDevice::setSecurityIOCap(uint8_t iocap)` - -Sets the Input/Output capabilities of this device. -
- -> `NimBLEDevice::setSecurityInitKey(uint8_t init_key)` - -If we are the initiator of the security procedure this sets the keys we will distribute. -
- -> `NimBLEDevice::setSecurityRespKey(uint8_t resp_key)` - -Sets the keys we are willing to accept from the peer during pairing. -
- - -## Arduino Configuration - -Unlike the original library pre-packaged in the esp32-arduino, this library has all the configuration options that are normally set in menuconfig available in the *src/nimconfig.h* file. - -This allows Arduino users to fully customize the build, such as increasing max connections or loading the BLE stack into external PSRAM. - -For details on the options, they are fully commented in *nimconfig.h* -
diff --git a/lib/libesp32_div/NimBLE-Arduino/docs/New_user_guide.md b/lib/libesp32_div/NimBLE-Arduino/docs/New_user_guide.md deleted file mode 100644 index ce02efe7e..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/docs/New_user_guide.md +++ /dev/null @@ -1,339 +0,0 @@ -# New User Guide - -**Note:** If you are migrating an existing project from the original Bluedroid library please see the [Migration Guide.](Migration_guide.md) - -If you are a new user this will guide you through a simple server and client application. - -* [Creating a Server](#creating-a-server) -* [Creating a Client](#creating-a-client) -
- -## Include Files -At the top of your application file add `#include NimBLEDevice.h`, this is the only header required and provides access to all classes. -
- -## Using the Library -In order to perform any BLE tasks you must first initialize the library, this prepares the NimBLE stack to be ready for commands. - -To do this you must call `NimBLEDevice::init("your device name here")`, the parameter passed is a character string containing the name you want to advertise. -If you're not creating a server or do not want to advertise a name, simply pass an empty string for the parameter. - -This can be called any time you wish to use BLE functions and does not need to be called from app_main(IDF) or setup(Arduino) but usually is. -
- - -## Creating a Server -BLE servers perform 2 tasks, they advertise their existence for clients to find them and they provide services which contain information for the connecting client. - -After initializing the NimBLE stack we create a server by calling `NimBLEDevice::createServer()`, this will create a server instance and return a pointer to it. - -Once we have created the server we need to tell it the services it hosts. -To do this we call `NimBLEServer::createService(const char* uuid)`. Which returns a pointer to an instance of `NimBLEService`. -The `uuid` parameter is a hexadecimal string with the uuid we want to give the service, it can be 16, 32, or 128 bits. - -For this example we will keep it simple and use a 16 bit value: ABCD. -
- -**Example code:** -``` -#include "NimBLEDevice.h" - -// void setup() in Arduino -void app_main(void) -{ - NimBLEDevice::init("NimBLE"); - - NimBLEServer *pServer = NimBLEDevice::createServer(); - NimBLEService *pService = pServer->createService("ABCD"); -} -``` - -Now we have NimBLE initialized, a server created and a service assigned to it. -We can't do much with this yet so now we should add a characteristic to the service to provide some data. - -Next we call `NimBLEService::createCharacteristic` which returns a pointer to an instance of `NimBLECharacteristic`, and takes two parameters: -A `uuid` to specify the UUID of the characteristic and a bitmask of the properties we want applied to it. - -Just as with the service UUID we will use a simple 16 bit value: 1234. -The properties bitmask is a little more involved. It is a combination of NIMBLE_PROPERTY:: values. - -Here is the list of options: -> NIMBLE_PROPERTY\::READ -> NIMBLE_PROPERTY\::READ_ENC -> NIMBLE_PROPERTY\::READ_AUTHEN -> NIMBLE_PROPERTY\::READ_AUTHOR -> NIMBLE_PROPERTY\::WRITE -> NIMBLE_PROPERTY\::WRITE_NR -> NIMBLE_PROPERTY\::WRITE_ENC -> NIMBLE_PROPERTY\::WRITE_AUTHEN -> NIMBLE_PROPERTY\::WRITE_AUTHOR -> NIMBLE_PROPERTY\::BROADCAST -> NIMBLE_PROPERTY\::NOTIFY -> NIMBLE_PROPERTY\::INDICATE - -For this example we won't need to specify these as the default value is `NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE` -which will allow reading and writing values to the characteristic without encryption or security. -The function call will simply be `pService->createCharacteristic("1234");` -
- -**Our example code now is:** -``` -#include "NimBLEDevice.h" - -// void setup() in Arduino -void app_main(void) -{ - NimBLEDevice::init("NimBLE"); - - NimBLEServer *pServer = NimBLEDevice::createServer(); - NimBLEService *pService = pServer->createService("ABCD"); - NimBLECharacteristic *pCharacteristic = pService->createCharacteristic("1234"); -} -``` - -All that's left to do now is start the service, give the characteristic a value and start advertising for clients. - -Fist we start the service by calling `NimBLEService::start()`. - -Next we need to call `NimBLECharacteristic::setValue` to set the characteristic value that the client will read. -There are many different types you can send as parameters for the value but for this example we will use a simple string. -`pCharacteristic->setValue("Hello BLE");` - -Next we need to advertise for connections. -To do this we create an instance of `NimBLEAdvertising` add our service to it (optional) and start advertisng. - -**The code for this will be:** -``` -NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); // create advertising instance -pAdvertising->addServiceUUID("ABCD"); // tell advertising the UUID of our service -pAdvertising->start(); // start advertising -``` -That's it, this will be enough to create a BLE server with a service and a characteristic and advertise for client connections. - -**The full example code:** -``` -#include "NimBLEDevice.h" - -// void setup() in Arduino -void app_main(void) -{ - NimBLEDevice::init("NimBLE"); - - NimBLEServer *pServer = NimBLEDevice::createServer(); - NimBLEService *pService = pServer->createService("ABCD"); - NimBLECharacteristic *pCharacteristic = pService->createCharacteristic("1234"); - - pService->start(); - pCharacteristic->setValue("Hello BLE"); - - NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); - pAdvertising->addServiceUUID("ABCD"); - pAdvertising->start(); -} -``` - -Now if you scan with your phone using nRFConnect or any other BLE app you should see a device named "NimBLE" with a service of "ABCD". - -For more advanced features and options please see the server examples in the examples folder. -
- - -## Creating a Client - -BLE clients perform 2 tasks, they scan for advertising servers and form connections to them to read and write to their characteristics/descriptors. - -After initializing the NimBLE stack we create a scan instance by calling `NimBLEDevice::getScan()`, this will create a `NimBLEScan` instance and return a pointer to it. - -Once we have created the scan we can start looking for advertising servers. - -To do this we call `NimBLEScan::start(duration)`, the duration parameter is a uint32_t that specifies the number of seconds to scan for, -passing 0 will scan forever. - -In this example we will scan for 10 seconds. This is a blocking function (a non blocking overload is also available). -This call returns an instance of `NimBLEScanResults` when the scan completes which can be parsed for advertisers we are interested in. - -**Example Code:** -``` -#include "NimBLEDevice.h" - -// void setup() in Arduino -void app_main(void) -{ - NimBLEDevice::init(""); - - NimBLEScan *pScan = NimBLEDevice::getScan(); - NimBLEScanResults results = pScan->start(10); -} -``` -
- -Now that we have scanned we need to check the results for any advertisers we are interested in connecting to. - -To do this we iterate through the results and check if any of the devices found are advertising the service we want `ABCD`. -Each result in `NimBLEScanResults` is a `NimBLEAdvertisedDevice` instance that we can access data from. - -We will check each device found for the `ABCD` service by calling `NimBLEAdvertisedDevice::isAdvertisingService`. -This takes an instance of `NimBLEUUID` as a parameter so we will need to create one. - -**The code for this looks like:** -``` -NimBLEUUID serviceUuid("ABCD"); - -for(int i = 0; i < results.getCount(); i++) { - NimBLEAdvertisedDevice device = results.getDevice(i); - - if (device.isAdvertisingService(serviceUuid)) { - // create a client and connect - } -} -``` -
- -Now that we can scan and parse advertisers we need to be able to create a `NimBLEClient` instance and use it to connect. - -To do this we call `NimBLEDevice::createClient` which creates the `NimBLEClient` instance and returns a pointer to it. - -After this we call `NimBLEClient::connect` to connect to the advertiser. -This takes a pointer to the `NimBLEAdvertisedDevice` and returns `true` if successful. - -**Lets do that now:** -``` -NimBLEUUID serviceUuid("ABCD"); - -for(int i = 0; i < results.getCount(); i++) { - NimBLEAdvertisedDevice device = results.getDevice(i); - - if (device.isAdvertisingService(serviceUuid)) { - NimBLEClient *pClient = NimBLEDevice::createClient(); - - if(pClient->connect(&device)) { - //success - } else { - // failed to connect - } - } -} -``` -As shown, the call to `NimBLEClient::connect` should have it's return value tested to make sure it succeeded before proceeding to get data. -
- -Next we need to access the servers data by asking it for the service and the characteristic we are interested in, then read the characteristic value. - -To do this we call `NimBLEClient::getService`, which takes as a parameter the UUID of the service and returns -a pointer an instance to `NimBLERemoteService` or `nullptr` if the service was not found. - -Next we will call `NimBLERemoteService::getCharacteristic` which takes as a parameter the UUID of the service and returns -a pointer to an instance of `NimBLERemoteCharacteristic` or `nullptr` if not found. - -Finally we will read the characteristic value with `NimBLERemoteCharacteristic::readValue()`. - -**Here is what that looks like:** -``` -NimBLEUUID serviceUuid("ABCD"); - -for(int i = 0; i < results.getCount(); i++) { - NimBLEAdvertisedDevice device = results.getDevice(i); - - if (device.isAdvertisingService(serviceUuid)) { - NimBLEClient *pClient = NimBLEDevice::createClient(); - - if (pClient->connect(&device)) { - NimBLERemoteService *pService = pClient->getService(serviceUuid); - - if (pService != nullptr) { - NimBLERemoteCharacteristic *pCharacteristic = pService->getCharacteristic("1234"); - - if (pCharacteristic != nullptr) { - std::string value = pCharacteristic->readValue(); - // print or do whatever you need with the value - } - } - } else { - // failed to connect - } - } -} -``` -
- -The last thing we should do is clean up once we are done with the connection. -Because multiple clients are supported and can be created we should delete them when finished with them to conserve resources. -This is done by calling `NimBLEDevice::deleteClient`. - -**Lets add that now:** -``` -NimBLEUUID serviceUuid("ABCD"); - -for(int i = 0; i < results.getCount(); i++) { - NimBLEAdvertisedDevice device = results.getDevice(i); - - if (device.isAdvertisingService(serviceUuid)) { - NimBLEClient *pClient = NimBLEDevice::createClient(); - - if (pClient->connect(&device)) { - NimBLERemoteService *pService = pClient->getService(serviceUuid); - - if (pService != nullptr) { - NimBLERemoteCharacteristic *pCharacteristic = pService->getCharacteristic("1234"); - - if (pCharacteristic != nullptr) { - std::string value = pCharacteristic->readValue(); - // print or do whatever you need with the value - } - } - } else { - // failed to connect - } - - NimBLEDevice::deleteClient(pClient); - } -} -``` -Note that there is no need to disconnect as that will be done when deleting the client instance. -
- -**Here is the full example code:** -``` -#include "NimBLEDevice.h" - -// void setup() in Arduino -void app_main(void) -{ - NimBLEDevice::init(""); - - NimBLEScan *pScan = NimBLEDevice::getScan(); - NimBLEScanResults results = pScan->start(10); - - NimBLEUUID serviceUuid("ABCD"); - - for(int i = 0; i < results.getCount(); i++) { - NimBLEAdvertisedDevice device = results.getDevice(i); - - if (device.isAdvertisingService(serviceUuid)) { - NimBLEClient *pClient = NimBLEDevice::createClient(); - - if (pClient->connect(&device)) { - NimBLERemoteService *pService = pClient->getService(serviceUuid); - - if (pService != nullptr) { - NimBLERemoteCharacteristic *pCharacteristic = pService->getCharacteristic("1234"); - - if (pCharacteristic != nullptr) { - std::string value = pCharacteristic->readValue(); - // print or do whatever you need with the value - } - } - } else { - // failed to connect - } - - NimBLEDevice::deleteClient(pClient); - } - } -} -``` -
- -For more advanced features and options please see the client examples in the examples folder. -
- diff --git a/lib/libesp32_div/NimBLE-Arduino/docs/Usage_tips.md b/lib/libesp32_div/NimBLE-Arduino/docs/Usage_tips.md deleted file mode 100644 index 8a60ef241..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/docs/Usage_tips.md +++ /dev/null @@ -1,41 +0,0 @@ -# Usage Tips - -## Put BLE functions in a task running on the NimBLE stack core - -When commands are sent to the stack from a different core they can experience delays in execution. -This library detects this and invokes the esp32 IPC to reroute these commands through the correct core but this also increases overhead. -Therefore it is highly recommended to create tasks for BLE to run on the same core, the macro `CONFIG_BT_NIMBLE_PINNED_TO_CORE` can be used to set the core. -
- -## Do not delete client instances unless necessary or unused - -When a client instance has been created and has connected to a peer device and it has retrieved service/characteristic information it will store that data for the life of the client instance. -If you are periodically connecting to the same devices and you have deleted the client instance or the services when connecting again it will cause a retrieval of that information from the peer again. -This results in significant energy drain on the battery of the devices, fragments heap, and reduces connection performance. - -Client instances in this library use approximately 20% of the original bluedroid library, deleting them will provide much less gain than it did before. - -It is recommended to retain the client instance in cases where the time between connecting to the same device is less than 5 minutes. -
- -## Only retrieve the services and characteristics needed - -As a client the use of `NimBLEClient::getServices` or `NimBLERemoteService::getCharacteristics` and using `true` for the parameter should be limited to devices that are not known. -Instead `NimBLEClient::getService(NimBLEUUID)` or `NimBLERemoteService::getCharacteristic(NimBLEUUID)` should be used to access certain attributes that are useful to the application. -This reduces energy consumed, heap allocated, connection time and improves overall efficiency. -
- -## Check return values - -Many user issues can be avoided by checking if a function returned successfully, by either testing for true/false such as when calling `NimBLEClient::connect`, -or nullptr such as when calling `NimBLEClient::getService`. The latter being a must, as calling a method on a nullptr will surely result in a crash. -Most of the functions in this library return something that should be checked before proceeding. -
- -## There will be bugs - please report them - -No code is bug free and unit testing will not find them all on it's own. If you encounter a bug, please report it along with any logs and decoded backtrace if applicable. -Best efforts will be made to correct any errors ASAP. - -Bug reports can be made at https://github.com/h2zero/NimBLE-Arduino/issues or https://github.com/h2zero/esp-nimble-cpp/issues. -Questions and suggestions will be happily accepted there as well. diff --git a/lib/libesp32_div/NimBLE-Arduino/docs/index.md b/lib/libesp32_div/NimBLE-Arduino/docs/index.md deleted file mode 100644 index 2f1af75a2..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/docs/index.md +++ /dev/null @@ -1,70 +0,0 @@ -# Overview - -This is a C++ BLE library for Espressif ESP32 and Nordic nRF51/nRF52 devices that uses the NimBLE BLE stack. -The aim is to maintain, as much as reasonable, the original ESP32 Arduino BLE API by while adding new features and making improvements in performance, resource use, and stability. -
- -# What is NimBLE? -NimBLE is a completely open source Bluetooth Low Energy stack produced by [Apache](https://github.com/apache/mynewt-nimble). -
- -# Arduino installation -**NOTE:** Nordic devices require using [n-able arduino core](https://github.com/h2zero/n-able-Arduino) - -**Arduino Library manager:** Go to `sketch` -> `Include Library` -> `Manage Libraries` and search for NimBLE and install. - -**Alternatively:** Download as .zip and extract to Arduino/libraries folder, or in Arduino IDE from Sketch menu -> Include library -> Add .Zip library. - -`#include "NimBLEDevice.h"` at the beginning of your sketch. - -Call `NimBLEDevice::init` in `setup`. -
- -# Platformio installation -* Open platformio.ini, a project configuration file located in the root of PlatformIO project. -* Add the following line to the lib_deps option of [env:] section: -``` -h2zero/NimBLE-Arduino@^1.4.0 -``` -* Build a project, PlatformIO will automatically install dependencies. -
- -# Using -This library is intended to be compatible with the original ESP32 BLE library functions and types with minor changes. - -If you have not used the original BLE library please refer to the [New user guide](New_user_guide.md). - -If you are familiar with the original library, see: [The migration guide](Migration_guide.md) for details. - -Also see [Improvements and updates](Improvements_and_updates.md) for information about non-breaking changes. - -For more advanced usage see [Usage tips](Usage_tips.md) for more performance and optimization. -
- -## Examples -See the Refactored_original_examples in the examples folder for highlights of the differences with the original library. - -More advanced examples highlighting many available features are in examples/NimBLE_Server, NimBLE_Client. - -Beacon examples provided by [beegee-tokyo](https://github.com/beegee-tokyo) are in examples/BLE_Beacon_Scanner, BLE_EddystoneTLM_Beacon, BLE_EddystoneURL_Beacon. - -Change the settings in the nimconfig.h file to customize NimBLE to your project, such as increasing max connections (default is 3). -
- -## Arduino command line and platformio -As an alternative to changing the configuration in nimconfig.h, Arduino command line and platformio.ini options are available. - -See the command line configuration options available in [Command line config](Command_line_config.md). -
- -# Need help? Have a question or suggestion? -Come chat on [gitter](https://gitter.im/NimBLE-Arduino/community?utm_source=share-link&utm_medium=link&utm_campaign=share-link) or open an issue at [NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino/issues) or [esp-nimble-cpp](https://github.com/h2zero/esp-nimble-cpp/issues) -
- -# Acknowledgments - -* [nkolban](https://github.com/nkolban) and [chegewara](https://github.com/chegewara) for the [original esp32 BLE library](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils) this project was derived from. -* [beegee-tokyo](https://github.com/beegee-tokyo) for contributing your time to test/debug and contributing the beacon examples. -* [Jeroen88](https://github.com/Jeroen88) for the amazing help debugging and improving the client code. -
- diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino b/lib/libesp32_div/NimBLE-Arduino/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino deleted file mode 100644 index 4161aabf7..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino +++ /dev/null @@ -1,153 +0,0 @@ -/* - Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp - Ported to Arduino ESP32 by Evandro Copercini -*/ - -/** NimBLE differences highlighted in comment blocks **/ - -/*******original******** - #include - #include - #include - #include - #include "BLEEddystoneURL.h" - #include "BLEEddystoneTLM.h" - #include "BLEBeacon.h" -***********************/ - -#include - -#include -#include -#include "NimBLEEddystoneURL.h" -#include "NimBLEEddystoneTLM.h" -#include "NimBLEBeacon.h" - -#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8)) - -int scanTime = 5; //In seconds -BLEScan *pBLEScan; - -class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks -{ - /*** Only a reference to the advertised device is passed now - void onResult(BLEAdvertisedDevice advertisedDevice) { **/ - void onResult(BLEAdvertisedDevice *advertisedDevice) - { - if (advertisedDevice->haveName()) - { - Serial.print("Device name: "); - Serial.println(advertisedDevice->getName().c_str()); - Serial.println(""); - } - - if (advertisedDevice->haveServiceUUID()) - { - BLEUUID devUUID = advertisedDevice->getServiceUUID(); - Serial.print("Found ServiceUUID: "); - Serial.println(devUUID.toString().c_str()); - Serial.println(""); - } - else - { - if (advertisedDevice->haveManufacturerData() == true) - { - std::string strManufacturerData = advertisedDevice->getManufacturerData(); - - uint8_t cManufacturerData[100]; - strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0); - - if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00) - { - Serial.println("Found an iBeacon!"); - BLEBeacon oBeacon = BLEBeacon(); - oBeacon.setData(strManufacturerData); - Serial.printf("iBeacon Frame\n"); - Serial.printf("ID: %04X Major: %d Minor: %d UUID: %s Power: %d\n", oBeacon.getManufacturerId(), ENDIAN_CHANGE_U16(oBeacon.getMajor()), ENDIAN_CHANGE_U16(oBeacon.getMinor()), oBeacon.getProximityUUID().toString().c_str(), oBeacon.getSignalPower()); - } - else - { - Serial.println("Found another manufacturers beacon!"); - Serial.printf("strManufacturerData: %d ", strManufacturerData.length()); - for (int i = 0; i < strManufacturerData.length(); i++) - { - Serial.printf("[%X]", cManufacturerData[i]); - } - Serial.printf("\n"); - } - } - return; - } - - BLEUUID eddyUUID = (uint16_t)0xfeaa; - - if (advertisedDevice->getServiceUUID().equals(eddyUUID)) - { - std::string serviceData = advertisedDevice->getServiceData(eddyUUID); - if (serviceData[0] == 0x10) - { - Serial.println("Found an EddystoneURL beacon!"); - BLEEddystoneURL foundEddyURL = BLEEddystoneURL(); - - foundEddyURL.setData(serviceData); - std::string bareURL = foundEddyURL.getURL(); - if (bareURL[0] == 0x00) - { - Serial.println("DATA-->"); - for (int idx = 0; idx < serviceData.length(); idx++) - { - Serial.printf("0x%08X ", serviceData[idx]); - } - Serial.println("\nInvalid Data"); - return; - } - - Serial.printf("Found URL: %s\n", foundEddyURL.getURL().c_str()); - Serial.printf("Decoded URL: %s\n", foundEddyURL.getDecodedURL().c_str()); - Serial.printf("TX power %d\n", foundEddyURL.getPower()); - Serial.println("\n"); - } - else if (serviceData[0] == 0x20) - { - Serial.println("Found an EddystoneTLM beacon!"); - BLEEddystoneTLM foundEddyURL = BLEEddystoneTLM(); - foundEddyURL.setData(serviceData); - - Serial.printf("Reported battery voltage: %dmV\n", foundEddyURL.getVolt()); - Serial.printf("Reported temperature from TLM class: %.2fC\n", (double)foundEddyURL.getTemp()); - int temp = (int)serviceData[5] + (int)(serviceData[4] << 8); - float calcTemp = temp / 256.0f; - Serial.printf("Reported temperature from data: %.2fC\n", calcTemp); - Serial.printf("Reported advertise count: %d\n", foundEddyURL.getCount()); - Serial.printf("Reported time since last reboot: %ds\n", foundEddyURL.getTime()); - Serial.println("\n"); - Serial.print(foundEddyURL.toString().c_str()); - Serial.println("\n"); - } - } - } -}; - -void setup() -{ - Serial.begin(115200); - Serial.println("Scanning..."); - - BLEDevice::init(""); - pBLEScan = BLEDevice::getScan(); //create new scan - pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); - pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster - pBLEScan->setInterval(100); - pBLEScan->setWindow(99); // less or equal setInterval value -} - -void loop() -{ - // put your main code here, to run repeatedly: - BLEScanResults foundDevices = pBLEScan->start(scanTime, false); - Serial.print("Devices found: "); - Serial.println(foundDevices.getCount()); - Serial.println("Scan done!"); - pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory - delay(2000); -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.md b/lib/libesp32_div/NimBLE-Arduino/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.md deleted file mode 100644 index 558c3e7ae..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.md +++ /dev/null @@ -1,9 +0,0 @@ -## BLE Beacon Scanner - -Initiates a BLE device scan. -Checks if the discovered devices are -- an iBeacon -- an Eddystone TLM beacon -- an Eddystone URL beacon - -and sends the decoded beacon information over Serial log \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.ino b/lib/libesp32_div/NimBLE-Arduino/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.ino deleted file mode 100644 index 32e0b1e99..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.ino +++ /dev/null @@ -1,113 +0,0 @@ -/* - EddystoneTLM beacon for NimBLE by BeeGee based on https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_Eddystone_TLM_deepsleep/ESP32_Eddystone_TLM_deepsleep.ino - EddystoneTLM frame specification https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md -*/ - -/* - Create a BLE server that will send periodic Eddystone URL frames. - The design of creating the BLE server is: - 1. Create a BLE Server - 2. Create advertising data - 3. Start advertising. - 4. wait - 5. Stop advertising. - 6. deep sleep - -*/ - -#include "NimBLEDevice.h" -#include "NimBLEBeacon.h" -#include "NimBLEAdvertising.h" -#include "NimBLEEddystoneURL.h" - -#include "sys/time.h" -#include "esp_sleep.h" - -#define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up - -// UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/) -#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" - -RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory -RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory - -BLEAdvertising *pAdvertising; -struct timeval nowTimeStruct; - -time_t lastTenth; - -// Check -// https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md -// and http://www.hugi.scene.org/online/coding/hugi%2015%20-%20cmtadfix.htm -// for the temperature value. It is a 8.8 fixed-point notation -void setBeacon() -{ - char beacon_data[25]; - uint16_t beconUUID = 0xFEAA; - uint16_t volt = random(2800, 3700); // 3300mV = 3.3V - float tempFloat = random(2000, 3100) / 100.0f; - Serial.printf("Random temperature is %.2fC\n", tempFloat); - int temp = (int)(tempFloat * 256); //(uint16_t)((float)23.00); - Serial.printf("Converted to 8.8 format %0X%0X\n", (temp >> 8), (temp & 0xFF)); - - BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); - BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); - - oScanResponseData.setFlags(0x06); // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04 - oScanResponseData.setCompleteServices(BLEUUID(beconUUID)); - - beacon_data[0] = 0x20; // Eddystone Frame Type (Unencrypted Eddystone-TLM) - beacon_data[1] = 0x00; // TLM version - beacon_data[2] = (volt >> 8); // Battery voltage, 1 mV/bit i.e. 0xCE4 = 3300mV = 3.3V - beacon_data[3] = (volt & 0xFF); // - beacon_data[4] = (temp >> 8); // Beacon temperature - beacon_data[5] = (temp & 0xFF); // - beacon_data[6] = ((bootcount & 0xFF000000) >> 24); // Advertising PDU count - beacon_data[7] = ((bootcount & 0xFF0000) >> 16); // - beacon_data[8] = ((bootcount & 0xFF00) >> 8); // - beacon_data[9] = (bootcount & 0xFF); // - beacon_data[10] = ((lastTenth & 0xFF000000) >> 24); // Time since power-on or reboot as 0.1 second resolution counter - beacon_data[11] = ((lastTenth & 0xFF0000) >> 16); // - beacon_data[12] = ((lastTenth & 0xFF00) >> 8); // - beacon_data[13] = (lastTenth & 0xFF); // - - oScanResponseData.setServiceData(BLEUUID(beconUUID), std::string(beacon_data, 14)); - oAdvertisementData.setName("TLMBeacon"); - pAdvertising->setAdvertisementData(oAdvertisementData); - pAdvertising->setScanResponseData(oScanResponseData); -} - -void setup() -{ - - Serial.begin(115200); - gettimeofday(&nowTimeStruct, NULL); - - Serial.printf("start ESP32 %d\n", bootcount++); - - Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n", nowTimeStruct.tv_sec, nowTimeStruct.tv_sec - last); - - last = nowTimeStruct.tv_sec; - lastTenth = nowTimeStruct.tv_sec * 10; // Time since last reset as 0.1 second resolution counter - - // Create the BLE Device - BLEDevice::init("TLMBeacon"); - - BLEDevice::setPower(ESP_PWR_LVL_N12); - - pAdvertising = BLEDevice::getAdvertising(); - - setBeacon(); - // Start advertising - pAdvertising->start(); - Serial.println("Advertizing started for 10s ..."); - delay(10000); - pAdvertising->stop(); - Serial.printf("enter deep sleep for 10s\n"); - esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION); - Serial.printf("in deep sleep\n"); -} - -void loop() -{ -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.md b/lib/libesp32_div/NimBLE-Arduino/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.md deleted file mode 100644 index 2e34029d1..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.md +++ /dev/null @@ -1,14 +0,0 @@ -## Eddystone TLM beacon -EddystoneTLM beacon by BeeGee based on -[pcbreflux ESP32 Eddystone TLM deepsleep](https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_Eddystone_TLM_deepsleep/ESP32_Eddystone_TLM_deepsleep.ino) - -[EddystoneTLM frame specification](https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md) - - Create a BLE server that will send periodic Eddystone TLM frames. - The design of creating the BLE server is: - 1. Create a BLE Server - 2. Create advertising data - 3. Start advertising. - 4. wait - 5. Stop advertising. - 6. deep sleep diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.ino b/lib/libesp32_div/NimBLE-Arduino/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.ino deleted file mode 100644 index 07879b257..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.ino +++ /dev/null @@ -1,185 +0,0 @@ -/* - EddystoneURL beacon for NimBLE by BeeGee - EddystoneURL frame specification https://github.com/google/eddystone/blob/master/eddystone-url/README.md - -*/ - -/* - Create a BLE server that will send periodic Eddystone URL frames. - The design of creating the BLE server is: - 1. Create a BLE Server - 2. Create advertising data - 3. Start advertising. - 4. wait - 5. Stop advertising. - 6. deep sleep - -*/ - -#include "NimBLEDevice.h" -#include "NimBLEBeacon.h" -#include "NimBLEEddystoneURL.h" - -#include "sys/time.h" -#include "esp_sleep.h" - -#define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up - -// UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/) -#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" - -RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory -RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory - -BLEAdvertising *pAdvertising; -struct timeval now; - -static const char *eddystone_url_prefix_subs[] = { - "http://www.", - "https://www.", - "http://", - "https://", - "urn:uuid:", - NULL -}; - -static const char *eddystone_url_suffix_subs[] = { - ".com/", - ".org/", - ".edu/", - ".net/", - ".info/", - ".biz/", - ".gov/", - ".com", - ".org", - ".edu", - ".net", - ".info", - ".biz", - ".gov", - NULL -}; - -static int string_begin_with(const char *str, const char *prefix) -{ - int prefix_len = strlen(prefix); - if (strncmp(prefix, str, prefix_len) == 0) - { - return prefix_len; - } - return 0; -} - -void setBeacon() -{ - BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); - BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); - - const char url[] = "https://d.giesecke.tk"; - - int scheme_len, ext_len = 1, i, idx, url_idx; - char *ret_data; - int url_len = strlen(url); - - ret_data = (char *)calloc(1, url_len + 13); - - ret_data[0] = 2; // Len - ret_data[1] = 0x01; // Type Flags - ret_data[2] = 0x06; // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04 - ret_data[3] = 3; // Len - ret_data[4] = 0x03; // Type 16-Bit UUID - ret_data[5] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB - ret_data[6] = 0xFE; // Eddystone UUID 1 MSB - ret_data[7] = 19; // Length of Beacon Data - ret_data[8] = 0x16; // Type Service Data - ret_data[9] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB - ret_data[10] = 0xFE; // Eddystone UUID 1 MSB - ret_data[11] = 0x10; // Eddystone Frame Type - ret_data[12] = 0xF4; // Beacons TX power at 0m - - i = 0, idx = 13, url_idx = 0; - - //replace prefix - scheme_len = 0; - while (eddystone_url_prefix_subs[i] != NULL) - { - if ((scheme_len = string_begin_with(url, eddystone_url_prefix_subs[i])) > 0) - { - ret_data[idx] = i; - idx++; - url_idx += scheme_len; - break; - } - i++; - } - while (url_idx < url_len) - { - i = 0; - ret_data[idx] = url[url_idx]; - ext_len = 1; - while (eddystone_url_suffix_subs[i] != NULL) - { - if ((ext_len = string_begin_with(&url[url_idx], eddystone_url_suffix_subs[i])) > 0) - { - ret_data[idx] = i; - break; - } - else - { - ext_len = 1; //inc 1 - } - i++; - } - url_idx += ext_len; - idx++; - } - ret_data[7] = idx - 8; - - Serial.printf("struct size %d url size %d reported len %d\n", - url_len + 13, - url_len, ret_data[7]); - - Serial.printf("URL in data %s\n", &ret_data[13]); - - std::string eddyStoneData(ret_data); - - oAdvertisementData.addData(eddyStoneData); - oScanResponseData.setName("MeBeacon"); - pAdvertising->setAdvertisementData(oAdvertisementData); - pAdvertising->setScanResponseData(oScanResponseData); -} - -void setup() -{ - - Serial.begin(115200); - gettimeofday(&now, NULL); - - Serial.printf("start ESP32 %d\n", bootcount++); - - Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n", now.tv_sec, now.tv_sec - last); - - last = now.tv_sec; - - // Create the BLE Device - BLEDevice::init("MeBeacon"); - - BLEDevice::setPower(ESP_PWR_LVL_N12); - - pAdvertising = BLEDevice::getAdvertising(); - - setBeacon(); - // Start advertising - pAdvertising->start(); - Serial.println("Advertizing started..."); - delay(10000); - pAdvertising->stop(); - Serial.printf("enter deep sleep\n"); - esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION); - Serial.printf("in deep sleep\n"); -} - -void loop() -{ -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.md b/lib/libesp32_div/NimBLE-Arduino/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.md deleted file mode 100644 index 2baf1cc52..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.md +++ /dev/null @@ -1,14 +0,0 @@ -## Eddystone URL beacon -EddystoneURL beacon by BeeGee based on -[pcbreflux ESP32 Eddystone URL deepsleep](https://github.com/pcbreflux/espressif/tree/master/esp32/arduino/sketchbook/ESP32_Eddystone_URL_deepsleep) - -[EddystoneURL frame specification](https://github.com/google/eddystone/blob/master/eddystone-url/README.md) - - Create a BLE server that will send periodic Eddystone URL frames. - The design of creating the BLE server is: - 1. Create a BLE Server - 2. Create advertising data - 3. Start advertising. - 4. wait - 5. Stop advertising. - 6. deep sleep diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/Bluetooth_5/NimBLE_extended_client/NimBLE_extended_client.ino b/lib/libesp32_div/NimBLE-Arduino/examples/Bluetooth_5/NimBLE_extended_client/NimBLE_extended_client.ino deleted file mode 100644 index 91a1e626b..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/Bluetooth_5/NimBLE_extended_client/NimBLE_extended_client.ino +++ /dev/null @@ -1,171 +0,0 @@ - -/** NimBLE Extended Client Demo: - * - * Demonstrates the Bluetooth 5.x client capabilities. - * - * Created: on April 2 2022 - * Author: H2zero - * -*/ - -/**************************************************** - * For use with ESP32C3, ESP32S3, ESP32H2 ONLY! * - /**************************************************/ - -#include -#if !CONFIG_BT_NIMBLE_EXT_ADV -# error Must enable extended advertising, see nimconfig.h file. -#endif - -void scanEndedCB(NimBLEScanResults results); - -#define SERVICE_UUID "ABCD" -#define CHARACTERISTIC_UUID "1234" - -static NimBLEAdvertisedDevice* advDevice; -static bool doConnect = false; -static uint32_t scanTime = 10; /* 0 = scan forever */ - -/* Define the PHY's to use when connecting to peer devices, can be 1, 2, or all 3 (default).*/ -static uint8_t connectPhys = BLE_GAP_LE_PHY_CODED_MASK | BLE_GAP_LE_PHY_1M_MASK /*| BLE_GAP_LE_PHY_2M_MASK */ ; - -/* Define a class to handle the callbacks for client connection events */ -class ClientCallbacks : public NimBLEClientCallbacks { - void onConnect(NimBLEClient* pClient) { - Serial.printf("Connected\n"); - }; - - void onDisconnect(NimBLEClient* pClient) { - Serial.printf("%s Disconnected - Starting scan\n", pClient->getPeerAddress().toString().c_str()); - NimBLEDevice::getScan()->start(scanTime, scanEndedCB); - }; -}; - - -/* Define a class to handle the callbacks when advertisements are received */ -class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks { - - void onResult(NimBLEAdvertisedDevice* advertisedDevice) { - Serial.printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str()); - if(advertisedDevice->isAdvertisingService(NimBLEUUID("ABCD"))) - { - Serial.printf("Found Our Service\n"); - /* Ready to connect now */ - doConnect = true; - /* Save the device reference in a global for the client to use*/ - advDevice = advertisedDevice; - /* stop scan before connecting */ - NimBLEDevice::getScan()->stop(); - } - }; -}; - - -/* Callback to process the results of the last scan or restart it */ -void scanEndedCB(NimBLEScanResults results){ - Serial.printf("Scan Ended\n"); - if (!doConnect) { /* Don't start the scan while connecting */ - NimBLEDevice::getScan()->start(scanTime, scanEndedCB); - } -} - - -/* Handles the provisioning of clients and connects / interfaces with the server */ -bool connectToServer() { - NimBLEClient* pClient = nullptr; - - pClient = NimBLEDevice::createClient(); - pClient->setClientCallbacks(new ClientCallbacks, false); - - /* Set the PHY's to use for this connection. This is a bitmask that represents the PHY's: - * * 0x01 BLE_GAP_LE_PHY_1M_MASK - * * 0x02 BLE_GAP_LE_PHY_2M_MASK - * * 0x04 BLE_GAP_LE_PHY_CODED_MASK - * Combine these with OR ("|"), eg BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK | BLE_GAP_LE_PHY_CODED_MASK; - */ - pClient->setConnectPhy(connectPhys); - - /** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */ - pClient->setConnectTimeout(10); - - if (!pClient->connect(advDevice)) { - /* Created a client but failed to connect, don't need to keep it as it has no data */ - NimBLEDevice::deleteClient(pClient); - Serial.printf("Failed to connect, deleted client\n"); - return false; - } - - Serial.printf("Connected to: %s RSSI: %d\n", - pClient->getPeerAddress().toString().c_str(), - pClient->getRssi()); - - /* Now we can read/write/subscribe the charateristics of the services we are interested in */ - NimBLERemoteService* pSvc = nullptr; - NimBLERemoteCharacteristic* pChr = nullptr; - - pSvc = pClient->getService(SERVICE_UUID); - - if (pSvc) { - pChr = pSvc->getCharacteristic(CHARACTERISTIC_UUID); - - if (pChr) { - // Read the value of the characteristic. - if (pChr->canRead()) { - std::string value = pChr->readValue(); - Serial.printf("Characteristic value: %s\n", value.c_str()); - } - } - - } else { - Serial.printf("ABCD service not found.\n"); - } - - NimBLEDevice::deleteClient(pClient); - Serial.printf("Done with this device!\n"); - return true; -} - -void setup () { - Serial.begin(115200); - Serial.printf("Starting NimBLE Client\n"); - - /* Initialize NimBLE, no device name specified as we are not advertising */ - NimBLEDevice::init(""); - NimBLEScan* pScan = NimBLEDevice::getScan(); - - /* create a callback that gets called when advertisers are found */ - pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks()); - - /* Set scan interval (how often) and window (how long) in milliseconds */ - pScan->setInterval(97); - pScan->setWindow(67); - - /* Active scan will gather scan response data from advertisers - * but will use more energy from both devices - */ - pScan->setActiveScan(true); - - /* Start scanning for advertisers for the scan time specified (in seconds) 0 = forever - * Optional callback for when scanning stops. - */ - pScan->start(scanTime, scanEndedCB); - - Serial.printf("Scanning for peripherals\n"); -} - -void loop () { - /* Loop here until we find a device we want to connect to */ - if (doConnect) { - /* Found a device we want to connect to, do it now */ - if (connectToServer()) { - Serial.printf("Success!, scanning for more!\n"); - } else { - Serial.printf("Failed to connect, starting scan\n"); - } - - doConnect = false; - NimBLEDevice::getScan()->start(scanTime, scanEndedCB); - } - - delay(10); -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/Bluetooth_5/NimBLE_extended_server/NimBLE_extended_server.ino b/lib/libesp32_div/NimBLE-Arduino/examples/Bluetooth_5/NimBLE_extended_server/NimBLE_extended_server.ino deleted file mode 100644 index 4bcd1b100..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/Bluetooth_5/NimBLE_extended_server/NimBLE_extended_server.ino +++ /dev/null @@ -1,150 +0,0 @@ -/** NimBLE Extended Advertiser Demo: - * - * Demonstrates the Bluetooth 5.x extended advertising capabilities. - * - * This demo will advertise a long data string on the CODED and 1M Phy's and - * starts a server allowing connection over either PHY's. It will advertise for - * 5 seconds then sleep for 20 seconds, if a client connects it will sleep once - * it has disconnected then repeats. - * - * Created: on April 2 2022 - * Author: H2zero - * -*/ - -/**************************************************** - * For use with ESP32C3, ESP32S3, ESP32H2 ONLY! * - /**************************************************/ - -#include "NimBLEDevice.h" -#if !CONFIG_BT_NIMBLE_EXT_ADV -# error Must enable extended advertising, see nimconfig.h file. -#endif - -#include "esp_sleep.h" - -#define SERVICE_UUID "ABCD" -#define CHARACTERISTIC_UUID "1234" - -/* Time in milliseconds to advertise */ -static uint32_t advTime = 5000; - -/* Time to sleep between advertisements */ -static uint32_t sleepSeconds = 20; - -/* Primary PHY used for advertising, can be one of BLE_HCI_LE_PHY_1M or BLE_HCI_LE_PHY_CODED */ -static uint8_t primaryPhy = BLE_HCI_LE_PHY_CODED; - -/* Secondary PHY used for advertising and connecting, - * can be one of BLE_HCI_LE_PHY_1M, BLE_HCI_LE_PHY_2M or BLE_HCI_LE_PHY_CODED - */ -static uint8_t secondaryPhy = BLE_HCI_LE_PHY_1M; - - -/* Handler class for server events */ -class ServerCallbacks: public NimBLEServerCallbacks { - void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) { - Serial.printf("Client connected:: %s\n", NimBLEAddress(desc->peer_ota_addr).toString().c_str()); - }; - - void onDisconnect(NimBLEServer* pServer) { - Serial.printf("Client disconnected - sleeping for %u seconds\n", sleepSeconds); - esp_deep_sleep_start(); - }; -}; - -/* Callback class to handle advertising events */ -class advertisingCallbacks: public NimBLEExtAdvertisingCallbacks { - void onStopped(NimBLEExtAdvertising* pAdv, int reason, uint8_t inst_id) { - /* Check the reason advertising stopped, don't sleep if client is connecting */ - printf("Advertising instance %u stopped\n", inst_id); - switch (reason) { - case 0: - printf("Client connecting\n"); - return; - case BLE_HS_ETIMEOUT: - printf("Time expired - sleeping for %u seconds\n", sleepSeconds); - break; - default: - break; - } - - esp_deep_sleep_start(); - } -}; - -void setup () { - Serial.begin(115200); - - NimBLEDevice::init("Extended advertiser"); - - /* Create the server and add the services/characteristics/descriptors */ - NimBLEServer *pServer = NimBLEDevice::createServer(); - pServer->setCallbacks(new ServerCallbacks); - - NimBLEService *pService = pServer->createService(SERVICE_UUID); - NimBLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID, - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE | - NIMBLE_PROPERTY::NOTIFY); - - pCharacteristic->setValue("Hello World"); - - /* Start the services */ - pService->start(); - - /* - * Create an extended advertisement with the instance ID 0 and set the PHY's. - * Multiple instances can be added as long as the instance ID is incremented. - */ - NimBLEExtAdvertisement extAdv(primaryPhy, secondaryPhy); - - /* Set the advertisement as connectable */ - extAdv.setConnectable(true); - - /* As per Bluetooth specification, extended advertising cannot be both scannable and connectable */ - extAdv.setScannable(false); // The default is false, set here for demonstration. - - /* Extended advertising allows for 251 bytes (minus header bytes ~20) in a single advertisement or up to 1650 if chained */ - extAdv.setServiceData(NimBLEUUID(SERVICE_UUID), std::string("Extended Advertising Demo.\r\n" - "Extended advertising allows for " - "251 bytes of data in a single advertisement,\r\n" - "or up to 1650 bytes with chaining.\r\n" - "This example message is 226 bytes long " - "and is using CODED_PHY for long range.")); - - extAdv.setCompleteServices16({NimBLEUUID(SERVICE_UUID)}); - - /* When extended advertising is enabled `NimBLEDevice::getAdvertising` returns a pointer to `NimBLEExtAdvertising */ - NimBLEExtAdvertising* pAdvertising = NimBLEDevice::getAdvertising(); - - /* Set the callbacks for advertising events */ - pAdvertising->setCallbacks(new advertisingCallbacks); - - /* - * NimBLEExtAdvertising::setInstanceData takes the instance ID and - * a reference to a `NimBLEExtAdvertisement` object. This sets the data - * that will be advertised for this instance ID, returns true if successful. - * - * Note: It is safe to create the advertisement as a local variable if setInstanceData - * is called before exiting the code block as the data will be copied. - */ - if (pAdvertising->setInstanceData(0, extAdv)) { - /* - * `NimBLEExtAdvertising::start` takes the advertisement instance ID to start - * and a duration in milliseconds or a max number of advertisements to send (or both). - */ - if (pAdvertising->start(0, advTime)) { - Serial.printf("Started advertising\n"); - } else { - Serial.printf("Failed to start advertising\n"); - } - } else { - Serial.printf("Failed to register advertisment data\n"); - } - - esp_sleep_enable_timer_wakeup(sleepSeconds * 1000000); -} - -void loop () { -} \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/Bluetooth_5/NimBLE_multi_advertiser/NimBLE_multi_advertiser.ino b/lib/libesp32_div/NimBLE-Arduino/examples/Bluetooth_5/NimBLE_multi_advertiser/NimBLE_multi_advertiser.ino deleted file mode 100644 index 73b7c89a2..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/Bluetooth_5/NimBLE_multi_advertiser/NimBLE_multi_advertiser.ino +++ /dev/null @@ -1,181 +0,0 @@ -/** NimBLE Multi Advertiser Demo: - * - * Demonstrates the Bluetooth 5.x extended advertising capabilities. - * - * This demo will advertise 2 advertisements, and extended scannable instance - * and a connectable legacy instance. They will advertise for 5 seconds then - * sleep for 20 seconds. The extended scannable instance will use the scan - * request callback to update it's data when a scan response is requested. - * - * Created: on April 9 2022 - * Author: H2zero - * -*/ - -/**************************************************** - * For use with ESP32C3, ESP32S3, ESP32H2 ONLY! * - /**************************************************/ - -#include -#if !CONFIG_BT_NIMBLE_EXT_ADV -# error Must enable extended advertising, see nimconfig.h file. -#endif - -#include "esp_sleep.h" - -#define SERVICE_UUID "ABCD" -#define CHARACTERISTIC_UUID "1234" - -/* Time in milliseconds to advertise */ -static uint32_t advTime = 5000; - -/* Time to sleep between advertisements */ -static uint32_t sleepTime = 20; - -/* Primary PHY used for advertising, can be one of BLE_HCI_LE_PHY_1M or BLE_HCI_LE_PHY_CODED */ -static uint8_t primaryPhy = BLE_HCI_LE_PHY_CODED; - -/* Secondary PHY used for advertising and connecting, - * can be one of BLE_HCI_LE_PHY_1M, BLE_HCI_LE_PHY_2M or BLE_HCI_LE_PHY_CODED - */ -static uint8_t secondaryPhy = BLE_HCI_LE_PHY_1M; - - -/* Handler class for server events */ -class ServerCallbacks: public NimBLEServerCallbacks { - void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) { - Serial.printf("Client connected: %s\n", NimBLEAddress(desc->peer_ota_addr).toString().c_str()); - }; - - void onDisconnect(NimBLEServer* pServer) { - Serial.printf("Client disconnected\n"); - // if still advertising we won't sleep yet. - if (!pServer->getAdvertising()->isAdvertising()) { - Serial.printf("Sleeping for %u seconds\n", sleepTime); - esp_deep_sleep_start(); - } - }; -}; - -/* Callback class to handle advertising events */ -class advCallbacks: public NimBLEExtAdvertisingCallbacks { - void onStopped(NimBLEExtAdvertising* pAdv, int reason, uint8_t inst_id) { - /* Check the reason advertising stopped, don't sleep if client is connecting */ - Serial.printf("Advertising instance %u stopped\n", inst_id); - switch (reason) { - case 0: - Serial.printf(" client connecting\n"); - return; - case BLE_HS_ETIMEOUT: - Serial.printf("Time expired - sleeping for %u seconds\n", sleepTime); - break; - default: - break; - } - - esp_deep_sleep_start(); - } - - bool m_updatedSR = false; - - void onScanRequest(NimBLEExtAdvertising* pAdv, uint8_t inst_id, NimBLEAddress addr) { - Serial.printf("Scan request for instance %u\n", inst_id); - // if the data has already been updated we don't need to change it again. - if (!m_updatedSR) { - Serial.printf("Updating scan data\n"); - NimBLEExtAdvertisement sr; - sr.setServiceData(NimBLEUUID(SERVICE_UUID), std::string("Hello from scan response!")); - pAdv->setScanResponseData(inst_id, sr); - m_updatedSR = true; - } - } -}; - -void setup () { - Serial.begin(115200); - - NimBLEDevice::init("Multi advertiser"); - - /* Create a server for our legacy advertiser */ - NimBLEServer *pServer = NimBLEDevice::createServer(); - pServer->setCallbacks(new ServerCallbacks); - - NimBLEService *pService = pServer->createService(SERVICE_UUID); - NimBLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID, - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE | - NIMBLE_PROPERTY::NOTIFY); - - pCharacteristic->setValue("Hello World"); - - /* Start the service */ - pService->start(); - - /* Create our multi advertising instances */ - - // extended scannable instance advertising on coded and 1m PHY's. - NimBLEExtAdvertisement extScannable(primaryPhy, secondaryPhy); - - // Legacy advertising as a connectable device. - NimBLEExtAdvertisement legacyConnectable; - - // Optional scan response data. - NimBLEExtAdvertisement legacyScanResponse; - - /* As per Bluetooth specification, extended advertising cannot be both scannable and connectable */ - extScannable.setScannable(true); - extScannable.setConnectable(false); - - /* Set the initial data */ - extScannable.setServiceData(NimBLEUUID(SERVICE_UUID), std::string("Scan me!")); - - /* enable the scan response callback, we will use this to update the data. */ - extScannable.enableScanRequestCallback(true); - - /* Optional custom address for this advertisment. */ - legacyConnectable.setAddress(NimBLEAddress("DE:AD:BE:EF:BA:AD")); - - /* Set the advertising data. */ - legacyConnectable.setName("Legacy"); - legacyConnectable.setCompleteServices16({NimBLEUUID(SERVICE_UUID)}); - - /* Set the legacy and connectable flags. */ - legacyConnectable.setLegacyAdvertising(true); - legacyConnectable.setConnectable(true); - - /* Put some data in the scan response if desired. */ - legacyScanResponse.setServiceData(NimBLEUUID(SERVICE_UUID), "Legacy SR"); - - /* Get the advertising ready */ - NimBLEExtAdvertising* pAdvertising = NimBLEDevice::getAdvertising(); - - /* Set the callbacks to handle advertising events */ - pAdvertising->setCallbacks(new advCallbacks); - - /* Set instance data. - * Up to 5 instances can be used if configured in menuconfig, instance 0 is always available. - * - * We will set the extended scannable data on instance 0 and the legacy data on instance 1. - * Note that the legacy scan response data needs to be set to the same instance (1). - */ - if (pAdvertising->setInstanceData( 0, extScannable ) && - pAdvertising->setInstanceData( 1, legacyConnectable ) && - pAdvertising->setScanResponseData( 1, legacyScanResponse )) { - /* - * `NimBLEExtAdvertising::start` takes the advertisement instance ID to start - * and a duration in milliseconds or a max number of advertisements to send (or both). - */ - if (pAdvertising->start(0, advTime) && pAdvertising->start(1, advTime)) { - Serial.printf("Started advertising\n"); - } else { - Serial.printf("Failed to start advertising\n"); - } - } else { - Serial.printf("Failed to register advertisment data\n"); - } - - esp_sleep_enable_timer_wakeup(sleepTime * 1000000); -} - -void loop(){ -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Client/NimBLE_Client.ino b/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Client/NimBLE_Client.ino deleted file mode 100644 index 577f67ff8..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Client/NimBLE_Client.ino +++ /dev/null @@ -1,396 +0,0 @@ - -/** NimBLE_Server Demo: - * - * Demonstrates many of the available features of the NimBLE client library. - * - * Created: on March 24 2020 - * Author: H2zero - * -*/ - -#include - -void scanEndedCB(NimBLEScanResults results); - -static NimBLEAdvertisedDevice* advDevice; - -static bool doConnect = false; -static uint32_t scanTime = 0; /** 0 = scan forever */ - - -/** None of these are required as they will be handled by the library with defaults. ** - ** Remove as you see fit for your needs */ -class ClientCallbacks : public NimBLEClientCallbacks { - void onConnect(NimBLEClient* pClient) { - Serial.println("Connected"); - /** After connection we should change the parameters if we don't need fast response times. - * These settings are 150ms interval, 0 latency, 450ms timout. - * Timeout should be a multiple of the interval, minimum is 100ms. - * I find a multiple of 3-5 * the interval works best for quick response/reconnect. - * Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 60 * 10ms = 600ms timeout - */ - pClient->updateConnParams(120,120,0,60); - }; - - void onDisconnect(NimBLEClient* pClient) { - Serial.print(pClient->getPeerAddress().toString().c_str()); - Serial.println(" Disconnected - Starting scan"); - NimBLEDevice::getScan()->start(scanTime, scanEndedCB); - }; - - /** Called when the peripheral requests a change to the connection parameters. - * Return true to accept and apply them or false to reject and keep - * the currently used parameters. Default will return true. - */ - bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params) { - if(params->itvl_min < 24) { /** 1.25ms units */ - return false; - } else if(params->itvl_max > 40) { /** 1.25ms units */ - return false; - } else if(params->latency > 2) { /** Number of intervals allowed to skip */ - return false; - } else if(params->supervision_timeout > 100) { /** 10ms units */ - return false; - } - - return true; - }; - - /********************* Security handled here ********************** - ****** Note: these are the same return values as defaults ********/ - uint32_t onPassKeyRequest(){ - Serial.println("Client Passkey Request"); - /** return the passkey to send to the server */ - return 123456; - }; - - bool onConfirmPIN(uint32_t pass_key){ - Serial.print("The passkey YES/NO number: "); - Serial.println(pass_key); - /** Return false if passkeys don't match. */ - return true; - }; - - /** Pairing process complete, we can check the results in ble_gap_conn_desc */ - void onAuthenticationComplete(ble_gap_conn_desc* desc){ - if(!desc->sec_state.encrypted) { - Serial.println("Encrypt connection failed - disconnecting"); - /** Find the client with the connection handle provided in desc */ - NimBLEDevice::getClientByID(desc->conn_handle)->disconnect(); - return; - } - }; -}; - - -/** Define a class to handle the callbacks when advertisments are received */ -class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks { - - void onResult(NimBLEAdvertisedDevice* advertisedDevice) { - Serial.print("Advertised Device found: "); - Serial.println(advertisedDevice->toString().c_str()); - if(advertisedDevice->isAdvertisingService(NimBLEUUID("DEAD"))) - { - Serial.println("Found Our Service"); - /** stop scan before connecting */ - NimBLEDevice::getScan()->stop(); - /** Save the device reference in a global for the client to use*/ - advDevice = advertisedDevice; - /** Ready to connect now */ - doConnect = true; - } - }; -}; - - -/** Notification / Indication receiving handler callback */ -void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify){ - std::string str = (isNotify == true) ? "Notification" : "Indication"; - str += " from "; - /** NimBLEAddress and NimBLEUUID have std::string operators */ - str += std::string(pRemoteCharacteristic->getRemoteService()->getClient()->getPeerAddress()); - str += ": Service = " + std::string(pRemoteCharacteristic->getRemoteService()->getUUID()); - str += ", Characteristic = " + std::string(pRemoteCharacteristic->getUUID()); - str += ", Value = " + std::string((char*)pData, length); - Serial.println(str.c_str()); -} - -/** Callback to process the results of the last scan or restart it */ -void scanEndedCB(NimBLEScanResults results){ - Serial.println("Scan Ended"); -} - - -/** Create a single global instance of the callback class to be used by all clients */ -static ClientCallbacks clientCB; - - -/** Handles the provisioning of clients and connects / interfaces with the server */ -bool connectToServer() { - NimBLEClient* pClient = nullptr; - - /** Check if we have a client we should reuse first **/ - if(NimBLEDevice::getClientListSize()) { - /** Special case when we already know this device, we send false as the - * second argument in connect() to prevent refreshing the service database. - * This saves considerable time and power. - */ - pClient = NimBLEDevice::getClientByPeerAddress(advDevice->getAddress()); - if(pClient){ - if(!pClient->connect(advDevice, false)) { - Serial.println("Reconnect failed"); - return false; - } - Serial.println("Reconnected client"); - } - /** We don't already have a client that knows this device, - * we will check for a client that is disconnected that we can use. - */ - else { - pClient = NimBLEDevice::getDisconnectedClient(); - } - } - - /** No client to reuse? Create a new one. */ - if(!pClient) { - if(NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS) { - Serial.println("Max clients reached - no more connections available"); - return false; - } - - pClient = NimBLEDevice::createClient(); - - Serial.println("New client created"); - - pClient->setClientCallbacks(&clientCB, false); - /** Set initial connection parameters: These settings are 15ms interval, 0 latency, 120ms timout. - * These settings are safe for 3 clients to connect reliably, can go faster if you have less - * connections. Timeout should be a multiple of the interval, minimum is 100ms. - * Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 51 * 10ms = 510ms timeout - */ - pClient->setConnectionParams(12,12,0,51); - /** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */ - pClient->setConnectTimeout(5); - - - if (!pClient->connect(advDevice)) { - /** Created a client but failed to connect, don't need to keep it as it has no data */ - NimBLEDevice::deleteClient(pClient); - Serial.println("Failed to connect, deleted client"); - return false; - } - } - - if(!pClient->isConnected()) { - if (!pClient->connect(advDevice)) { - Serial.println("Failed to connect"); - return false; - } - } - - Serial.print("Connected to: "); - Serial.println(pClient->getPeerAddress().toString().c_str()); - Serial.print("RSSI: "); - Serial.println(pClient->getRssi()); - - /** Now we can read/write/subscribe the charateristics of the services we are interested in */ - NimBLERemoteService* pSvc = nullptr; - NimBLERemoteCharacteristic* pChr = nullptr; - NimBLERemoteDescriptor* pDsc = nullptr; - - pSvc = pClient->getService("DEAD"); - if(pSvc) { /** make sure it's not null */ - pChr = pSvc->getCharacteristic("BEEF"); - - if(pChr) { /** make sure it's not null */ - if(pChr->canRead()) { - Serial.print(pChr->getUUID().toString().c_str()); - Serial.print(" Value: "); - Serial.println(pChr->readValue().c_str()); - } - - if(pChr->canWrite()) { - if(pChr->writeValue("Tasty")) { - Serial.print("Wrote new value to: "); - Serial.println(pChr->getUUID().toString().c_str()); - } - else { - /** Disconnect if write failed */ - pClient->disconnect(); - return false; - } - - if(pChr->canRead()) { - Serial.print("The value of: "); - Serial.print(pChr->getUUID().toString().c_str()); - Serial.print(" is now: "); - Serial.println(pChr->readValue().c_str()); - } - } - - /** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe(). - * Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false. - * Unsubscribe parameter defaults are: response=false. - */ - if(pChr->canNotify()) { - //if(!pChr->registerForNotify(notifyCB)) { - if(!pChr->subscribe(true, notifyCB)) { - /** Disconnect if subscribe failed */ - pClient->disconnect(); - return false; - } - } - else if(pChr->canIndicate()) { - /** Send false as first argument to subscribe to indications instead of notifications */ - //if(!pChr->registerForNotify(notifyCB, false)) { - if(!pChr->subscribe(false, notifyCB)) { - /** Disconnect if subscribe failed */ - pClient->disconnect(); - return false; - } - } - } - - } else { - Serial.println("DEAD service not found."); - } - - pSvc = pClient->getService("BAAD"); - if(pSvc) { /** make sure it's not null */ - pChr = pSvc->getCharacteristic("F00D"); - - if(pChr) { /** make sure it's not null */ - if(pChr->canRead()) { - Serial.print(pChr->getUUID().toString().c_str()); - Serial.print(" Value: "); - Serial.println(pChr->readValue().c_str()); - } - - pDsc = pChr->getDescriptor(NimBLEUUID("C01D")); - if(pDsc) { /** make sure it's not null */ - Serial.print("Descriptor: "); - Serial.print(pDsc->getUUID().toString().c_str()); - Serial.print(" Value: "); - Serial.println(pDsc->readValue().c_str()); - } - - if(pChr->canWrite()) { - if(pChr->writeValue("No tip!")) { - Serial.print("Wrote new value to: "); - Serial.println(pChr->getUUID().toString().c_str()); - } - else { - /** Disconnect if write failed */ - pClient->disconnect(); - return false; - } - - if(pChr->canRead()) { - Serial.print("The value of: "); - Serial.print(pChr->getUUID().toString().c_str()); - Serial.print(" is now: "); - Serial.println(pChr->readValue().c_str()); - } - } - - /** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe(). - * Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false. - * Unsubscribe parameter defaults are: response=false. - */ - if(pChr->canNotify()) { - //if(!pChr->registerForNotify(notifyCB)) { - if(!pChr->subscribe(true, notifyCB)) { - /** Disconnect if subscribe failed */ - pClient->disconnect(); - return false; - } - } - else if(pChr->canIndicate()) { - /** Send false as first argument to subscribe to indications instead of notifications */ - //if(!pChr->registerForNotify(notifyCB, false)) { - if(!pChr->subscribe(false, notifyCB)) { - /** Disconnect if subscribe failed */ - pClient->disconnect(); - return false; - } - } - } - - } else { - Serial.println("BAAD service not found."); - } - - Serial.println("Done with this device!"); - return true; -} - -void setup (){ - Serial.begin(115200); - Serial.println("Starting NimBLE Client"); - /** Initialize NimBLE, no device name spcified as we are not advertising */ - NimBLEDevice::init(""); - - /** Set the IO capabilities of the device, each option will trigger a different pairing method. - * BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing - * BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing - * BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing - */ - //NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); // use passkey - //NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison - - /** 2 different ways to set security - both calls achieve the same result. - * no bonding, no man in the middle protection, secure connections. - * - * These are the default values, only shown here for demonstration. - */ - //NimBLEDevice::setSecurityAuth(false, false, true); - NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC); - - /** Optional: set the transmit power, default is 3db */ -#ifdef ESP_PLATFORM - NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */ -#else - NimBLEDevice::setPower(9); /** +9db */ -#endif - - /** Optional: set any devices you don't want to get advertisments from */ - // NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff")); - - /** create new scan */ - NimBLEScan* pScan = NimBLEDevice::getScan(); - - /** create a callback that gets called when advertisers are found */ - pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks()); - - /** Set scan interval (how often) and window (how long) in milliseconds */ - pScan->setInterval(45); - pScan->setWindow(15); - - /** Active scan will gather scan response data from advertisers - * but will use more energy from both devices - */ - pScan->setActiveScan(true); - /** Start scanning for advertisers for the scan time specified (in seconds) 0 = forever - * Optional callback for when scanning stops. - */ - pScan->start(scanTime, scanEndedCB); -} - - -void loop (){ - /** Loop here until we find a device we want to connect to */ - while(!doConnect){ - delay(1); - } - - doConnect = false; - - /** Found a device we want to connect to, do it now */ - if(connectToServer()) { - Serial.println("Success! we should now be getting notifications, scanning for more!"); - } else { - Serial.println("Failed to connect, starting scan"); - } - - NimBLEDevice::getScan()->start(scanTime,scanEndedCB); -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Scan_Continuous/NimBLE_Scan_Continuous.ino b/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Scan_Continuous/NimBLE_Scan_Continuous.ino deleted file mode 100644 index b8d24d264..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Scan_Continuous/NimBLE_Scan_Continuous.ino +++ /dev/null @@ -1,71 +0,0 @@ -/** Example of continuous scanning for BLE advertisements. - * This example will scan forever while consuming as few resources as possible - * and report all advertisments on the serial monitor. - * - * Created: on January 31 2021 - * Author: H2zero - * - */ - -#include "NimBLEDevice.h" - -NimBLEScan* pBLEScan; - -class MyAdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks { - void onResult(NimBLEAdvertisedDevice* advertisedDevice) { - Serial.printf("Advertised Device: %s \n", advertisedDevice->toString().c_str()); - } -}; - -void setup() { - Serial.begin(115200); - Serial.println("Scanning..."); - -/** *Optional* Sets the filtering mode used by the scanner in the BLE controller. - * - * Can be one of: - * CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE (0) (default) - * Filter by device address only, advertisements from the same address will be reported only once. - * - * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA (1) - * Filter by data only, advertisements with the same data will only be reported once, - * even from different addresses. - * - * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE (2) - * Filter by address and data, advertisements from the same address will be reported only once, - * except if the data in the advertisement has changed, then it will be reported again. - * - * Can only be used BEFORE calling NimBLEDevice::init. -*/ - NimBLEDevice::setScanFilterMode(CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE); - -/** *Optional* Sets the scan filter cache size in the BLE controller. - * When the number of duplicate advertisements seen by the controller - * reaches this value it will clear the cache and start reporting previously - * seen devices. The larger this number, the longer time between repeated - * device reports. Range 10 - 1000. (default 20) - * - * Can only be used BEFORE calling NimBLEDevice::init. - */ - NimBLEDevice::setScanDuplicateCacheSize(200); - - NimBLEDevice::init(""); - - pBLEScan = NimBLEDevice::getScan(); //create new scan - // Set the callback for when devices are discovered, no duplicates. - pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(), false); - pBLEScan->setActiveScan(true); // Set active scanning, this will get more data from the advertiser. - pBLEScan->setInterval(97); // How often the scan occurs / switches channels; in milliseconds, - pBLEScan->setWindow(37); // How long to scan during the interval; in milliseconds. - pBLEScan->setMaxResults(0); // do not store the scan results, use callback only. -} - -void loop() { - // If an error occurs that stops the scan, it will be restarted here. - if(pBLEScan->isScanning() == false) { - // Start scan with: duration = 0 seconds(forever), no scan end callback, not a continuation of a previous scan. - pBLEScan->start(0, nullptr, false); - } - - delay(2000); -} \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Scan_Whitelist/NimBLE_Scan_whitelist.ino b/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Scan_Whitelist/NimBLE_Scan_whitelist.ino deleted file mode 100644 index cddbcc91b..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Scan_Whitelist/NimBLE_Scan_whitelist.ino +++ /dev/null @@ -1,67 +0,0 @@ -/* - * NimBLE_Scan_Whitelist demo - * - * Created May 16, 2021 - * Author: h2zero - */ - -#include - -int scanTime = 5; //In seconds -NimBLEScan* pBLEScan; - -class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { - void onResult(BLEAdvertisedDevice* advertisedDevice) { - Serial.printf("Advertised Device: %s \n", advertisedDevice->toString().c_str()); - /* - * Here we add the device scanned to the whitelist based on service data but any - * advertised data can be used for your preffered data. - */ - if (advertisedDevice->haveServiceData()) { - /* If this is a device with data we want to capture, add it to the whitelist */ - if (advertisedDevice->getServiceData(NimBLEUUID("AABB")) != "") { - Serial.printf("Adding %s to whitelist\n", std::string(advertisedDevice->getAddress()).c_str()); - NimBLEDevice::whiteListAdd(advertisedDevice->getAddress()); - } - } - } -}; - -void setup() { - Serial.begin(115200); - Serial.println("Scanning..."); - - NimBLEDevice::init(""); - pBLEScan = NimBLEDevice::getScan(); - pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); - pBLEScan->setActiveScan(true); - pBLEScan->setInterval(100); - pBLEScan->setFilterPolicy(BLE_HCI_SCAN_FILT_NO_WL); - pBLEScan->setWindow(99); -} - -void loop() { - NimBLEScanResults foundDevices = pBLEScan->start(scanTime, false); - Serial.print("Devices found: "); - Serial.println(foundDevices.getCount()); - Serial.println("Scan done!"); - - Serial.println("Whitelist contains:"); - for (auto i=0; i 0) { - if (foundDevices.getCount() == 0) { - pBLEScan->setFilterPolicy(BLE_HCI_SCAN_FILT_NO_WL); - } else { - pBLEScan->setFilterPolicy(BLE_HCI_SCAN_FILT_USE_WL); - } - } - pBLEScan->clearResults(); - delay(2000); -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Secure_Client/NimBLE_Secure_Client.ino b/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Secure_Client/NimBLE_Secure_Client.ino deleted file mode 100644 index 0936b5a26..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Secure_Client/NimBLE_Secure_Client.ino +++ /dev/null @@ -1,95 +0,0 @@ -/** NimBLE_Secure_Client Demo: - * - * This example demonstrates the secure passkey protected conenction and communication between an esp32 server and an esp32 client. - * Please note that esp32 stores auth info in nvs memory. After a successful connection it is possible that a passkey change will be ineffective. - * To avoid this clear the memory of the esp32's between security testings. esptool.py is capable of this, example: esptool.py --port /dev/ttyUSB0 erase_flash. - * - * Created: on Jan 08 2021 - * Author: mblasee - */ - -#include - -class ClientCallbacks : public NimBLEClientCallbacks -{ - uint32_t onPassKeyRequest() - { - Serial.println("Client Passkey Request"); - /** return the passkey to send to the server */ - /** Change this to be different from NimBLE_Secure_Server if you want to test what happens on key mismatch */ - return 123456; - }; -}; -static ClientCallbacks clientCB; - -void setup() -{ - Serial.begin(115200); - Serial.println("Starting NimBLE Client"); - - NimBLEDevice::init(""); -#ifdef ESP_PLATFORM - NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */ -#else - NimBLEDevice::setPower(9); /** +9db */ -#endif - NimBLEDevice::setSecurityAuth(true, true, true); - NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); - NimBLEScan *pScan = NimBLEDevice::getScan(); - NimBLEScanResults results = pScan->start(5); - - NimBLEUUID serviceUuid("ABCD"); - - for (int i = 0; i < results.getCount(); i++) - { - NimBLEAdvertisedDevice device = results.getDevice(i); - Serial.println(device.getName().c_str()); - - if (device.isAdvertisingService(serviceUuid)) - { - NimBLEClient *pClient = NimBLEDevice::createClient(); - pClient->setClientCallbacks(&clientCB, false); - - if (pClient->connect(&device)) - { - pClient->secureConnection(); - NimBLERemoteService *pService = pClient->getService(serviceUuid); - if (pService != nullptr) - { - NimBLERemoteCharacteristic *pNonSecureCharacteristic = pService->getCharacteristic("1234"); - - if (pNonSecureCharacteristic != nullptr) - { - // Testing to read a non secured characteristic, you should be able to read this even if you have mismatching passkeys. - std::string value = pNonSecureCharacteristic->readValue(); - // print or do whatever you need with the value - Serial.println(value.c_str()); - } - - NimBLERemoteCharacteristic *pSecureCharacteristic = pService->getCharacteristic("1235"); - - if (pSecureCharacteristic != nullptr) - { - // Testing to read a secured characteristic, you should be able to read this only if you have matching passkeys, otherwise you should - // get an error like this. E NimBLERemoteCharacteristic: "<< readValue rc=261" - // This means you are trying to do something without the proper permissions. - std::string value = pSecureCharacteristic->readValue(); - // print or do whatever you need with the value - Serial.println(value.c_str()); - } - } - } - else - { - // failed to connect - Serial.println("failed to connect"); - } - - NimBLEDevice::deleteClient(pClient); - } - } -} - -void loop() -{ -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Secure_Server/NimBLE_Secure_Server.ino b/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Secure_Server/NimBLE_Secure_Server.ino deleted file mode 100644 index 9cd866ccb..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Secure_Server/NimBLE_Secure_Server.ino +++ /dev/null @@ -1,41 +0,0 @@ -/** NimBLE_Secure_Server Demo: - * - * This example demonstrates the secure passkey protected conenction and communication between an esp32 server and an esp32 client. - * Please note that esp32 stores auth info in nvs memory. After a successful connection it is possible that a passkey change will be ineffective. - * To avoid this clear the memory of the esp32's between security testings. esptool.py is capable of this, example: esptool.py --port /dev/ttyUSB0 erase_flash. - * - * Created: on Jan 08 2021 - * Author: mblasee - */ - -#include - -void setup() { - Serial.begin(115200); - Serial.println("Starting NimBLE Server"); - NimBLEDevice::init("NimBLE"); -#ifdef ESP_PLATFORM - NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */ -#else - NimBLEDevice::setPower(9); /** +9db */ -#endif - - NimBLEDevice::setSecurityAuth(true, true, true); - NimBLEDevice::setSecurityPasskey(123456); - NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY); - NimBLEServer *pServer = NimBLEDevice::createServer(); - NimBLEService *pService = pServer->createService("ABCD"); - NimBLECharacteristic *pNonSecureCharacteristic = pService->createCharacteristic("1234", NIMBLE_PROPERTY::READ ); - NimBLECharacteristic *pSecureCharacteristic = pService->createCharacteristic("1235", NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::READ_AUTHEN); - - pService->start(); - pNonSecureCharacteristic->setValue("Hello Non Secure BLE"); - pSecureCharacteristic->setValue("Hello Secure BLE"); - - NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); - pAdvertising->addServiceUUID("ABCD"); - pAdvertising->start(); -} - -void loop() { -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Server/NimBLE_Server.ino b/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Server/NimBLE_Server.ino deleted file mode 100644 index 034fe24d4..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Server/NimBLE_Server.ino +++ /dev/null @@ -1,260 +0,0 @@ - -/** NimBLE_Server Demo: - * - * Demonstrates many of the available features of the NimBLE server library. - * - * Created: on March 22 2020 - * Author: H2zero - * -*/ - -#include - -static NimBLEServer* pServer; - -/** None of these are required as they will be handled by the library with defaults. ** - ** Remove as you see fit for your needs */ -class ServerCallbacks: public NimBLEServerCallbacks { - void onConnect(NimBLEServer* pServer) { - Serial.println("Client connected"); - Serial.println("Multi-connect support: start advertising"); - NimBLEDevice::startAdvertising(); - }; - /** Alternative onConnect() method to extract details of the connection. - * See: src/ble_gap.h for the details of the ble_gap_conn_desc struct. - */ - void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) { - Serial.print("Client address: "); - Serial.println(NimBLEAddress(desc->peer_ota_addr).toString().c_str()); - /** We can use the connection handle here to ask for different connection parameters. - * Args: connection handle, min connection interval, max connection interval - * latency, supervision timeout. - * Units; Min/Max Intervals: 1.25 millisecond increments. - * Latency: number of intervals allowed to skip. - * Timeout: 10 millisecond increments, try for 5x interval time for best results. - */ - pServer->updateConnParams(desc->conn_handle, 24, 48, 0, 60); - }; - void onDisconnect(NimBLEServer* pServer) { - Serial.println("Client disconnected - start advertising"); - NimBLEDevice::startAdvertising(); - }; - void onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) { - Serial.printf("MTU updated: %u for connection ID: %u\n", MTU, desc->conn_handle); - }; - -/********************* Security handled here ********************** -****** Note: these are the same return values as defaults ********/ - uint32_t onPassKeyRequest(){ - Serial.println("Server Passkey Request"); - /** This should return a random 6 digit number for security - * or make your own static passkey as done here. - */ - return 123456; - }; - - bool onConfirmPIN(uint32_t pass_key){ - Serial.print("The passkey YES/NO number: ");Serial.println(pass_key); - /** Return false if passkeys don't match. */ - return true; - }; - - void onAuthenticationComplete(ble_gap_conn_desc* desc){ - /** Check that encryption was successful, if not we disconnect the client */ - if(!desc->sec_state.encrypted) { - NimBLEDevice::getServer()->disconnect(desc->conn_handle); - Serial.println("Encrypt connection failed - disconnecting client"); - return; - } - Serial.println("Starting BLE work!"); - }; -}; - -/** Handler class for characteristic actions */ -class CharacteristicCallbacks: public NimBLECharacteristicCallbacks { - void onRead(NimBLECharacteristic* pCharacteristic){ - Serial.print(pCharacteristic->getUUID().toString().c_str()); - Serial.print(": onRead(), value: "); - Serial.println(pCharacteristic->getValue().c_str()); - }; - - void onWrite(NimBLECharacteristic* pCharacteristic) { - Serial.print(pCharacteristic->getUUID().toString().c_str()); - Serial.print(": onWrite(), value: "); - Serial.println(pCharacteristic->getValue().c_str()); - }; - /** Called before notification or indication is sent, - * the value can be changed here before sending if desired. - */ - void onNotify(NimBLECharacteristic* pCharacteristic) { - Serial.println("Sending notification to clients"); - }; - - - /** The status returned in status is defined in NimBLECharacteristic.h. - * The value returned in code is the NimBLE host return code. - */ - void onStatus(NimBLECharacteristic* pCharacteristic, Status status, int code) { - String str = ("Notification/Indication status code: "); - str += status; - str += ", return code: "; - str += code; - str += ", "; - str += NimBLEUtils::returnCodeToString(code); - Serial.println(str); - }; - - void onSubscribe(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc, uint16_t subValue) { - String str = "Client ID: "; - str += desc->conn_handle; - str += " Address: "; - str += std::string(NimBLEAddress(desc->peer_ota_addr)).c_str(); - if(subValue == 0) { - str += " Unsubscribed to "; - }else if(subValue == 1) { - str += " Subscribed to notfications for "; - } else if(subValue == 2) { - str += " Subscribed to indications for "; - } else if(subValue == 3) { - str += " Subscribed to notifications and indications for "; - } - str += std::string(pCharacteristic->getUUID()).c_str(); - - Serial.println(str); - }; -}; - -/** Handler class for descriptor actions */ -class DescriptorCallbacks : public NimBLEDescriptorCallbacks { - void onWrite(NimBLEDescriptor* pDescriptor) { - std::string dscVal = pDescriptor->getValue(); - Serial.print("Descriptor witten value:"); - Serial.println(dscVal.c_str()); - }; - - void onRead(NimBLEDescriptor* pDescriptor) { - Serial.print(pDescriptor->getUUID().toString().c_str()); - Serial.println(" Descriptor read"); - }; -}; - - -/** Define callback instances globally to use for multiple Charateristics \ Descriptors */ -static DescriptorCallbacks dscCallbacks; -static CharacteristicCallbacks chrCallbacks; - - -void setup() { - Serial.begin(115200); - Serial.println("Starting NimBLE Server"); - - /** sets device name */ - NimBLEDevice::init("NimBLE-Arduino"); - - /** Optional: set the transmit power, default is 3db */ -#ifdef ESP_PLATFORM - NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */ -#else - NimBLEDevice::setPower(9); /** +9db */ -#endif - - /** Set the IO capabilities of the device, each option will trigger a different pairing method. - * BLE_HS_IO_DISPLAY_ONLY - Passkey pairing - * BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing - * BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing - */ - //NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY); // use passkey - //NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison - - /** 2 different ways to set security - both calls achieve the same result. - * no bonding, no man in the middle protection, secure connections. - * - * These are the default values, only shown here for demonstration. - */ - //NimBLEDevice::setSecurityAuth(false, false, true); - NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC); - - pServer = NimBLEDevice::createServer(); - pServer->setCallbacks(new ServerCallbacks()); - - NimBLEService* pDeadService = pServer->createService("DEAD"); - NimBLECharacteristic* pBeefCharacteristic = pDeadService->createCharacteristic( - "BEEF", - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE | - /** Require a secure connection for read and write access */ - NIMBLE_PROPERTY::READ_ENC | // only allow reading if paired / encrypted - NIMBLE_PROPERTY::WRITE_ENC // only allow writing if paired / encrypted - ); - - pBeefCharacteristic->setValue("Burger"); - pBeefCharacteristic->setCallbacks(&chrCallbacks); - - /** 2904 descriptors are a special case, when createDescriptor is called with - * 0x2904 a NimBLE2904 class is created with the correct properties and sizes. - * However we must cast the returned reference to the correct type as the method - * only returns a pointer to the base NimBLEDescriptor class. - */ - NimBLE2904* pBeef2904 = (NimBLE2904*)pBeefCharacteristic->createDescriptor("2904"); - pBeef2904->setFormat(NimBLE2904::FORMAT_UTF8); - pBeef2904->setCallbacks(&dscCallbacks); - - - NimBLEService* pBaadService = pServer->createService("BAAD"); - NimBLECharacteristic* pFoodCharacteristic = pBaadService->createCharacteristic( - "F00D", - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE | - NIMBLE_PROPERTY::NOTIFY - ); - - pFoodCharacteristic->setValue("Fries"); - pFoodCharacteristic->setCallbacks(&chrCallbacks); - - /** Note a 0x2902 descriptor MUST NOT be created as NimBLE will create one automatically - * if notification or indication properties are assigned to a characteristic. - */ - - /** Custom descriptor: Arguments are UUID, Properties, max length in bytes of the value */ - NimBLEDescriptor* pC01Ddsc = pFoodCharacteristic->createDescriptor( - "C01D", - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE| - NIMBLE_PROPERTY::WRITE_ENC, // only allow writing if paired / encrypted - 20 - ); - pC01Ddsc->setValue("Send it back!"); - pC01Ddsc->setCallbacks(&dscCallbacks); - - /** Start the services when finished creating all Characteristics and Descriptors */ - pDeadService->start(); - pBaadService->start(); - - NimBLEAdvertising* pAdvertising = NimBLEDevice::getAdvertising(); - /** Add the services to the advertisment data **/ - pAdvertising->addServiceUUID(pDeadService->getUUID()); - pAdvertising->addServiceUUID(pBaadService->getUUID()); - /** If your device is battery powered you may consider setting scan response - * to false as it will extend battery life at the expense of less data sent. - */ - pAdvertising->setScanResponse(true); - pAdvertising->start(); - - Serial.println("Advertising Started"); -} - - -void loop() { - /** Do your thing here, this just spams notifications to all connected clients */ - if(pServer->getConnectedCount()) { - NimBLEService* pSvc = pServer->getServiceByUUID("BAAD"); - if(pSvc) { - NimBLECharacteristic* pChr = pSvc->getCharacteristic("F00D"); - if(pChr) { - pChr->notify(true); - } - } - } - - delay(2000); -} \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Server_Whitelist/NimBLE_Server_Whitelist.ino b/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Server_Whitelist/NimBLE_Server_Whitelist.ino deleted file mode 100644 index 4c7d33549..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Server_Whitelist/NimBLE_Server_Whitelist.ino +++ /dev/null @@ -1,105 +0,0 @@ -/* - * NimBLE_Server_Whitelist demo - * - * Created May 17, 2021 - * Author: h2zero - */ - -#include - -NimBLECharacteristic* pCharacteristic = nullptr; -bool deviceConnected = false; -bool oldDeviceConnected = false; -uint32_t value = 0; - -// See the following for generating UUIDs: -// https://www.uuidgenerator.net/ - -#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" -#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" - - -class MyServerCallbacks: public NimBLEServerCallbacks { - void onConnect(NimBLEServer* pServer) { - deviceConnected = true; - }; - - void onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) { - // Peer disconnected, add them to the whitelist - // This allows us to use the whitelist to filter connection attempts - // which will minimize reconnection time. - NimBLEDevice::whiteListAdd(NimBLEAddress(desc->peer_ota_addr)); - deviceConnected = false; - } -}; - -void onAdvComplete(NimBLEAdvertising *pAdvertising) { - Serial.println("Advertising stopped"); - if (deviceConnected) { - return; - } - // If advertising timed out without connection start advertising without whitelist filter - pAdvertising->setScanFilter(false,false); - pAdvertising->start(); -} - - -void setup() { - Serial.begin(115200); - - // Create the BLE Device - NimBLEDevice::init("ESP32"); - - // Create the BLE Server - NimBLEServer* pServer = NimBLEDevice::createServer(); - pServer->setCallbacks(new MyServerCallbacks()); - pServer->advertiseOnDisconnect(false); - - // Create the BLE Service - NimBLEService *pService = pServer->createService(SERVICE_UUID); - - // Create a BLE Characteristic - pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID, - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE | - NIMBLE_PROPERTY::NOTIFY ); - - // Start the service - pService->start(); - - // Start advertising - NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); - pAdvertising->addServiceUUID(SERVICE_UUID); - pAdvertising->setScanResponse(false); - pAdvertising->start(); - Serial.println("Waiting a client connection to notify..."); -} - -void loop() { - // notify changed value - if (deviceConnected) { - pCharacteristic->setValue((uint8_t*)&value, 4); - pCharacteristic->notify(); - value++; - } - // disconnecting - if (!deviceConnected && oldDeviceConnected) { - NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); - if (NimBLEDevice::getWhiteListCount() > 0) { - // Allow anyone to scan but only whitelisted can connect. - pAdvertising->setScanFilter(false,true); - } - // advertise with whitelist for 30 seconds - pAdvertising->start(30, onAdvComplete); - Serial.println("start advertising"); - oldDeviceConnected = deviceConnected; - } - // connecting - if (deviceConnected && !oldDeviceConnected) { - // do stuff here on connecting - oldDeviceConnected = deviceConnected; - } - - delay(2000); -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Service_Data_Advertiser/NimBLE_Service_Data_Advertiser.ino b/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Service_Data_Advertiser/NimBLE_Service_Data_Advertiser.ino deleted file mode 100644 index dd588fd22..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/NimBLE_Service_Data_Advertiser/NimBLE_Service_Data_Advertiser.ino +++ /dev/null @@ -1,33 +0,0 @@ -/** NimBLE_Service_Data_Advertiser Demo: - * - * Simple demo of advertising service data that changes every 5 seconds - * - * Created: on February 7 2021 - * Author: H2zero - * -*/ - -#include - -#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" - -static NimBLEUUID dataUuid(SERVICE_UUID); -static NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); -static uint32_t count = 0; - -void setup() { - Serial.begin(115200); - Serial.println("Starting BLE work!"); - - NimBLEDevice::init("svc data"); -} - -void loop() { - pAdvertising->stop(); - pAdvertising->setServiceData(dataUuid, std::string((char*)&count, sizeof(count))); - pAdvertising->start(); - - Serial.printf("Advertising count = %d\n", count); - count++; - delay(5000); -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_client/BLE_client.ino b/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_client/BLE_client.ino deleted file mode 100644 index 0d4ab94b4..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_client/BLE_client.ino +++ /dev/null @@ -1,194 +0,0 @@ -/** - * A BLE client example that is rich in capabilities. - * There is a lot new capabilities implemented. - * author unknown - * updated by chegewara - * updated for NimBLE by H2zero - */ - -/** NimBLE differences highlighted in comment blocks **/ - -/*******original******** -#include "BLEDevice.h" -***********************/ -#include "NimBLEDevice.h" - -// The remote service we wish to connect to. -static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b"); -// The characteristic of the remote service we are interested in. -static BLEUUID charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8"); - -static boolean doConnect = false; -static boolean connected = false; -static boolean doScan = false; -static BLERemoteCharacteristic* pRemoteCharacteristic; -static BLEAdvertisedDevice* myDevice; - -static void notifyCallback( - BLERemoteCharacteristic* pBLERemoteCharacteristic, - uint8_t* pData, - size_t length, - bool isNotify) { - Serial.print("Notify callback for characteristic "); - Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); - Serial.print(" of data length "); - Serial.println(length); - Serial.print("data: "); - Serial.println((char*)pData); -} - -/** None of these are required as they will be handled by the library with defaults. ** - ** Remove as you see fit for your needs */ -class MyClientCallback : public BLEClientCallbacks { - void onConnect(BLEClient* pclient) { - } - - void onDisconnect(BLEClient* pclient) { - connected = false; - Serial.println("onDisconnect"); - } -/***************** New - Security handled here ******************** -****** Note: these are the same return values as defaults ********/ - uint32_t onPassKeyRequest(){ - Serial.println("Client PassKeyRequest"); - return 123456; - } - bool onConfirmPIN(uint32_t pass_key){ - Serial.print("The passkey YES/NO number: ");Serial.println(pass_key); - return true; - } - - void onAuthenticationComplete(ble_gap_conn_desc desc){ - Serial.println("Starting BLE work!"); - } -/*******************************************************************/ -}; - -bool connectToServer() { - Serial.print("Forming a connection to "); - Serial.println(myDevice->getAddress().toString().c_str()); - - BLEClient* pClient = BLEDevice::createClient(); - Serial.println(" - Created client"); - - pClient->setClientCallbacks(new MyClientCallback()); - - // Connect to the remove BLE Server. - pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private) - Serial.println(" - Connected to server"); - - // Obtain a reference to the service we are after in the remote BLE server. - BLERemoteService* pRemoteService = pClient->getService(serviceUUID); - if (pRemoteService == nullptr) { - Serial.print("Failed to find our service UUID: "); - Serial.println(serviceUUID.toString().c_str()); - pClient->disconnect(); - return false; - } - Serial.println(" - Found our service"); - - - // Obtain a reference to the characteristic in the service of the remote BLE server. - pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); - if (pRemoteCharacteristic == nullptr) { - Serial.print("Failed to find our characteristic UUID: "); - Serial.println(charUUID.toString().c_str()); - pClient->disconnect(); - return false; - } - Serial.println(" - Found our characteristic"); - - // Read the value of the characteristic. - if(pRemoteCharacteristic->canRead()) { - std::string value = pRemoteCharacteristic->readValue(); - Serial.print("The characteristic value was: "); - Serial.println(value.c_str()); - } - - if(pRemoteCharacteristic->canNotify()) - pRemoteCharacteristic->registerForNotify(notifyCallback); - - connected = true; - return true; -} - -/** - * Scan for BLE servers and find the first one that advertises the service we are looking for. - */ -class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { - /** - * Called for each advertising BLE server. - */ - -/*** Only a reference to the advertised device is passed now - void onResult(BLEAdvertisedDevice advertisedDevice) { **/ - void onResult(BLEAdvertisedDevice* advertisedDevice) { - Serial.print("BLE Advertised Device found: "); - Serial.println(advertisedDevice->toString().c_str()); - - // We have found a device, let us now see if it contains the service we are looking for. -/******************************************************************************** - if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) { -********************************************************************************/ - if (advertisedDevice->haveServiceUUID() && advertisedDevice->isAdvertisingService(serviceUUID)) { - - BLEDevice::getScan()->stop(); -/******************************************************************* - myDevice = new BLEAdvertisedDevice(advertisedDevice); -*******************************************************************/ - myDevice = advertisedDevice; /** Just save the reference now, no need to copy the object */ - doConnect = true; - doScan = true; - - } // Found our server - } // onResult -}; // MyAdvertisedDeviceCallbacks - - -void setup() { - Serial.begin(115200); - Serial.println("Starting Arduino BLE Client application..."); - BLEDevice::init(""); - - // Retrieve a Scanner and set the callback we want to use to be informed when we - // have detected a new device. Specify that we want active scanning and start the - // scan to run for 5 seconds. - BLEScan* pBLEScan = BLEDevice::getScan(); - pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); - pBLEScan->setInterval(1349); - pBLEScan->setWindow(449); - pBLEScan->setActiveScan(true); - pBLEScan->start(5, false); -} // End of setup. - - -// This is the Arduino main loop function. -void loop() { - - // If the flag "doConnect" is true then we have scanned for and found the desired - // BLE Server with which we wish to connect. Now we connect to it. Once we are - // connected we set the connected flag to be true. - if (doConnect == true) { - if (connectToServer()) { - Serial.println("We are now connected to the BLE Server."); - } else { - Serial.println("We have failed to connect to the server; there is nothin more we will do."); - } - doConnect = false; - } - - // If we are connected to a peer BLE Server, update the characteristic each time we are reached - // with the current time since boot. - if (connected) { - String newValue = "Time since boot: " + String(millis()/1000); - Serial.println("Setting new characteristic value to \"" + newValue + "\""); - - // Set the characteristic's value to be the array of bytes that is actually a string. - /*** Note: write / read value now returns true if successful, false otherwise - try again or disconnect ***/ - pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length()); - }else if(doScan){ - BLEDevice::getScan()->start(0); // this is just eample to start scan after disconnect, most likely there is better way to do it in arduino - } - - delay(1000); // Delay a second between loops. -} // End of loop diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_iBeacon/BLE_iBeacon.ino b/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_iBeacon/BLE_iBeacon.ino deleted file mode 100644 index 86b97def3..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_iBeacon/BLE_iBeacon.ino +++ /dev/null @@ -1,118 +0,0 @@ -/* - Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp - Ported to Arduino ESP32 by pcbreflux -*/ - - -/* - Create a BLE server that will send periodic iBeacon frames. - The design of creating the BLE server is: - 1. Create a BLE Server - 2. Create advertising data - 3. Start advertising. - 4. wait - 5. Stop advertising. - 6. deep sleep - -*/ - - -/** NimBLE differences highlighted in comment blocks **/ - - -#include "sys/time.h" -/*******original******** -#include "BLEDevice.h" -#include "BLEUtils.h" -#include "BLEBeacon.h" -***********************/ -#include "NimBLEDevice.h" -#include "NimBLEBeacon.h" -#include "esp_sleep.h" - -#define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up -RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory -RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory - -#ifdef __cplusplus -extern "C" { -#endif - -uint8_t temprature_sens_read(); -//uint8_t g_phyFuns; - -#ifdef __cplusplus -} -#endif - -// See the following for generating UUIDs: -// https://www.uuidgenerator.net/ -BLEAdvertising *pAdvertising; -struct timeval now; - -#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/) - -void setBeacon() { - - BLEBeacon oBeacon = BLEBeacon(); - oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!) - oBeacon.setProximityUUID(BLEUUID(BEACON_UUID)); - oBeacon.setMajor((bootcount & 0xFFFF0000) >> 16); - oBeacon.setMinor(bootcount&0xFFFF); - BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); - BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); - - oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04 - - std::string strServiceData = ""; - - strServiceData += (char)26; // Len - strServiceData += (char)0xFF; // Type - strServiceData += oBeacon.getData(); - oAdvertisementData.addData(strServiceData); - - pAdvertising->setAdvertisementData(oAdvertisementData); - pAdvertising->setScanResponseData(oScanResponseData); - /** pAdvertising->setAdvertisementType(ADV_TYPE_NONCONN_IND); - * Advertising mode. Can be one of following constants: - * - BLE_GAP_CONN_MODE_NON (non-connectable; 3.C.9.3.2). - * - BLE_GAP_CONN_MODE_DIR (directed-connectable; 3.C.9.3.3). - * - BLE_GAP_CONN_MODE_UND (undirected-connectable; 3.C.9.3.4). - */ - pAdvertising->setAdvertisementType(BLE_GAP_CONN_MODE_NON); - -} - -void setup() { - - - Serial.begin(115200); - gettimeofday(&now, NULL); - - Serial.printf("start ESP32 %d\n",bootcount++); - - Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n",now.tv_sec,now.tv_sec-last); - - last = now.tv_sec; - - // Create the BLE Device - BLEDevice::init(""); - - // Create the BLE Server - // BLEServer *pServer = BLEDevice::createServer(); // <-- no longer required to instantiate BLEServer, less flash and ram usage - - pAdvertising = BLEDevice::getAdvertising(); - - setBeacon(); - // Start advertising - pAdvertising->start(); - Serial.println("Advertizing started..."); - delay(100); - pAdvertising->stop(); - Serial.printf("enter deep sleep\n"); - esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION); - Serial.printf("in deep sleep\n"); -} - -void loop() { -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_notify/BLE_notify.ino b/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_notify/BLE_notify.ino deleted file mode 100644 index cb0488819..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_notify/BLE_notify.ino +++ /dev/null @@ -1,146 +0,0 @@ -/* - Video: https://www.youtube.com/watch?v=oCMOYS71NIU - Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp - Ported to Arduino ESP32 by Evandro Copercini - updated by chegewara - - Create a BLE server that, once we receive a connection, will send periodic notifications. - The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b - And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8 - - The design of creating the BLE server is: - 1. Create a BLE Server - 2. Create a BLE Service - 3. Create a BLE Characteristic on the Service - 4. Create a BLE Descriptor on the characteristic - 5. Start the service. - 6. Start advertising. - - A connect hander associated with the server starts a background task that performs notification - every couple of seconds. -*/ - -/** NimBLE differences highlighted in comment blocks **/ - -/*******original******** -#include -#include -#include -#include -***********************/ -#include - -BLEServer* pServer = NULL; -BLECharacteristic* pCharacteristic = NULL; -bool deviceConnected = false; -bool oldDeviceConnected = false; -uint32_t value = 0; - -// See the following for generating UUIDs: -// https://www.uuidgenerator.net/ - -#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" -#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" - -/** None of these are required as they will be handled by the library with defaults. ** - ** Remove as you see fit for your needs */ -class MyServerCallbacks: public BLEServerCallbacks { - void onConnect(BLEServer* pServer) { - deviceConnected = true; - }; - - void onDisconnect(BLEServer* pServer) { - deviceConnected = false; - } -/***************** New - Security handled here ******************** -****** Note: these are the same return values as defaults ********/ - uint32_t onPassKeyRequest(){ - Serial.println("Server PassKeyRequest"); - return 123456; - } - - bool onConfirmPIN(uint32_t pass_key){ - Serial.print("The passkey YES/NO number: ");Serial.println(pass_key); - return true; - } - - void onAuthenticationComplete(ble_gap_conn_desc desc){ - Serial.println("Starting BLE work!"); - } -/*******************************************************************/ -}; - - -void setup() { - Serial.begin(115200); - - // Create the BLE Device - BLEDevice::init("ESP32"); - - // Create the BLE Server - pServer = BLEDevice::createServer(); - pServer->setCallbacks(new MyServerCallbacks()); - - // Create the BLE Service - BLEService *pService = pServer->createService(SERVICE_UUID); - - // Create a BLE Characteristic - pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID, - /******* Enum Type NIMBLE_PROPERTY now ******* - BLECharacteristic::PROPERTY_READ | - BLECharacteristic::PROPERTY_WRITE | - BLECharacteristic::PROPERTY_NOTIFY | - BLECharacteristic::PROPERTY_INDICATE - ); - **********************************************/ - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE | - NIMBLE_PROPERTY::NOTIFY | - NIMBLE_PROPERTY::INDICATE - ); - - // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml - // Create a BLE Descriptor - /*************************************************** - NOTE: DO NOT create a 2902 descriptor. - it will be created automatically if notifications - or indications are enabled on a characteristic. - - pCharacteristic->addDescriptor(new BLE2902()); - ****************************************************/ - // Start the service - pService->start(); - - // Start advertising - BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); - pAdvertising->addServiceUUID(SERVICE_UUID); - pAdvertising->setScanResponse(false); - /** Note, this could be left out as that is the default value */ - pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter - - BLEDevice::startAdvertising(); - Serial.println("Waiting a client connection to notify..."); -} - -void loop() { - // notify changed value - if (deviceConnected) { - pCharacteristic->setValue((uint8_t*)&value, 4); - pCharacteristic->notify(); - value++; - delay(3); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms - } - // disconnecting - if (!deviceConnected && oldDeviceConnected) { - delay(500); // give the bluetooth stack the chance to get things ready - pServer->startAdvertising(); // restart advertising - Serial.println("start advertising"); - oldDeviceConnected = deviceConnected; - } - // connecting - if (deviceConnected && !oldDeviceConnected) { - // do stuff here on connecting - oldDeviceConnected = deviceConnected; - } -} \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_scan/BLE_scan.ino b/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_scan/BLE_scan.ino deleted file mode 100644 index 86cdaf46f..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_scan/BLE_scan.ino +++ /dev/null @@ -1,49 +0,0 @@ -/* - Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp - Ported to Arduino ESP32 by Evandro Copercini -*/ - -/** NimBLE differences highlighted in comment blocks **/ - -/*******original******** -#include -#include -#include -#include -***********************/ - -#include - -int scanTime = 5; //In seconds -BLEScan* pBLEScan; - -class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { - /*** Only a reference to the advertised device is passed now - void onResult(BLEAdvertisedDevice advertisedDevice) { **/ - void onResult(BLEAdvertisedDevice* advertisedDevice) { - /** Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str()); **/ - Serial.printf("Advertised Device: %s \n", advertisedDevice->toString().c_str()); - } -}; - -void setup() { - Serial.begin(115200); - Serial.println("Scanning..."); - - BLEDevice::init(""); - pBLEScan = BLEDevice::getScan(); //create new scan - pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); - pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster - pBLEScan->setInterval(100); - pBLEScan->setWindow(99); // less or equal setInterval value -} - -void loop() { - // put your main code here, to run repeatedly: - BLEScanResults foundDevices = pBLEScan->start(scanTime, false); - Serial.print("Devices found: "); - Serial.println(foundDevices.getCount()); - Serial.println("Scan done!"); - pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory - delay(2000); -} \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_server/BLE_server.ino b/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_server/BLE_server.ino deleted file mode 100644 index faa4d88ea..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_server/BLE_server.ino +++ /dev/null @@ -1,57 +0,0 @@ -/* - Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp - Ported to Arduino ESP32 by Evandro Copercini - updates by chegewara -*/ - -/** NimBLE differences highlighted in comment blocks **/ - -/*******original******** -#include -#include -#include -***********************/ - -#include - -// See the following for generating UUIDs: -// https://www.uuidgenerator.net/ - -#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" -#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" - -void setup() { - Serial.begin(115200); - Serial.println("Starting BLE work!"); - - BLEDevice::init("Long name works now"); - BLEServer *pServer = BLEDevice::createServer(); - BLEService *pService = pServer->createService(SERVICE_UUID); - BLECharacteristic *pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID, - /***** Enum Type NIMBLE_PROPERTY now ***** - BLECharacteristic::PROPERTY_READ | - BLECharacteristic::PROPERTY_WRITE - ); - *****************************************/ - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE - ); - - pCharacteristic->setValue("Hello World says Neil"); - pService->start(); - // BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility - BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); - pAdvertising->addServiceUUID(SERVICE_UUID); - pAdvertising->setScanResponse(true); - pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue - pAdvertising->setMaxPreferred(0x12); - - BLEDevice::startAdvertising(); - Serial.println("Characteristic defined! Now you can read it in your phone!"); -} - -void loop() { - // put your main code here, to run repeatedly: - delay(2000); -} \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_server_multiconnect/BLE_server_multiconnect.ino b/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_server_multiconnect/BLE_server_multiconnect.ino deleted file mode 100644 index 9ae3859c7..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_server_multiconnect/BLE_server_multiconnect.ino +++ /dev/null @@ -1,150 +0,0 @@ -/* - Video: https://www.youtube.com/watch?v=oCMOYS71NIU - Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp - Ported to Arduino ESP32 by Evandro Copercini - updated by chegewara - - Create a BLE server that, once we receive a connection, will send periodic notifications. - The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b - And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8 - - The design of creating the BLE server is: - 1. Create a BLE Server - 2. Create a BLE Service - 3. Create a BLE Characteristic on the Service - 4. Create a BLE Descriptor on the characteristic - 5. Start the service. - 6. Start advertising. - - A connect hander associated with the server starts a background task that performs notification - every couple of seconds. -*/ - -/** NimBLE differences highlighted in comment blocks **/ - -/*******original******** -#include -#include -#include -#include -***********************/ -#include - -BLEServer* pServer = NULL; -BLECharacteristic* pCharacteristic = NULL; -bool deviceConnected = false; -bool oldDeviceConnected = false; -uint32_t value = 0; - -// See the following for generating UUIDs: -// https://www.uuidgenerator.net/ - -#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" -#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" - - -/** None of these are required as they will be handled by the library with defaults. ** - ** Remove as you see fit for your needs */ -class MyServerCallbacks: public BLEServerCallbacks { - void onConnect(BLEServer* pServer) { - deviceConnected = true; - BLEDevice::startAdvertising(); - }; - - void onDisconnect(BLEServer* pServer) { - deviceConnected = false; - } - /***************** New - Security handled here ******************** - ****** Note: these are the same return values as defaults ********/ - uint32_t onPassKeyRequest(){ - Serial.println("Server PassKeyRequest"); - return 123456; - } - - bool onConfirmPIN(uint32_t pass_key){ - Serial.print("The passkey YES/NO number: ");Serial.println(pass_key); - return true; - } - - void onAuthenticationComplete(ble_gap_conn_desc desc){ - Serial.println("Starting BLE work!"); - } - /*******************************************************************/ -}; - - - -void setup() { - Serial.begin(115200); - - // Create the BLE Device - BLEDevice::init("ESP32"); - - // Create the BLE Server - pServer = BLEDevice::createServer(); - pServer->setCallbacks(new MyServerCallbacks()); - - // Create the BLE Service - BLEService *pService = pServer->createService(SERVICE_UUID); - - // Create a BLE Characteristic - pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID, - /******* Enum Type NIMBLE_PROPERTY now ******* - BLECharacteristic::PROPERTY_READ | - BLECharacteristic::PROPERTY_WRITE | - BLECharacteristic::PROPERTY_NOTIFY | - BLECharacteristic::PROPERTY_INDICATE - ); - **********************************************/ - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE | - NIMBLE_PROPERTY::NOTIFY | - NIMBLE_PROPERTY::INDICATE - ); - - // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml - // Create a BLE Descriptor - /*************************************************** - NOTE: DO NOT create a 2902 descriptor - it will be created automatically if notifications - or indications are enabled on a characteristic. - - pCharacteristic->addDescriptor(new BLE2902()); - ****************************************************/ - - // Start the service - pService->start(); - - // Start advertising - BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); - pAdvertising->addServiceUUID(SERVICE_UUID); - pAdvertising->setScanResponse(false); - /** Note, this could be left out as that is the default value */ - pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter - - BLEDevice::startAdvertising(); - Serial.println("Waiting a client connection to notify..."); -} - -void loop() { - // notify changed value - if (deviceConnected) { - pCharacteristic->setValue((uint8_t*)&value, 4); - pCharacteristic->notify(); - value++; - delay(10); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms - } - // disconnecting - if (!deviceConnected && oldDeviceConnected) { - delay(500); // give the bluetooth stack the chance to get things ready - pServer->startAdvertising(); // restart advertising - Serial.println("start advertising"); - oldDeviceConnected = deviceConnected; - } - // connecting - if (deviceConnected && !oldDeviceConnected) { - // do stuff here on connecting - oldDeviceConnected = deviceConnected; - } -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_uart/BLE_uart.ino b/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_uart/BLE_uart.ino deleted file mode 100644 index 0a31ef289..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_uart/BLE_uart.ino +++ /dev/null @@ -1,163 +0,0 @@ -/* - Video: https://www.youtube.com/watch?v=oCMOYS71NIU - Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp - Ported to Arduino ESP32 by Evandro Copercini - - Create a BLE server that, once we receive a connection, will send periodic notifications. - The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E - Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE" - Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY" - - The design of creating the BLE server is: - 1. Create a BLE Server - 2. Create a BLE Service - 3. Create a BLE Characteristic on the Service - 4. Create a BLE Descriptor on the characteristic - 5. Start the service. - 6. Start advertising. - - In this example rxValue is the data received (only accessible inside that function). - And txValue is the data to be sent, in this example just a byte incremented every second. -*/ - -/** NimBLE differences highlighted in comment blocks **/ - -/*******original******** -#include -#include -#include -#include -***********************/ -#include - -BLEServer *pServer = NULL; -BLECharacteristic * pTxCharacteristic; -bool deviceConnected = false; -bool oldDeviceConnected = false; -uint8_t txValue = 0; - -// See the following for generating UUIDs: -// https://www.uuidgenerator.net/ - -#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID -#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" -#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" - - -/** None of these are required as they will be handled by the library with defaults. ** - ** Remove as you see fit for your needs */ -class MyServerCallbacks: public BLEServerCallbacks { - void onConnect(BLEServer* pServer) { - deviceConnected = true; - }; - - void onDisconnect(BLEServer* pServer) { - deviceConnected = false; - } - /***************** New - Security handled here ******************** - ****** Note: these are the same return values as defaults ********/ - uint32_t onPassKeyRequest(){ - Serial.println("Server PassKeyRequest"); - return 123456; - } - - bool onConfirmPIN(uint32_t pass_key){ - Serial.print("The passkey YES/NO number: ");Serial.println(pass_key); - return true; - } - - void onAuthenticationComplete(ble_gap_conn_desc desc){ - Serial.println("Starting BLE work!"); - } - /*******************************************************************/ -}; - -class MyCallbacks: public BLECharacteristicCallbacks { - void onWrite(BLECharacteristic *pCharacteristic) { - std::string rxValue = pCharacteristic->getValue(); - - if (rxValue.length() > 0) { - Serial.println("*********"); - Serial.print("Received Value: "); - for (int i = 0; i < rxValue.length(); i++) - Serial.print(rxValue[i]); - - Serial.println(); - Serial.println("*********"); - } - } -}; - - -void setup() { - Serial.begin(115200); - - // Create the BLE Device - BLEDevice::init("UART Service"); - - // Create the BLE Server - pServer = BLEDevice::createServer(); - pServer->setCallbacks(new MyServerCallbacks()); - - // Create the BLE Service - BLEService *pService = pServer->createService(SERVICE_UUID); - - // Create a BLE Characteristic - pTxCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID_TX, - /******* Enum Type NIMBLE_PROPERTY now ******* - BLECharacteristic::PROPERTY_NOTIFY - ); - **********************************************/ - NIMBLE_PROPERTY::NOTIFY - ); - - /*************************************************** - NOTE: DO NOT create a 2902 descriptor - it will be created automatically if notifications - or indications are enabled on a characteristic. - - pCharacteristic->addDescriptor(new BLE2902()); - ****************************************************/ - - BLECharacteristic * pRxCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID_RX, - /******* Enum Type NIMBLE_PROPERTY now ******* - BLECharacteristic::PROPERTY_WRITE - ); - *********************************************/ - NIMBLE_PROPERTY::WRITE - ); - - pRxCharacteristic->setCallbacks(new MyCallbacks()); - - // Start the service - pService->start(); - - // Start advertising - pServer->getAdvertising()->start(); - Serial.println("Waiting a client connection to notify..."); -} - -void loop() { - - if (deviceConnected) { - pTxCharacteristic->setValue(&txValue, 1); - pTxCharacteristic->notify(); - txValue++; - delay(10); // bluetooth stack will go into congestion, if too many packets are sent - } - - // disconnecting - if (!deviceConnected && oldDeviceConnected) { - delay(500); // give the bluetooth stack the chance to get things ready - pServer->startAdvertising(); // restart advertising - Serial.println("start advertising"); - oldDeviceConnected = deviceConnected; - } - // connecting - if (deviceConnected && !oldDeviceConnected) { - // do stuff here on connecting - oldDeviceConnected = deviceConnected; - } -} diff --git a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_write/BLE_write.ino b/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_write/BLE_write.ino deleted file mode 100644 index b1eb0f83e..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/examples/Refactored_original_examples/BLE_write/BLE_write.ino +++ /dev/null @@ -1,75 +0,0 @@ -/* - Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleWrite.cpp - Ported to Arduino ESP32 by Evandro Copercini -*/ - -/** NimBLE differences highlighted in comment blocks **/ - -/*******original******** -#include -#include -#include -***********************/ -#include - -// See the following for generating UUIDs: -// https://www.uuidgenerator.net/ - -#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" -#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" - - -class MyCallbacks: public BLECharacteristicCallbacks { - void onWrite(BLECharacteristic *pCharacteristic) { - std::string value = pCharacteristic->getValue(); - - if (value.length() > 0) { - Serial.println("*********"); - Serial.print("New value: "); - for (int i = 0; i < value.length(); i++) - Serial.print(value[i]); - - Serial.println(); - Serial.println("*********"); - } - } -}; - -void setup() { - Serial.begin(115200); - - Serial.println("1- Download and install an BLE scanner app in your phone"); - Serial.println("2- Scan for BLE devices in the app"); - Serial.println("3- Connect to MyESP32"); - Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something"); - Serial.println("5- See the magic =)"); - - BLEDevice::init("MyESP32"); - BLEServer *pServer = BLEDevice::createServer(); - - BLEService *pService = pServer->createService(SERVICE_UUID); - - BLECharacteristic *pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID, - /***** Enum Type NIMBLE_PROPERTY now ***** - BLECharacteristic::PROPERTY_READ | - BLECharacteristic::PROPERTY_WRITE - ); - *****************************************/ - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE - ); - - pCharacteristic->setCallbacks(new MyCallbacks()); - - pCharacteristic->setValue("Hello World"); - pService->start(); - - BLEAdvertising *pAdvertising = pServer->getAdvertising(); - pAdvertising->start(); -} - -void loop() { - // put your main code here, to run repeatedly: - delay(2000); -} \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/library.json b/lib/libesp32_div/NimBLE-Arduino/library.json deleted file mode 100644 index 1f55748d6..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/library.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "NimBLE-Arduino", - "keywords": "esp32, bluetooth", - "description": "Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE", - "version": "1.4.1", - "frameworks": "arduino", - "platforms": "espressif32" -} diff --git a/lib/libesp32_div/NimBLE-Arduino/library.properties b/lib/libesp32_div/NimBLE-Arduino/library.properties deleted file mode 100644 index d1b32b9cf..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/library.properties +++ /dev/null @@ -1,10 +0,0 @@ -name=NimBLE-Arduino -version=1.4.1 -author=h2zero -maintainer=h2zero -sentence=Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE. -paragraph=This is a more updated and lower resource alternative to the original bluedroid BLE library for esp32. Uses 50% less flash space and approximately 100KB less ram with the same functionality. Nearly 100% compatible with existing application code, migration guide included. -url=https://github.com/h2zero/NimBLE-Arduino -category=Communication -architectures=esp32,arm-ble -includes=NimBLEDevice.h \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/HIDKeyboardTypes.h b/lib/libesp32_div/NimBLE-Arduino/src/HIDKeyboardTypes.h deleted file mode 100644 index 531437ee4..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/HIDKeyboardTypes.h +++ /dev/null @@ -1,402 +0,0 @@ -/* Copyright (c) 2015 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Note: this file was pulled from different parts of the USBHID library, in mbed SDK - */ - -#ifndef KEYBOARD_DEFS_H -#define KEYBOARD_DEFS_H - -#define REPORT_ID_KEYBOARD 1 -#define REPORT_ID_VOLUME 3 - -/* Modifiers */ -enum MODIFIER_KEY { - KEY_CTRL = 1, - KEY_SHIFT = 2, - KEY_ALT = 4, -}; - - -enum MEDIA_KEY { - KEY_NEXT_TRACK, /*!< next Track Button */ - KEY_PREVIOUS_TRACK, /*!< Previous track Button */ - KEY_STOP, /*!< Stop Button */ - KEY_PLAY_PAUSE, /*!< Play/Pause Button */ - KEY_MUTE, /*!< Mute Button */ - KEY_VOLUME_UP, /*!< Volume Up Button */ - KEY_VOLUME_DOWN, /*!< Volume Down Button */ -}; - -enum FUNCTION_KEY { - KEY_F1 = 128, /* F1 key */ - KEY_F2, /* F2 key */ - KEY_F3, /* F3 key */ - KEY_F4, /* F4 key */ - KEY_F5, /* F5 key */ - KEY_F6, /* F6 key */ - KEY_F7, /* F7 key */ - KEY_F8, /* F8 key */ - KEY_F9, /* F9 key */ - KEY_F10, /* F10 key */ - KEY_F11, /* F11 key */ - KEY_F12, /* F12 key */ - - KEY_PRINT_SCREEN, /* Print Screen key */ - KEY_SCROLL_LOCK, /* Scroll lock */ - KEY_CAPS_LOCK, /* caps lock */ - KEY_NUM_LOCK, /* num lock */ - KEY_INSERT, /* Insert key */ - KEY_HOME, /* Home key */ - KEY_PAGE_UP, /* Page Up key */ - KEY_PAGE_DOWN, /* Page Down key */ - - RIGHT_ARROW, /* Right arrow */ - LEFT_ARROW, /* Left arrow */ - DOWN_ARROW, /* Down arrow */ - UP_ARROW, /* Up arrow */ -}; - -typedef struct { - unsigned char usage; - unsigned char modifier; -} KEYMAP; - -#ifdef US_KEYBOARD -/* US keyboard (as HID standard) */ -#define KEYMAP_SIZE (152) -const KEYMAP keymap[KEYMAP_SIZE] = { - {0, 0}, /* NUL */ - {0, 0}, /* SOH */ - {0, 0}, /* STX */ - {0, 0}, /* ETX */ - {0, 0}, /* EOT */ - {0, 0}, /* ENQ */ - {0, 0}, /* ACK */ - {0, 0}, /* BEL */ - {0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */ - {0x2b, 0}, /* TAB */ /* Keyboard Tab */ - {0x28, 0}, /* LF */ /* Keyboard Return (Enter) */ - {0, 0}, /* VT */ - {0, 0}, /* FF */ - {0, 0}, /* CR */ - {0, 0}, /* SO */ - {0, 0}, /* SI */ - {0, 0}, /* DEL */ - {0, 0}, /* DC1 */ - {0, 0}, /* DC2 */ - {0, 0}, /* DC3 */ - {0, 0}, /* DC4 */ - {0, 0}, /* NAK */ - {0, 0}, /* SYN */ - {0, 0}, /* ETB */ - {0, 0}, /* CAN */ - {0, 0}, /* EM */ - {0, 0}, /* SUB */ - {0, 0}, /* ESC */ - {0, 0}, /* FS */ - {0, 0}, /* GS */ - {0, 0}, /* RS */ - {0, 0}, /* US */ - {0x2c, 0}, /* */ - {0x1e, KEY_SHIFT}, /* ! */ - {0x34, KEY_SHIFT}, /* " */ - {0x20, KEY_SHIFT}, /* # */ - {0x21, KEY_SHIFT}, /* $ */ - {0x22, KEY_SHIFT}, /* % */ - {0x24, KEY_SHIFT}, /* & */ - {0x34, 0}, /* ' */ - {0x26, KEY_SHIFT}, /* ( */ - {0x27, KEY_SHIFT}, /* ) */ - {0x25, KEY_SHIFT}, /* * */ - {0x2e, KEY_SHIFT}, /* + */ - {0x36, 0}, /* , */ - {0x2d, 0}, /* - */ - {0x37, 0}, /* . */ - {0x38, 0}, /* / */ - {0x27, 0}, /* 0 */ - {0x1e, 0}, /* 1 */ - {0x1f, 0}, /* 2 */ - {0x20, 0}, /* 3 */ - {0x21, 0}, /* 4 */ - {0x22, 0}, /* 5 */ - {0x23, 0}, /* 6 */ - {0x24, 0}, /* 7 */ - {0x25, 0}, /* 8 */ - {0x26, 0}, /* 9 */ - {0x33, KEY_SHIFT}, /* : */ - {0x33, 0}, /* ; */ - {0x36, KEY_SHIFT}, /* < */ - {0x2e, 0}, /* = */ - {0x37, KEY_SHIFT}, /* > */ - {0x38, KEY_SHIFT}, /* ? */ - {0x1f, KEY_SHIFT}, /* @ */ - {0x04, KEY_SHIFT}, /* A */ - {0x05, KEY_SHIFT}, /* B */ - {0x06, KEY_SHIFT}, /* C */ - {0x07, KEY_SHIFT}, /* D */ - {0x08, KEY_SHIFT}, /* E */ - {0x09, KEY_SHIFT}, /* F */ - {0x0a, KEY_SHIFT}, /* G */ - {0x0b, KEY_SHIFT}, /* H */ - {0x0c, KEY_SHIFT}, /* I */ - {0x0d, KEY_SHIFT}, /* J */ - {0x0e, KEY_SHIFT}, /* K */ - {0x0f, KEY_SHIFT}, /* L */ - {0x10, KEY_SHIFT}, /* M */ - {0x11, KEY_SHIFT}, /* N */ - {0x12, KEY_SHIFT}, /* O */ - {0x13, KEY_SHIFT}, /* P */ - {0x14, KEY_SHIFT}, /* Q */ - {0x15, KEY_SHIFT}, /* R */ - {0x16, KEY_SHIFT}, /* S */ - {0x17, KEY_SHIFT}, /* T */ - {0x18, KEY_SHIFT}, /* U */ - {0x19, KEY_SHIFT}, /* V */ - {0x1a, KEY_SHIFT}, /* W */ - {0x1b, KEY_SHIFT}, /* X */ - {0x1c, KEY_SHIFT}, /* Y */ - {0x1d, KEY_SHIFT}, /* Z */ - {0x2f, 0}, /* [ */ - {0x31, 0}, /* \ */ - {0x30, 0}, /* ] */ - {0x23, KEY_SHIFT}, /* ^ */ - {0x2d, KEY_SHIFT}, /* _ */ - {0x35, 0}, /* ` */ - {0x04, 0}, /* a */ - {0x05, 0}, /* b */ - {0x06, 0}, /* c */ - {0x07, 0}, /* d */ - {0x08, 0}, /* e */ - {0x09, 0}, /* f */ - {0x0a, 0}, /* g */ - {0x0b, 0}, /* h */ - {0x0c, 0}, /* i */ - {0x0d, 0}, /* j */ - {0x0e, 0}, /* k */ - {0x0f, 0}, /* l */ - {0x10, 0}, /* m */ - {0x11, 0}, /* n */ - {0x12, 0}, /* o */ - {0x13, 0}, /* p */ - {0x14, 0}, /* q */ - {0x15, 0}, /* r */ - {0x16, 0}, /* s */ - {0x17, 0}, /* t */ - {0x18, 0}, /* u */ - {0x19, 0}, /* v */ - {0x1a, 0}, /* w */ - {0x1b, 0}, /* x */ - {0x1c, 0}, /* y */ - {0x1d, 0}, /* z */ - {0x2f, KEY_SHIFT}, /* { */ - {0x31, KEY_SHIFT}, /* | */ - {0x30, KEY_SHIFT}, /* } */ - {0x35, KEY_SHIFT}, /* ~ */ - {0,0}, /* DEL */ - - {0x3a, 0}, /* F1 */ - {0x3b, 0}, /* F2 */ - {0x3c, 0}, /* F3 */ - {0x3d, 0}, /* F4 */ - {0x3e, 0}, /* F5 */ - {0x3f, 0}, /* F6 */ - {0x40, 0}, /* F7 */ - {0x41, 0}, /* F8 */ - {0x42, 0}, /* F9 */ - {0x43, 0}, /* F10 */ - {0x44, 0}, /* F11 */ - {0x45, 0}, /* F12 */ - - {0x46, 0}, /* PRINT_SCREEN */ - {0x47, 0}, /* SCROLL_LOCK */ - {0x39, 0}, /* CAPS_LOCK */ - {0x53, 0}, /* NUM_LOCK */ - {0x49, 0}, /* INSERT */ - {0x4a, 0}, /* HOME */ - {0x4b, 0}, /* PAGE_UP */ - {0x4e, 0}, /* PAGE_DOWN */ - - {0x4f, 0}, /* RIGHT_ARROW */ - {0x50, 0}, /* LEFT_ARROW */ - {0x51, 0}, /* DOWN_ARROW */ - {0x52, 0}, /* UP_ARROW */ -}; - -#else -/* UK keyboard */ -#define KEYMAP_SIZE (152) -const KEYMAP keymap[KEYMAP_SIZE] = { - {0, 0}, /* NUL */ - {0, 0}, /* SOH */ - {0, 0}, /* STX */ - {0, 0}, /* ETX */ - {0, 0}, /* EOT */ - {0, 0}, /* ENQ */ - {0, 0}, /* ACK */ - {0, 0}, /* BEL */ - {0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */ - {0x2b, 0}, /* TAB */ /* Keyboard Tab */ - {0x28, 0}, /* LF */ /* Keyboard Return (Enter) */ - {0, 0}, /* VT */ - {0, 0}, /* FF */ - {0, 0}, /* CR */ - {0, 0}, /* SO */ - {0, 0}, /* SI */ - {0, 0}, /* DEL */ - {0, 0}, /* DC1 */ - {0, 0}, /* DC2 */ - {0, 0}, /* DC3 */ - {0, 0}, /* DC4 */ - {0, 0}, /* NAK */ - {0, 0}, /* SYN */ - {0, 0}, /* ETB */ - {0, 0}, /* CAN */ - {0, 0}, /* EM */ - {0, 0}, /* SUB */ - {0, 0}, /* ESC */ - {0, 0}, /* FS */ - {0, 0}, /* GS */ - {0, 0}, /* RS */ - {0, 0}, /* US */ - {0x2c, 0}, /* */ - {0x1e, KEY_SHIFT}, /* ! */ - {0x1f, KEY_SHIFT}, /* " */ - {0x32, 0}, /* # */ - {0x21, KEY_SHIFT}, /* $ */ - {0x22, KEY_SHIFT}, /* % */ - {0x24, KEY_SHIFT}, /* & */ - {0x34, 0}, /* ' */ - {0x26, KEY_SHIFT}, /* ( */ - {0x27, KEY_SHIFT}, /* ) */ - {0x25, KEY_SHIFT}, /* * */ - {0x2e, KEY_SHIFT}, /* + */ - {0x36, 0}, /* , */ - {0x2d, 0}, /* - */ - {0x37, 0}, /* . */ - {0x38, 0}, /* / */ - {0x27, 0}, /* 0 */ - {0x1e, 0}, /* 1 */ - {0x1f, 0}, /* 2 */ - {0x20, 0}, /* 3 */ - {0x21, 0}, /* 4 */ - {0x22, 0}, /* 5 */ - {0x23, 0}, /* 6 */ - {0x24, 0}, /* 7 */ - {0x25, 0}, /* 8 */ - {0x26, 0}, /* 9 */ - {0x33, KEY_SHIFT}, /* : */ - {0x33, 0}, /* ; */ - {0x36, KEY_SHIFT}, /* < */ - {0x2e, 0}, /* = */ - {0x37, KEY_SHIFT}, /* > */ - {0x38, KEY_SHIFT}, /* ? */ - {0x34, KEY_SHIFT}, /* @ */ - {0x04, KEY_SHIFT}, /* A */ - {0x05, KEY_SHIFT}, /* B */ - {0x06, KEY_SHIFT}, /* C */ - {0x07, KEY_SHIFT}, /* D */ - {0x08, KEY_SHIFT}, /* E */ - {0x09, KEY_SHIFT}, /* F */ - {0x0a, KEY_SHIFT}, /* G */ - {0x0b, KEY_SHIFT}, /* H */ - {0x0c, KEY_SHIFT}, /* I */ - {0x0d, KEY_SHIFT}, /* J */ - {0x0e, KEY_SHIFT}, /* K */ - {0x0f, KEY_SHIFT}, /* L */ - {0x10, KEY_SHIFT}, /* M */ - {0x11, KEY_SHIFT}, /* N */ - {0x12, KEY_SHIFT}, /* O */ - {0x13, KEY_SHIFT}, /* P */ - {0x14, KEY_SHIFT}, /* Q */ - {0x15, KEY_SHIFT}, /* R */ - {0x16, KEY_SHIFT}, /* S */ - {0x17, KEY_SHIFT}, /* T */ - {0x18, KEY_SHIFT}, /* U */ - {0x19, KEY_SHIFT}, /* V */ - {0x1a, KEY_SHIFT}, /* W */ - {0x1b, KEY_SHIFT}, /* X */ - {0x1c, KEY_SHIFT}, /* Y */ - {0x1d, KEY_SHIFT}, /* Z */ - {0x2f, 0}, /* [ */ - {0x64, 0}, /* \ */ - {0x30, 0}, /* ] */ - {0x23, KEY_SHIFT}, /* ^ */ - {0x2d, KEY_SHIFT}, /* _ */ - {0x35, 0}, /* ` */ - {0x04, 0}, /* a */ - {0x05, 0}, /* b */ - {0x06, 0}, /* c */ - {0x07, 0}, /* d */ - {0x08, 0}, /* e */ - {0x09, 0}, /* f */ - {0x0a, 0}, /* g */ - {0x0b, 0}, /* h */ - {0x0c, 0}, /* i */ - {0x0d, 0}, /* j */ - {0x0e, 0}, /* k */ - {0x0f, 0}, /* l */ - {0x10, 0}, /* m */ - {0x11, 0}, /* n */ - {0x12, 0}, /* o */ - {0x13, 0}, /* p */ - {0x14, 0}, /* q */ - {0x15, 0}, /* r */ - {0x16, 0}, /* s */ - {0x17, 0}, /* t */ - {0x18, 0}, /* u */ - {0x19, 0}, /* v */ - {0x1a, 0}, /* w */ - {0x1b, 0}, /* x */ - {0x1c, 0}, /* y */ - {0x1d, 0}, /* z */ - {0x2f, KEY_SHIFT}, /* { */ - {0x64, KEY_SHIFT}, /* | */ - {0x30, KEY_SHIFT}, /* } */ - {0x32, KEY_SHIFT}, /* ~ */ - {0,0}, /* DEL */ - - {0x3a, 0}, /* F1 */ - {0x3b, 0}, /* F2 */ - {0x3c, 0}, /* F3 */ - {0x3d, 0}, /* F4 */ - {0x3e, 0}, /* F5 */ - {0x3f, 0}, /* F6 */ - {0x40, 0}, /* F7 */ - {0x41, 0}, /* F8 */ - {0x42, 0}, /* F9 */ - {0x43, 0}, /* F10 */ - {0x44, 0}, /* F11 */ - {0x45, 0}, /* F12 */ - - {0x46, 0}, /* PRINT_SCREEN */ - {0x47, 0}, /* SCROLL_LOCK */ - {0x39, 0}, /* CAPS_LOCK */ - {0x53, 0}, /* NUM_LOCK */ - {0x49, 0}, /* INSERT */ - {0x4a, 0}, /* HOME */ - {0x4b, 0}, /* PAGE_UP */ - {0x4e, 0}, /* PAGE_DOWN */ - - {0x4f, 0}, /* RIGHT_ARROW */ - {0x50, 0}, /* LEFT_ARROW */ - {0x51, 0}, /* DOWN_ARROW */ - {0x52, 0}, /* UP_ARROW */ -}; -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/HIDTypes.h b/lib/libesp32_div/NimBLE-Arduino/src/HIDTypes.h deleted file mode 100644 index 8ee31dae6..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/HIDTypes.h +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (c) 2010-2011 mbed.org, MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without -* restriction, including without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING -* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef USBCLASS_HID_TYPES -#define USBCLASS_HID_TYPES - -#include - -/* */ -#define HID_VERSION_1_11 (0x0111) - -/* HID Class */ -#define HID_CLASS (3) -#define HID_SUBCLASS_NONE (0) -#define HID_PROTOCOL_NONE (0) - -/* Descriptors */ -#define HID_DESCRIPTOR (33) -#define HID_DESCRIPTOR_LENGTH (0x09) -#define REPORT_DESCRIPTOR (34) - -/* Class requests */ -#define GET_REPORT (0x1) -#define GET_IDLE (0x2) -#define SET_REPORT (0x9) -#define SET_IDLE (0xa) - -/* HID Class Report Descriptor */ -/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */ -/* of data as per HID Class standard */ - -/* Main items */ -#define HIDINPUT(size) (0x80 | size) -#define HIDOUTPUT(size) (0x90 | size) -#define FEATURE(size) (0xb0 | size) -#define COLLECTION(size) (0xa0 | size) -#define END_COLLECTION(size) (0xc0 | size) - -/* Global items */ -#define USAGE_PAGE(size) (0x04 | size) -#define LOGICAL_MINIMUM(size) (0x14 | size) -#define LOGICAL_MAXIMUM(size) (0x24 | size) -#define PHYSICAL_MINIMUM(size) (0x34 | size) -#define PHYSICAL_MAXIMUM(size) (0x44 | size) -#define UNIT_EXPONENT(size) (0x54 | size) -#define UNIT(size) (0x64 | size) -#define REPORT_SIZE(size) (0x74 | size) //bits -#define REPORT_ID(size) (0x84 | size) -#define REPORT_COUNT(size) (0x94 | size) //bytes -#define PUSH(size) (0xa4 | size) -#define POP(size) (0xb4 | size) - -/* Local items */ -#define USAGE(size) (0x08 | size) -#define USAGE_MINIMUM(size) (0x18 | size) -#define USAGE_MAXIMUM(size) (0x28 | size) -#define DESIGNATOR_INDEX(size) (0x38 | size) -#define DESIGNATOR_MINIMUM(size) (0x48 | size) -#define DESIGNATOR_MAXIMUM(size) (0x58 | size) -#define STRING_INDEX(size) (0x78 | size) -#define STRING_MINIMUM(size) (0x88 | size) -#define STRING_MAXIMUM(size) (0x98 | size) -#define DELIMITER(size) (0xa8 | size) - -/* HID Report */ -/* Where report IDs are used the first byte of 'data' will be the */ -/* report ID and 'length' will include this report ID byte. */ - -#define MAX_HID_REPORT_SIZE (64) - -typedef struct { - uint32_t length; - uint8_t data[MAX_HID_REPORT_SIZE]; -} HID_REPORT; - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLE2904.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLE2904.cpp deleted file mode 100644 index b518d9b00..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLE2904.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * NimBLE2904.cpp - * - * Created: on March 13, 2020 - * Author H2zero - * - * Originally: - * - * BLE2904.cpp - * - * Created on: Dec 23, 2017 - * Author: kolban - */ - -/* - * See also: - * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml - */ -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include "NimBLE2904.h" - - -NimBLE2904::NimBLE2904(NimBLECharacteristic* pCharacteristic) -: NimBLEDescriptor(NimBLEUUID((uint16_t) 0x2904), - BLE_GATT_CHR_F_READ, - sizeof(BLE2904_Data), - pCharacteristic) -{ - m_data.m_format = 0; - m_data.m_exponent = 0; - m_data.m_namespace = 1; // 1 = Bluetooth SIG Assigned Numbers - m_data.m_unit = 0; - m_data.m_description = 0; - setValue((uint8_t*) &m_data, sizeof(m_data)); -} // BLE2904 - - -/** - * @brief Set the description. - */ -void NimBLE2904::setDescription(uint16_t description) { - m_data.m_description = description; - setValue((uint8_t*) &m_data, sizeof(m_data)); -} - - -/** - * @brief Set the exponent. - */ -void NimBLE2904::setExponent(int8_t exponent) { - m_data.m_exponent = exponent; - setValue((uint8_t*) &m_data, sizeof(m_data)); -} // setExponent - - -/** - * @brief Set the format. - */ -void NimBLE2904::setFormat(uint8_t format) { - m_data.m_format = format; - setValue((uint8_t*) &m_data, sizeof(m_data)); -} // setFormat - - -/** - * @brief Set the namespace. - */ -void NimBLE2904::setNamespace(uint8_t namespace_value) { - m_data.m_namespace = namespace_value; - setValue((uint8_t*) &m_data, sizeof(m_data)); -} // setNamespace - - -/** - * @brief Set the units for this value. It should be one of the encoded values defined here: - * https://www.bluetooth.com/specifications/assigned-numbers/units - * @param [in] unit The type of units of this characteristic as defined by assigned numbers. - */ -void NimBLE2904::setUnit(uint16_t unit) { - m_data.m_unit = unit; - setValue((uint8_t*) &m_data, sizeof(m_data)); -} // setUnit - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLE2904.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLE2904.h deleted file mode 100644 index 29dde51e8..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLE2904.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * NimBLE2904.h - * - * Created: on March 13, 2020 - * Author H2zero - * - * Originally: - * - * BLE2904.h - * - * Created on: Dec 23, 2017 - * Author: kolban - */ - -#ifndef MAIN_NIMBLE2904_H_ -#define MAIN_NIMBLE2904_H_ -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include "NimBLEDescriptor.h" - -struct BLE2904_Data { - uint8_t m_format; - int8_t m_exponent; - uint16_t m_unit; // See https://www.bluetooth.com/specifications/assigned-numbers/units - uint8_t m_namespace; - uint16_t m_description; - -} __attribute__((packed)); - - -/** - * @brief Descriptor for Characteristic Presentation Format. - * - * This is a convenience descriptor for the Characteristic Presentation Format which has a UUID of 0x2904. - * - * See also: - * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml - */ -class NimBLE2904: public NimBLEDescriptor { -public: - NimBLE2904(NimBLECharacteristic* pCharacterisitic = nullptr); - static const uint8_t FORMAT_BOOLEAN = 1; - static const uint8_t FORMAT_UINT2 = 2; - static const uint8_t FORMAT_UINT4 = 3; - static const uint8_t FORMAT_UINT8 = 4; - static const uint8_t FORMAT_UINT12 = 5; - static const uint8_t FORMAT_UINT16 = 6; - static const uint8_t FORMAT_UINT24 = 7; - static const uint8_t FORMAT_UINT32 = 8; - static const uint8_t FORMAT_UINT48 = 9; - static const uint8_t FORMAT_UINT64 = 10; - static const uint8_t FORMAT_UINT128 = 11; - static const uint8_t FORMAT_SINT8 = 12; - static const uint8_t FORMAT_SINT12 = 13; - static const uint8_t FORMAT_SINT16 = 14; - static const uint8_t FORMAT_SINT24 = 15; - static const uint8_t FORMAT_SINT32 = 16; - static const uint8_t FORMAT_SINT48 = 17; - static const uint8_t FORMAT_SINT64 = 18; - static const uint8_t FORMAT_SINT128 = 19; - static const uint8_t FORMAT_FLOAT32 = 20; - static const uint8_t FORMAT_FLOAT64 = 21; - static const uint8_t FORMAT_SFLOAT16 = 22; - static const uint8_t FORMAT_SFLOAT32 = 23; - static const uint8_t FORMAT_IEEE20601 = 24; - static const uint8_t FORMAT_UTF8 = 25; - static const uint8_t FORMAT_UTF16 = 26; - static const uint8_t FORMAT_OPAQUE = 27; - - void setDescription(uint16_t); - void setExponent(int8_t exponent); - void setFormat(uint8_t format); - void setNamespace(uint8_t namespace_value); - void setUnit(uint16_t unit); - -private: - friend class NimBLECharacteristic; - BLE2904_Data m_data; -}; // BLE2904 - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */ -#endif /* MAIN_NIMBLE2904_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAddress.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAddress.cpp deleted file mode 100644 index d8ce5e88c..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAddress.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - * NimBLEAddress.cpp - * - * Created: on Jan 24 2020 - * Author H2zero - * - * Originally: - * - * BLEAddress.cpp - * - * Created on: Jul 2, 2017 - * Author: kolban - */ -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include - -#include "NimBLEAddress.h" -#include "NimBLEUtils.h" -#include "NimBLELog.h" - -static const char* LOG_TAG = "NimBLEAddress"; - -/************************************************* - * NOTE: NimBLE address bytes are in INVERSE ORDER! - * We will accomodate that fact in these methods. -*************************************************/ - -/** - * @brief Create an address from the native NimBLE representation. - * @param [in] address The native NimBLE address. - */ -NimBLEAddress::NimBLEAddress(ble_addr_t address) { - memcpy(m_address, address.val, 6); - m_addrType = address.type; -} // NimBLEAddress - - -/** - * @brief Create a blank address, i.e. 00:00:00:00:00:00, type 0. - */ -NimBLEAddress::NimBLEAddress() { - NimBLEAddress(""); -} // NimBLEAddress - - -/** - * @brief Create an address from a hex string - * - * A hex string is of the format: - * ``` - * 00:00:00:00:00:00 - * ``` - * which is 17 characters in length. - * - * @param [in] stringAddress The hex string representation of the address. - * @param [in] type The type of the address. - */ -NimBLEAddress::NimBLEAddress(const std::string &stringAddress, uint8_t type) { - m_addrType = type; - - if (stringAddress.length() == 0) { - memset(m_address, 0, 6); - return; - } - - if (stringAddress.length() == 6) { - std::reverse_copy(stringAddress.data(), stringAddress.data() + 6, m_address); - return; - } - - if (stringAddress.length() != 17) { - memset(m_address, 0, sizeof m_address); // "00:00:00:00:00:00" represents an invalid address - NIMBLE_LOGD(LOG_TAG, "Invalid address '%s'", stringAddress.c_str()); - return; - } - - int data[6]; - if(sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[5], &data[4], &data[3], &data[2], &data[1], &data[0]) != 6) { - memset(m_address, 0, sizeof m_address); // "00:00:00:00:00:00" represents an invalid address - NIMBLE_LOGD(LOG_TAG, "Invalid address '%s'", stringAddress.c_str()); - } - for(size_t index = 0; index < sizeof m_address; index++) { - m_address[index] = data[index]; - } -} // NimBLEAddress - - -/** - * @brief Constructor for compatibility with bluedroid esp library using native ESP representation. - * @param [in] address A uint8_t[6] or esp_bd_addr_t containing the address. - * @param [in] type The type of the address. - */ -NimBLEAddress::NimBLEAddress(uint8_t address[6], uint8_t type) { - std::reverse_copy(address, address + sizeof m_address, m_address); - m_addrType = type; -} // NimBLEAddress - - -/** - * @brief Constructor for address using a hex value.\n - * Use the same byte order, so use 0xa4c1385def16 for "a4:c1:38:5d:ef:16" - * @param [in] address uint64_t containing the address. - * @param [in] type The type of the address. - */ -NimBLEAddress::NimBLEAddress(const uint64_t &address, uint8_t type) { - memcpy(m_address, &address, sizeof m_address); - m_addrType = type; -} // NimBLEAddress - - -/** - * @brief Determine if this address equals another. - * @param [in] otherAddress The other address to compare against. - * @return True if the addresses are equal. - */ -bool NimBLEAddress::equals(const NimBLEAddress &otherAddress) const { - return *this == otherAddress; -} // equals - - -/** - * @brief Get the native representation of the address. - * @return a pointer to the uint8_t[6] array of the address. - */ -const uint8_t *NimBLEAddress::getNative() const { - return m_address; -} // getNative - - -/** - * @brief Get the address type. - * @return The address type. - */ -uint8_t NimBLEAddress::getType() const { - return m_addrType; -} // getType - - -/** - * @brief Convert a BLE address to a string. - * - * A string representation of an address is in the format: - * - * ``` - * xx:xx:xx:xx:xx:xx - * ``` - * - * @return The string representation of the address. - * @deprecated Use std::string() operator instead. - */ -std::string NimBLEAddress::toString() const { - return std::string(*this); -} // toString - - -/** - * @brief Convenience operator to check if this address is equal to another. - */ -bool NimBLEAddress::operator ==(const NimBLEAddress & rhs) const { - return memcmp(rhs.m_address, m_address, sizeof m_address) == 0; -} // operator == - - -/** - * @brief Convenience operator to check if this address is not equal to another. - */ -bool NimBLEAddress::operator !=(const NimBLEAddress & rhs) const { - return !this->operator==(rhs); -} // operator != - - -/** - * @brief Convienience operator to convert this address to string representation. - * @details This allows passing NimBLEAddress to functions - * that accept std::string and/or or it's methods as a parameter. - */ -NimBLEAddress::operator std::string() const { - char buffer[18]; - snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", - m_address[5], m_address[4], m_address[3], - m_address[2], m_address[1], m_address[0]); - return std::string(buffer); -} // operator std::string - - -/** - * @brief Convenience operator to convert the native address representation to uint_64. - */ -NimBLEAddress::operator uint64_t() const { - uint64_t address = 0; - memcpy(&address, m_address, sizeof m_address); - return address; -} // operator uint64_t - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAddress.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAddress.h deleted file mode 100644 index a6e10a09c..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAddress.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * NimBLEAddress.h - * - * Created: on Jan 24 2020 - * Author H2zero - * - * Originally: - * - * BLEAddress.h - * - * Created on: Jul 2, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_NIMBLEADDRESS_H_ -#define COMPONENTS_NIMBLEADDRESS_H_ -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "nimble/ble.h" -#else -#include "nimble/nimble/include/nimble/ble.h" -#endif - -/**** FIX COMPILATION ****/ -#undef min -#undef max -/**************************/ - -#include -#include - -/** - * @brief A %BLE device address. - * - * Every %BLE device has a unique address which can be used to identify it and form connections. - */ -class NimBLEAddress { -public: - NimBLEAddress(); - NimBLEAddress(ble_addr_t address); - NimBLEAddress(uint8_t address[6], uint8_t type = BLE_ADDR_PUBLIC); - NimBLEAddress(const std::string &stringAddress, uint8_t type = BLE_ADDR_PUBLIC); - NimBLEAddress(const uint64_t &address, uint8_t type = BLE_ADDR_PUBLIC); - bool equals(const NimBLEAddress &otherAddress) const; - const uint8_t* getNative() const; - std::string toString() const; - uint8_t getType() const; - - bool operator ==(const NimBLEAddress & rhs) const; - bool operator !=(const NimBLEAddress & rhs) const; - operator std::string() const; - operator uint64_t() const; - -private: - uint8_t m_address[6]; - uint8_t m_addrType; -}; - -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_NIMBLEADDRESS_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAdvertisedDevice.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAdvertisedDevice.cpp deleted file mode 100644 index b4fb0f4de..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAdvertisedDevice.cpp +++ /dev/null @@ -1,864 +0,0 @@ -/* - * NimBLEAdvertisedDevice.cpp - * - * Created: on Jan 24 2020 - * Author H2zero - * - * Originally: - * - * BLEAdvertisedDevice.cpp - * - * Created on: Jul 3, 2017 - * Author: kolban - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) - -#include "NimBLEDevice.h" -#include "NimBLEAdvertisedDevice.h" -#include "NimBLEUtils.h" -#include "NimBLELog.h" - -#include - -static const char* LOG_TAG = "NimBLEAdvertisedDevice"; - - -/** - * @brief Constructor - */ -NimBLEAdvertisedDevice::NimBLEAdvertisedDevice() : - m_payload(62,0) -{ - m_advType = 0; - m_rssi = -9999; - m_callbackSent = false; - m_timestamp = 0; - m_advLength = 0; -} // NimBLEAdvertisedDevice - - -/** - * @brief Get the address of the advertising device. - * @return The address of the advertised device. - */ -NimBLEAddress NimBLEAdvertisedDevice::getAddress() { - return m_address; -} // getAddress - - -/** - * @brief Get the advertisement type. - * @return The advertising type the device is reporting: - * * BLE_HCI_ADV_TYPE_ADV_IND (0) - indirect advertising - * * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD (1) - direct advertising - high duty cycle - * * BLE_HCI_ADV_TYPE_ADV_SCAN_IND (2) - indirect scan response - * * BLE_HCI_ADV_TYPE_ADV_NONCONN_IND (3) - indirect advertising - not connectable - * * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD (4) - direct advertising - low duty cycle - */ -uint8_t NimBLEAdvertisedDevice::getAdvType() { - return m_advType; -} // getAdvType - - -/** - * @brief Get the appearance. - * - * A %BLE device can declare its own appearance. The appearance is how it would like to be shown to an end user - * typically in the form of an icon. - * - * @return The appearance of the advertised device. - */ -uint16_t NimBLEAdvertisedDevice::getAppearance() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_APPEARANCE, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length == BLE_HS_ADV_APPEARANCE_LEN + 1) { - return *field->value | *(field->value + 1) << 8; - } - } - - return 0; -} // getAppearance - - -/** - * @brief Get the advertisement interval. - * @return The advertisement interval in 0.625ms units. - */ -uint16_t NimBLEAdvertisedDevice::getAdvInterval() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length == BLE_HS_ADV_ADV_ITVL_LEN + 1) { - return *field->value | *(field->value + 1) << 8; - } - } - - return 0; -} // getAdvInterval - - -/** - * @brief Get the preferred min connection interval. - * @return The preferred min connection interval in 1.25ms units. - */ -uint16_t NimBLEAdvertisedDevice::getMinInterval() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) { - return *field->value | *(field->value + 1) << 8; - } - } - - return 0; -} // getMinInterval - - -/** - * @brief Get the preferred max connection interval. - * @return The preferred max connection interval in 1.25ms units. - */ -uint16_t NimBLEAdvertisedDevice::getMaxInterval() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) { - return *(field->value + 2) | *(field->value + 3) << 8; - } - } - - return 0; -} // getMaxInterval - - -/** - * @brief Get the manufacturer data. - * @return The manufacturer data of the advertised device. - */ -std::string NimBLEAdvertisedDevice::getManufacturerData() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_MFG_DATA, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length > 1) { - return std::string((char*)field->value, field->length - 1); - } - } - - return ""; -} // getManufacturerData - - -/** - * @brief Get the URI from the advertisement. - * @return The URI data. - */ -std::string NimBLEAdvertisedDevice::getURI() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_URI, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length > 1) { - return std::string((char*)field->value, field->length - 1); - } - } - - return ""; -} // getURI - - -/** - * @brief Get the advertised name. - * @return The name of the advertised device. - */ -std::string NimBLEAdvertisedDevice::getName() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_COMP_NAME, 0, &data_loc) > 0 || - findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME, 0, &data_loc) > 0) - { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length > 1) { - return std::string((char*)field->value, field->length - 1); - } - } - - return ""; -} // getName - - -/** - * @brief Get the RSSI. - * @return The RSSI of the advertised device. - */ -int NimBLEAdvertisedDevice::getRSSI() { - return m_rssi; -} // getRSSI - - -/** - * @brief Get the scan object that created this advertised device. - * @return The scan object. - */ -NimBLEScan* NimBLEAdvertisedDevice::getScan() { - return NimBLEDevice::getScan(); -} // getScan - - -/** - * @brief Get the number of target addresses. - * @return The number of addresses. - */ -uint8_t NimBLEAdvertisedDevice::getTargetAddressCount() { - uint8_t count = 0; - - count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR); - count += findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR); - - return count; -} - - -/** - * @brief Get the target address at the index. - * @param [in] index The index of the target address. - * @return The target address. - */ -NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) { - ble_hs_adv_field *field = nullptr; - uint8_t count = 0; - size_t data_loc = ULONG_MAX; - - index++; - count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, index, &data_loc); - - if (count < index) { - index -= count; - count = findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR, index, &data_loc); - } - - if(count > 0 && data_loc != ULONG_MAX) { - field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length < index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) { - index -= count - field->length / BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN; - } - if(field->length > index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) { - return NimBLEAddress(field->value + (index - 1) * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN); - } - } - - return NimBLEAddress(""); -} - - -/** - * @brief Get the service data. - * @param [in] index The index of the service data requested. - * @return The advertised service data or empty string if no data. - */ -std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) { - ble_hs_adv_field *field = nullptr; - uint8_t bytes; - size_t data_loc = findServiceData(index, &bytes); - - if(data_loc != ULONG_MAX) { - field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length > bytes) { - return std::string((char*)(field->value + bytes), field->length - bytes - 1); - } - } - - return ""; -} //getServiceData - - -/** - * @brief Get the service data. - * @param [in] uuid The uuid of the service data requested. - * @return The advertised service data or empty string if no data. - */ -std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) { - ble_hs_adv_field *field = nullptr; - uint8_t bytes; - uint8_t index = 0; - size_t data_loc = findServiceData(index, &bytes); - size_t plSize = m_payload.size() - 2; - uint8_t uuidBytes = uuid.bitSize() / 8; - - while(data_loc < plSize) { - field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(bytes == uuidBytes && NimBLEUUID(field->value, bytes, false) == uuid) { - return std::string((char*)(field->value + bytes), field->length - bytes - 1); - } - - index++; - data_loc = findServiceData(index, &bytes); - } - - NIMBLE_LOGI(LOG_TAG, "No service data found"); - return ""; -} //getServiceData - - -/** - * @brief Get the UUID of the service data at the index. - * @param [in] index The index of the service data UUID requested. - * @return The advertised service data UUID or an empty UUID if not found. - */ -NimBLEUUID NimBLEAdvertisedDevice::getServiceDataUUID(uint8_t index) { - ble_hs_adv_field *field = nullptr; - uint8_t bytes; - size_t data_loc = findServiceData(index, &bytes); - - if(data_loc != ULONG_MAX) { - field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length >= bytes) { - return NimBLEUUID(field->value, bytes, false); - } - } - - return NimBLEUUID(""); -} // getServiceDataUUID - - -/** - * @brief Find the service data at the index. - * @param [in] index The index of the service data to find. - * @param [in] bytes A pointer to storage for the number of the bytes in the UUID. - * @return The index in the vector where the data is located, ULONG_MAX if not found. - */ -size_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) { - size_t data_loc = 0; - uint8_t found = 0; - - *bytes = 0; - index++; - found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16, index, &data_loc); - if(found == index) { - *bytes = 2; - return data_loc; - } - - index -= found; - found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32, index, &data_loc); - if(found == index) { - *bytes = 4; - return data_loc; - } - - index -= found; - found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128, index, &data_loc); - if(found == index) { - *bytes = 16; - return data_loc; - } - - return ULONG_MAX; -} - - -/** - * @brief Get the count of advertised service data UUIDS - * @return The number of service data UUIDS in the vector. - */ -uint8_t NimBLEAdvertisedDevice::getServiceDataCount() { - uint8_t count = 0; - - count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16); - count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32); - count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128); - - return count; -} // getServiceDataCount - - -/** - * @brief Get the Service UUID. - * @param [in] index The index of the service UUID requested. - * @return The Service UUID of the advertised service, or an empty UUID if not found. - */ -NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) { - uint8_t count = 0; - size_t data_loc = 0; - uint8_t uuidBytes = 0; - uint8_t type = BLE_HS_ADV_TYPE_INCOMP_UUIDS16; - ble_hs_adv_field *field = nullptr; - - index++; - - do { - count = findAdvField(type, index, &data_loc); - if(count >= index) { - if(type < BLE_HS_ADV_TYPE_INCOMP_UUIDS32) { - uuidBytes = 2; - } else if(type < BLE_HS_ADV_TYPE_INCOMP_UUIDS128) { - uuidBytes = 4; - } else { - uuidBytes = 16; - } - break; - - } else { - type++; - index -= count; - } - - } while(type <= BLE_HS_ADV_TYPE_COMP_UUIDS128); - - if(uuidBytes > 0) { - field = (ble_hs_adv_field *)&m_payload[data_loc]; - // In the case of more than one field of service uuid's we need to adjust - // the index to account for the uuids of the previous fields. - if(field->length < index * uuidBytes) { - index -= count - field->length / uuidBytes; - } - - if(field->length > uuidBytes * index) { - return NimBLEUUID(field->value + uuidBytes * (index - 1), uuidBytes, false); - } - } - - return NimBLEUUID(""); -} // getServiceUUID - - -/** - * @brief Get the number of services advertised - * @return The count of services in the advertising packet. - */ -uint8_t NimBLEAdvertisedDevice::getServiceUUIDCount() { - uint8_t count = 0; - - count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS16); - count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS16); - count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS32); - count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS32); - count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS128); - count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS128); - - return count; -} // getServiceUUIDCount - - -/** - * @brief Check advertised services for existence of the required UUID - * @param [in] uuid The service uuid to look for in the advertisement. - * @return Return true if service is advertised - */ -bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) { - size_t count = getServiceUUIDCount(); - for(size_t i = 0; i < count; i++) { - if(uuid == getServiceUUID(i)) { - return true; - } - } - - return false; -} // isAdvertisingService - - -/** - * @brief Get the TX Power. - * @return The TX Power of the advertised device. - */ -int8_t NimBLEAdvertisedDevice::getTXPower() { - size_t data_loc = 0; - - if(findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL, 0, &data_loc) > 0) { - ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc]; - if(field->length == BLE_HS_ADV_TX_PWR_LVL_LEN + 1) { - return *(int8_t*)field->value; - } - } - - return -99; -} // getTXPower - - -/** - * @brief Does this advertisement have preferred connection parameters? - * @return True if connection parameters are present. - */ -bool NimBLEAdvertisedDevice::haveConnParams() { - return findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE) > 0; -} // haveConnParams - - -/** - * @brief Does this advertisement have have the advertising interval? - * @return True if the advertisement interval is present. - */ -bool NimBLEAdvertisedDevice::haveAdvInterval() { - return findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL) > 0; -} // haveAdvInterval - - -/** - * @brief Does this advertisement have an appearance value? - * @return True if there is an appearance value present. - */ -bool NimBLEAdvertisedDevice::haveAppearance() { - return findAdvField(BLE_HS_ADV_TYPE_APPEARANCE) > 0; -} // haveAppearance - - -/** - * @brief Does this advertisement have manufacturer data? - * @return True if there is manufacturer data present. - */ -bool NimBLEAdvertisedDevice::haveManufacturerData() { - return findAdvField(BLE_HS_ADV_TYPE_MFG_DATA) > 0; -} // haveManufacturerData - - -/** - * @brief Does this advertisement have a URI? - * @return True if there is a URI present. - */ -bool NimBLEAdvertisedDevice::haveURI() { - return findAdvField(BLE_HS_ADV_TYPE_URI) > 0; -} // haveURI - - -/** - * @brief Does the advertisement contain a target address? - * @return True if an address is present. - */ -bool NimBLEAdvertisedDevice::haveTargetAddress() { - return findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR) > 0 || - findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR) > 0; -} - - -/** - * @brief Does this advertisement have a name value? - * @return True if there is a name value present. - */ -bool NimBLEAdvertisedDevice::haveName() { - return findAdvField(BLE_HS_ADV_TYPE_COMP_NAME) > 0 || - findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME) > 0; -} // haveName - - -/** - * @brief Does this advertisement have a signal strength value? - * @return True if there is a signal strength value present. - */ -bool NimBLEAdvertisedDevice::haveRSSI() { - return m_rssi != -9999; -} // haveRSSI - - -/** - * @brief Does this advertisement have a service data value? - * @return True if there is a service data value present. - */ -bool NimBLEAdvertisedDevice::haveServiceData() { - return getServiceDataCount() > 0; -} // haveServiceData - - -/** - * @brief Does this advertisement have a service UUID value? - * @return True if there is a service UUID value present. - */ -bool NimBLEAdvertisedDevice::haveServiceUUID() { - return getServiceUUIDCount() > 0; -} // haveServiceUUID - - -/** - * @brief Does this advertisement have a transmission power value? - * @return True if there is a transmission power value present. - */ -bool NimBLEAdvertisedDevice::haveTXPower() { - return findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL) > 0; -} // haveTXPower - - -#if CONFIG_BT_NIMBLE_EXT_ADV -/** - * @brief Get the set ID of the extended advertisement. - * @return The set ID. - */ -uint8_t NimBLEAdvertisedDevice::getSetId() { - return m_sid; -} // getSetId - - -/** - * @brief Get the primary PHY used by this advertisement. - * @return The PHY type, one of: - * * BLE_HCI_LE_PHY_1M - * * BLE_HCI_LE_PHY_CODED - */ -uint8_t NimBLEAdvertisedDevice::getPrimaryPhy() { - return m_primPhy; -} // getPrimaryPhy - - -/** - * @brief Get the primary PHY used by this advertisement. - * @return The PHY type, one of: - * * BLE_HCI_LE_PHY_1M - * * BLE_HCI_LE_PHY_2M - * * BLE_HCI_LE_PHY_CODED - */ -uint8_t NimBLEAdvertisedDevice::getSecondaryPhy() { - return m_secPhy; -} // getSecondaryPhy - - -/** - * @brief Get the periodic interval of the advertisement. - * @return The periodic advertising interval, 0 if not periodic advertising. - */ -uint16_t NimBLEAdvertisedDevice::getPeriodicInterval() { - return m_periodicItvl; -} // getPeriodicInterval -#endif - - -uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, size_t * data_loc) { - ble_hs_adv_field *field = nullptr; - size_t length = m_payload.size(); - size_t data = 0; - uint8_t count = 0; - - if (length < 3) { - return count; - } - - while (length > 2) { - field = (ble_hs_adv_field*)&m_payload[data]; - - if (field->length >= length) { - return count; - } - - if (field->type == type) { - switch (type) { - case BLE_HS_ADV_TYPE_INCOMP_UUIDS16: - case BLE_HS_ADV_TYPE_COMP_UUIDS16: - count += field->length / 2; - break; - - case BLE_HS_ADV_TYPE_INCOMP_UUIDS32: - case BLE_HS_ADV_TYPE_COMP_UUIDS32: - count += field->length / 4; - break; - - case BLE_HS_ADV_TYPE_INCOMP_UUIDS128: - case BLE_HS_ADV_TYPE_COMP_UUIDS128: - count += field->length / 16; - break; - - case BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR: - case BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR: - count += field->length / 6; - break; - - default: - count++; - break; - } - - if (data_loc != nullptr) { - if (index == 0 || count >= index) { - break; - } - } - } - - length -= 1 + field->length; - data += 1 + field->length; - } - - if (data_loc != nullptr && field != nullptr) { - *data_loc = data; - } - - return count; -} - - -/** - * @brief Set the address of the advertised device. - * @param [in] address The address of the advertised device. - */ -void NimBLEAdvertisedDevice::setAddress(NimBLEAddress address) { - m_address = address; -} // setAddress - - -/** - * @brief Set the adFlag for this device. - * @param [in] advType The advertisement flag data from the advertisement. - */ -void NimBLEAdvertisedDevice::setAdvType(uint8_t advType, bool isLegacyAdv) { - m_advType = advType; -#if CONFIG_BT_NIMBLE_EXT_ADV - m_isLegacyAdv = isLegacyAdv; -#else - (void)isLegacyAdv; -#endif -} // setAdvType - - -/** - * @brief Set the RSSI for this device. - * @param [in] rssi The RSSI of the discovered device. - */ -void NimBLEAdvertisedDevice::setRSSI(int rssi) { - m_rssi = rssi; -} // setRSSI - - -/** - * @brief Create a string representation of this device. - * @return A string representation of this device. - */ -std::string NimBLEAdvertisedDevice::toString() { - std::string res = "Name: " + getName() + ", Address: " + getAddress().toString(); - - if (haveAppearance()) { - char val[6]; - snprintf(val, sizeof(val), "%d", getAppearance()); - res += ", appearance: "; - res += val; - } - - if (haveManufacturerData()) { - char *pHex = NimBLEUtils::buildHexData(nullptr, (uint8_t*)getManufacturerData().data(), getManufacturerData().length()); - res += ", manufacturer data: "; - res += pHex; - free(pHex); - } - - if (haveServiceUUID()) { - res += ", serviceUUID: " + getServiceUUID().toString(); - } - - if (haveTXPower()) { - char val[5]; - snprintf(val, sizeof(val), "%d", getTXPower()); - res += ", txPower: "; - res += val; - } - - if (haveServiceData()) { - uint8_t count = getServiceDataCount(); - res += "\nService Data:"; - for(uint8_t i = 0; i < count; i++) { - res += "\nUUID: " + std::string(getServiceDataUUID(i)); - res += ", Data: " + getServiceData(i); - } - } - - return res; - -} // toString - - -/** - * @brief Get the payload advertised by the device. - * @return The advertisement payload. - */ -uint8_t* NimBLEAdvertisedDevice::getPayload() { - return &m_payload[0]; -} // getPayload - - -/** - * @brief Stores the payload of the advertised device in a vector. - * @param [in] payload The advertisement payload. - * @param [in] length The length of the payload in bytes. - * @param [in] append Indicates if the the data should be appended (scan response). - */ -void NimBLEAdvertisedDevice::setPayload(const uint8_t *payload, uint8_t length, bool append) { - if(!append) { - m_advLength = length; - m_payload.assign(payload, payload + length); - } else { - m_payload.insert(m_payload.end(), payload, payload + length); - } -} - - -/** - * @brief Get the length of the advertisement data in the payload. - * @return The number of bytes in the payload that is from the advertisement. - */ -uint8_t NimBLEAdvertisedDevice::getAdvLength() { - return m_advLength; -} - - -/** - * @brief Get the advertised device address type. - * @return The device address type: - * * BLE_ADDR_PUBLIC (0x00) - * * BLE_ADDR_RANDOM (0x01) - * * BLE_ADDR_PUBLIC_ID (0x02) - * * BLE_ADDR_RANDOM_ID (0x03) - */ -uint8_t NimBLEAdvertisedDevice::getAddressType() { - return m_address.getType(); -} // getAddressType - - -/** - * @brief Get the timeStamp of when the device last advertised. - * @return The timeStamp of when the device was last seen. - */ -time_t NimBLEAdvertisedDevice::getTimestamp() { - return m_timestamp; -} // getTimestamp - - -/** - * @brief Get the length of the payload advertised by the device. - * @return The size of the payload in bytes. - */ -size_t NimBLEAdvertisedDevice::getPayloadLength() { - return m_payload.size(); -} // getPayloadLength - - -/** - * @brief Check if this device is advertising as connectable. - * @return True if the device is connectable. - */ -bool NimBLEAdvertisedDevice::isConnectable() { -#if CONFIG_BT_NIMBLE_EXT_ADV - if (m_isLegacyAdv) { - return m_advType == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND || - m_advType == BLE_HCI_ADV_RPT_EVTYPE_DIR_IND; - } -#endif - return (m_advType & BLE_HCI_ADV_CONN_MASK) || - (m_advType & BLE_HCI_ADV_DIRECT_MASK); -} // isConnectable - - -/** - * @brief Check if this advertisement is a legacy or extended type - * @return True if legacy (Bluetooth 4.x), false if extended (bluetooth 5.x). - */ -bool NimBLEAdvertisedDevice::isLegacyAdvertisement() { -#if CONFIG_BT_NIMBLE_EXT_ADV - return m_isLegacyAdv; -# else - return true; -#endif -} // isLegacyAdvertisement - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ - diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAdvertisedDevice.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAdvertisedDevice.h deleted file mode 100644 index 772bab914..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAdvertisedDevice.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * NimBLEAdvertisedDevice.h - * - * Created: on Jan 24 2020 - * Author H2zero - * - * Originally: - * - * BLEAdvertisedDevice.h - * - * Created on: Jul 3, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ -#define COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) - -#include "NimBLEAddress.h" -#include "NimBLEScan.h" -#include "NimBLEUUID.h" - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "host/ble_hs_adv.h" -#else -#include "nimble/nimble/host/include/host/ble_hs_adv.h" -#endif - -#include -#include -#include - - -class NimBLEScan; -/** - * @brief A representation of a %BLE advertised device found by a scan. - * - * When we perform a %BLE scan, the result will be a set of devices that are advertising. This - * class provides a model of a detected device. - */ -class NimBLEAdvertisedDevice { -public: - NimBLEAdvertisedDevice(); - - NimBLEAddress getAddress(); - uint8_t getAdvType(); - uint16_t getAppearance(); - uint16_t getAdvInterval(); - uint16_t getMinInterval(); - uint16_t getMaxInterval(); - std::string getManufacturerData(); - std::string getURI(); - - /** - * @brief A template to convert the service data to . - * @tparam T The type to convert the data to. - * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof(). - * @return The data converted to or NULL if skipSizeCheck is false and the data is - * less than sizeof(). - * @details Use: getManufacturerData(skipSizeCheck); - */ - template - T getManufacturerData(bool skipSizeCheck = false) { - std::string data = getManufacturerData(); - if(!skipSizeCheck && data.size() < sizeof(T)) return T(); - const char *pData = data.data(); - return *((T *)pData); - } - - std::string getName(); - int getRSSI(); - NimBLEScan* getScan(); - uint8_t getServiceDataCount(); - std::string getServiceData(uint8_t index = 0); - std::string getServiceData(const NimBLEUUID &uuid); - - /** - * @brief A template to convert the service data to . - * @tparam T The type to convert the data to. - * @param [in] index The vector index of the service data requested. - * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof(). - * @return The data converted to or NULL if skipSizeCheck is false and the data is - * less than sizeof(). - * @details Use: getServiceData(skipSizeCheck); - */ - template - T getServiceData(uint8_t index = 0, bool skipSizeCheck = false) { - std::string data = getServiceData(index); - if(!skipSizeCheck && data.size() < sizeof(T)) return T(); - const char *pData = data.data(); - return *((T *)pData); - } - - /** - * @brief A template to convert the service data to . - * @tparam T The type to convert the data to. - * @param [in] uuid The uuid of the service data requested. - * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof(). - * @return The data converted to or NULL if skipSizeCheck is false and the data is - * less than sizeof(). - * @details Use: getServiceData(skipSizeCheck); - */ - template - T getServiceData(const NimBLEUUID &uuid, bool skipSizeCheck = false) { - std::string data = getServiceData(uuid); - if(!skipSizeCheck && data.size() < sizeof(T)) return T(); - const char *pData = data.data(); - return *((T *)pData); - } - - NimBLEUUID getServiceDataUUID(uint8_t index = 0); - NimBLEUUID getServiceUUID(uint8_t index = 0); - uint8_t getServiceUUIDCount(); - NimBLEAddress getTargetAddress(uint8_t index = 0); - uint8_t getTargetAddressCount(); - int8_t getTXPower(); - uint8_t* getPayload(); - uint8_t getAdvLength(); - size_t getPayloadLength(); - uint8_t getAddressType(); - time_t getTimestamp(); - bool isAdvertisingService(const NimBLEUUID &uuid); - bool haveAppearance(); - bool haveManufacturerData(); - bool haveName(); - bool haveRSSI(); - bool haveServiceData(); - bool haveServiceUUID(); - bool haveTXPower(); - bool haveConnParams(); - bool haveAdvInterval(); - bool haveTargetAddress(); - bool haveURI(); - std::string toString(); - bool isConnectable(); - bool isLegacyAdvertisement(); -#if CONFIG_BT_NIMBLE_EXT_ADV - uint8_t getSetId(); - uint8_t getPrimaryPhy(); - uint8_t getSecondaryPhy(); - uint16_t getPeriodicInterval(); -#endif - -private: - friend class NimBLEScan; - - void setAddress(NimBLEAddress address); - void setAdvType(uint8_t advType, bool isLegacyAdv); - void setPayload(const uint8_t *payload, uint8_t length, bool append); - void setRSSI(int rssi); -#if CONFIG_BT_NIMBLE_EXT_ADV - void setSetId(uint8_t sid) { m_sid = sid; } - void setPrimaryPhy(uint8_t phy) { m_primPhy = phy; } - void setSecondaryPhy(uint8_t phy) { m_secPhy = phy; } - void setPeriodicInterval(uint16_t itvl) { m_periodicItvl = itvl; } -#endif - uint8_t findAdvField(uint8_t type, uint8_t index = 0, size_t * data_loc = nullptr); - size_t findServiceData(uint8_t index, uint8_t* bytes); - - NimBLEAddress m_address = NimBLEAddress(""); - uint8_t m_advType; - int m_rssi; - time_t m_timestamp; - bool m_callbackSent; - uint8_t m_advLength; -#if CONFIG_BT_NIMBLE_EXT_ADV - bool m_isLegacyAdv; - uint8_t m_sid; - uint8_t m_primPhy; - uint8_t m_secPhy; - uint16_t m_periodicItvl; -#endif - - std::vector m_payload; -}; - -/** - * @brief A callback handler for callbacks associated device scanning. - * - * When we are performing a scan as a %BLE client, we may wish to know when a new device that is advertising - * has been found. This class can be sub-classed and registered such that when a scan is performed and - * a new advertised device has been found, we will be called back to be notified. - */ -class NimBLEAdvertisedDeviceCallbacks { -public: - virtual ~NimBLEAdvertisedDeviceCallbacks() {} - /** - * @brief Called when a new scan result is detected. - * - * As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the - * device that was found. During any individual scan, a device will only be detected one time. - */ - virtual void onResult(NimBLEAdvertisedDevice* advertisedDevice) = 0; -}; - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */ -#endif /* COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAdvertising.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAdvertising.cpp deleted file mode 100644 index e45316d69..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAdvertising.cpp +++ /dev/null @@ -1,1038 +0,0 @@ -/* - * NimBLEAdvertising.cpp - * - * Created: on March 3, 2020 - * Author H2zero - * - * Originally: - * - * BLEAdvertising.cpp - * - * This class encapsulates advertising a BLE Server. - * Created on: Jun 21, 2017 - * Author: kolban - * - */ -#include "nimconfig.h" -#if (defined(CONFIG_BT_ENABLED) && \ - defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && \ - !CONFIG_BT_NIMBLE_EXT_ADV) || defined(_DOXYGEN_) - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "services/gap/ble_svc_gap.h" -#else -#include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h" -#endif -#include "NimBLEAdvertising.h" -#include "NimBLEDevice.h" -#include "NimBLEServer.h" -#include "NimBLEUtils.h" -#include "NimBLELog.h" - -static const char* LOG_TAG = "NimBLEAdvertising"; - - -/** - * @brief Construct a default advertising object. - */ -NimBLEAdvertising::NimBLEAdvertising() { - reset(); -} // NimBLEAdvertising - - -/** - * @brief Stops the current advertising and resets the advertising data to the default values. - */ -void NimBLEAdvertising::reset() { - if(NimBLEDevice::getInitialized() && isAdvertising()) { - stop(); - } - memset(&m_advData, 0, sizeof m_advData); - memset(&m_scanData, 0, sizeof m_scanData); - memset(&m_advParams, 0, sizeof m_advParams); - memset(&m_slaveItvl, 0, sizeof m_slaveItvl); - const char *name = ble_svc_gap_device_name(); - - m_advData.name = (uint8_t *)name; - m_advData.name_len = strlen(name); - m_advData.name_is_complete = 1; - m_advData.tx_pwr_lvl = NimBLEDevice::getPower(); - m_advData.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP); - -#if !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - m_advParams.conn_mode = BLE_GAP_CONN_MODE_NON; -#else - m_advParams.conn_mode = BLE_GAP_CONN_MODE_UND; -#endif - m_advParams.disc_mode = BLE_GAP_DISC_MODE_GEN; - m_customAdvData = false; - m_customScanResponseData = false; - m_scanResp = true; - m_advDataSet = false; - // Set this to non-zero to prevent auto start if host reset before started by app. - m_duration = BLE_HS_FOREVER; - m_advCompCB = nullptr; -} // reset - - -/** - * @brief Add a service uuid to exposed list of services. - * @param [in] serviceUUID The UUID of the service to expose. - */ -void NimBLEAdvertising::addServiceUUID(const NimBLEUUID &serviceUUID) { - m_serviceUUIDs.push_back(serviceUUID); - m_advDataSet = false; -} // addServiceUUID - - -/** - * @brief Add a service uuid to exposed list of services. - * @param [in] serviceUUID The string representation of the service to expose. - */ -void NimBLEAdvertising::addServiceUUID(const char* serviceUUID) { - addServiceUUID(NimBLEUUID(serviceUUID)); - m_advDataSet = false; -} // addServiceUUID - - -/** - * @brief Add a service uuid to exposed list of services. - * @param [in] serviceUUID The UUID of the service to expose. - */ -void NimBLEAdvertising::removeServiceUUID(const NimBLEUUID &serviceUUID) { - for(auto it = m_serviceUUIDs.begin(); it != m_serviceUUIDs.end(); ++it) { - if((*it) == serviceUUID) { - m_serviceUUIDs.erase(it); - break; - } - } - m_advDataSet = false; -} // addServiceUUID - - -/** - * @brief Set the device appearance in the advertising data. - * The codes for distinct appearances can be found here:\n - * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml. - * @param [in] appearance The appearance of the device in the advertising data. - */ -void NimBLEAdvertising::setAppearance(uint16_t appearance) { - m_advData.appearance = appearance; - m_advData.appearance_is_present = 1; - m_advDataSet = false; -} // setAppearance - - -/** - * @brief Add the transmission power level to the advertisement packet. - */ -void NimBLEAdvertising::addTxPower() { - m_advData.tx_pwr_lvl_is_present = 1; - m_advDataSet = false; -} // addTxPower - - -/** - * @brief Set the advertised name of the device. - * @param [in] name The name to advertise. - */ -void NimBLEAdvertising::setName(const std::string &name) { - m_name.assign(name.begin(), name.end()); - m_advData.name = &m_name[0]; - m_advData.name_len = m_name.size(); - m_advDataSet = false; -} // setName - - -/** - * @brief Set the advertised manufacturer data. - * @param [in] data The data to advertise. - */ -void NimBLEAdvertising::setManufacturerData(const std::string &data) { - m_mfgData.assign(data.begin(), data.end()); - m_advData.mfg_data = &m_mfgData[0]; - m_advData.mfg_data_len = m_mfgData.size(); - m_advDataSet = false; -} // setManufacturerData - - -/** - * @brief Set the advertised URI. - * @param [in] uri The URI to advertise. - */ -void NimBLEAdvertising::setURI(const std::string &uri) { - m_uri.assign(uri.begin(), uri.end()); - m_advData.uri = &m_uri[0]; - m_advData.uri_len = m_uri.size(); - m_advDataSet = false; -} // setURI - - -/** - * @brief Set the service data advertised for the UUID. - * @param [in] uuid The UUID the service data belongs to. - * @param [in] data The data to advertise. - * @note If data length is 0 the service data will not be advertised. - */ -void NimBLEAdvertising::setServiceData(const NimBLEUUID &uuid, const std::string &data) { - switch (uuid.bitSize()) { - case 16: { - m_svcData16.assign((uint8_t*)&uuid.getNative()->u16.value, (uint8_t*)&uuid.getNative()->u16.value + 2); - m_svcData16.insert(m_svcData16.end(), data.begin(), data.end()); - m_advData.svc_data_uuid16 = (uint8_t*)&m_svcData16[0]; - m_advData.svc_data_uuid16_len = (data.length() > 0) ? m_svcData16.size() : 0; - break; - } - - case 32: { - m_svcData32.assign((uint8_t*)&uuid.getNative()->u32.value, (uint8_t*)&uuid.getNative()->u32.value + 4); - m_svcData32.insert(m_svcData32.end(), data.begin(), data.end()); - m_advData.svc_data_uuid32 = (uint8_t*)&m_svcData32[0]; - m_advData.svc_data_uuid32_len = (data.length() > 0) ? m_svcData32.size() : 0; - break; - } - - case 128: { - m_svcData128.assign(uuid.getNative()->u128.value, uuid.getNative()->u128.value + 16); - m_svcData128.insert(m_svcData128.end(), data.begin(), data.end()); - m_advData.svc_data_uuid128 = (uint8_t*)&m_svcData128[0]; - m_advData.svc_data_uuid128_len = (data.length() > 0) ? m_svcData128.size() : 0; - break; - } - - default: - return; - } - - m_advDataSet = false; -} // setServiceData - - -/** - * @brief Set the type of advertisment to use. - * @param [in] adv_type: - * * BLE_GAP_CONN_MODE_NON (0) - not connectable advertising - * * BLE_GAP_CONN_MODE_DIR (1) - directed connectable advertising - * * BLE_GAP_CONN_MODE_UND (2) - undirected connectable advertising - */ -void NimBLEAdvertising::setAdvertisementType(uint8_t adv_type){ - m_advParams.conn_mode = adv_type; -} // setAdvertisementType - - -/** - * @brief Set the minimum advertising interval. - * @param [in] mininterval Minimum value for advertising interval in 0.625ms units, 0 = use default. - */ -void NimBLEAdvertising::setMinInterval(uint16_t mininterval) { - m_advParams.itvl_min = mininterval; -} // setMinInterval - - -/** - * @brief Set the maximum advertising interval. - * @param [in] maxinterval Maximum value for advertising interval in 0.625ms units, 0 = use default. - */ -void NimBLEAdvertising::setMaxInterval(uint16_t maxinterval) { - m_advParams.itvl_max = maxinterval; -} // setMaxInterval - - -/** - * @brief Set the advertised min connection interval preferred by this device. - * @param [in] mininterval the max interval value. Range = 0x0006 to 0x0C80. - * @details Values not within the range will cancel advertising of this data.\n - * Consumes 6 bytes of advertising space (combined with max interval). - */ -void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) { - // invalid paramters, set the slave interval to null - if(mininterval < 0x0006 || mininterval > 0x0C80) { - m_advData.slave_itvl_range = nullptr; - return; - } - - if(m_advData.slave_itvl_range == nullptr) { - m_advData.slave_itvl_range = m_slaveItvl; - } - - m_slaveItvl[0] = mininterval; - m_slaveItvl[1] = mininterval >> 8; - - uint16_t maxinterval = *(uint16_t*)(m_advData.slave_itvl_range+2); - - // If mininterval is higher than the maxinterval make them the same - if(mininterval > maxinterval) { - m_slaveItvl[2] = m_slaveItvl[0]; - m_slaveItvl[3] = m_slaveItvl[1]; - } - - m_advDataSet = false; -} // setMinPreferred - - -/** - * @brief Set the advertised max connection interval preferred by this device. - * @param [in] maxinterval the max interval value. Range = 0x0006 to 0x0C80. - * @details Values not within the range will cancel advertising of this data.\n - * Consumes 6 bytes of advertising space (combined with min interval). - */ -void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) { - // invalid paramters, set the slave interval to null - if(maxinterval < 0x0006 || maxinterval > 0x0C80) { - m_advData.slave_itvl_range = nullptr; - return; - } - if(m_advData.slave_itvl_range == nullptr) { - m_advData.slave_itvl_range = m_slaveItvl; - } - m_slaveItvl[2] = maxinterval; - m_slaveItvl[3] = maxinterval >> 8; - - uint16_t mininterval = *(uint16_t*)(m_advData.slave_itvl_range); - - // If mininterval is higher than the maxinterval make them the same - if(mininterval > maxinterval) { - m_slaveItvl[0] = m_slaveItvl[2]; - m_slaveItvl[1] = m_slaveItvl[3]; - } - - m_advDataSet = false; -} // setMaxPreferred - - -/** - * @brief Set if scan response is available. - * @param [in] set true = scan response available. - */ -void NimBLEAdvertising::setScanResponse(bool set) { - m_scanResp = set; - m_advDataSet = false; -} // setScanResponse - - -/** - * @brief Set the filtering for the scan filter. - * @param [in] scanRequestWhitelistOnly If true, only allow scan requests from those on the white list. - * @param [in] connectWhitelistOnly If true, only allow connections from those on the white list. - */ -void NimBLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) { - NIMBLE_LOGD(LOG_TAG, ">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d", - scanRequestWhitelistOnly, connectWhitelistOnly); - if (!scanRequestWhitelistOnly && !connectWhitelistOnly) { - m_advParams.filter_policy = BLE_HCI_ADV_FILT_NONE; - NIMBLE_LOGD(LOG_TAG, "<< setScanFilter"); - return; - } - if (scanRequestWhitelistOnly && !connectWhitelistOnly) { - m_advParams.filter_policy = BLE_HCI_ADV_FILT_SCAN; - NIMBLE_LOGD(LOG_TAG, "<< setScanFilter"); - return; - } - if (!scanRequestWhitelistOnly && connectWhitelistOnly) { - m_advParams.filter_policy = BLE_HCI_ADV_FILT_CONN; - NIMBLE_LOGD(LOG_TAG, "<< setScanFilter"); - return; - } - if (scanRequestWhitelistOnly && connectWhitelistOnly) { - m_advParams.filter_policy = BLE_HCI_ADV_FILT_BOTH; - NIMBLE_LOGD(LOG_TAG, "<< setScanFilter"); - return; - } -} // setScanFilter - - -/** - * @brief Set the advertisement data that is to be published in a regular advertisement. - * @param [in] advertisementData The data to be advertised. - * @details The use of this function will replace any data set with addServiceUUID\n - * or setAppearance. If you wish for these to be advertised you must include them\n - * in the advertisementData parameter sent. - */ - -void NimBLEAdvertising::setAdvertisementData(NimBLEAdvertisementData& advertisementData) { - NIMBLE_LOGD(LOG_TAG, ">> setAdvertisementData"); - int rc = ble_gap_adv_set_data( - (uint8_t*)advertisementData.getPayload().data(), - advertisementData.getPayload().length()); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_set_data: %d %s", - rc, NimBLEUtils::returnCodeToString(rc)); - } - m_customAdvData = true; // Set the flag that indicates we are using custom advertising data. - NIMBLE_LOGD(LOG_TAG, "<< setAdvertisementData"); -} // setAdvertisementData - - -/** - * @brief Set the advertisement data that is to be published in a scan response. - * @param [in] advertisementData The data to be advertised. - * @details Calling this without also using setAdvertisementData will have no effect.\n - * When using custom scan response data you must also use custom advertisement data. - */ -void NimBLEAdvertising::setScanResponseData(NimBLEAdvertisementData& advertisementData) { - NIMBLE_LOGD(LOG_TAG, ">> setScanResponseData"); - int rc = ble_gap_adv_rsp_set_data( - (uint8_t*)advertisementData.getPayload().data(), - advertisementData.getPayload().length()); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_rsp_set_data: %d %s", - rc, NimBLEUtils::returnCodeToString(rc)); - } - m_customScanResponseData = true; // Set the flag that indicates we are using custom scan response data. - NIMBLE_LOGD(LOG_TAG, "<< setScanResponseData"); -} // setScanResponseData - - -/** - * @brief Start advertising. - * @param [in] duration The duration, in seconds, to advertise, 0 == advertise forever. - * @param [in] advCompleteCB A pointer to a callback to be invoked when advertising ends. - * @return True if advertising started successfully. - */ -bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdvertising *pAdv)) { - NIMBLE_LOGD(LOG_TAG, ">> Advertising start: customAdvData: %d, customScanResponseData: %d", - m_customAdvData, m_customScanResponseData); - - // If Host is not synced we cannot start advertising. - if(!NimBLEDevice::m_synced) { - NIMBLE_LOGE(LOG_TAG, "Host reset, wait for sync."); - return false; - } - -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - NimBLEServer* pServer = NimBLEDevice::getServer(); - if(pServer != nullptr) { - if(!pServer->m_gattsStarted){ - pServer->start(); - } else if(pServer->getConnectedCount() >= NIMBLE_MAX_CONNECTIONS) { - NIMBLE_LOGE(LOG_TAG, "Max connections reached - not advertising"); - return false; - } - } -#endif - - // If already advertising just return - if(ble_gap_adv_active()) { - NIMBLE_LOGW(LOG_TAG, "Advertising already active"); - return true; - } - - // Save the duration incase of host reset so we can restart with the same params - m_duration = duration; - - if(duration == 0){ - duration = BLE_HS_FOREVER; - } - else{ - duration = duration*1000; // convert duration to milliseconds - } - - m_advCompCB = advCompleteCB; - - m_advParams.disc_mode = BLE_GAP_DISC_MODE_GEN; - m_advData.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP); - if(m_advParams.conn_mode == BLE_GAP_CONN_MODE_NON) { - if(!m_scanResp) { - m_advParams.disc_mode = BLE_GAP_DISC_MODE_NON; - // non-connectable advertising does not require AD flags. - m_advData.flags = 0; - } - } - - int rc = 0; - - if (!m_customAdvData && !m_advDataSet) { - //start with 3 bytes for the flags data if required - uint8_t payloadLen = (m_advData.flags > 0) ? (2 + 1) : 0; - if(m_advData.mfg_data_len > 0) - payloadLen += (2 + m_advData.mfg_data_len); - - if(m_advData.svc_data_uuid16_len > 0) - payloadLen += (2 + m_advData.svc_data_uuid16_len); - - if(m_advData.svc_data_uuid32_len > 0) - payloadLen += (2 + m_advData.svc_data_uuid32_len); - - if(m_advData.svc_data_uuid128_len > 0) - payloadLen += (2 + m_advData.svc_data_uuid128_len); - - if(m_advData.uri_len > 0) - payloadLen += (2 + m_advData.uri_len); - - if(m_advData.appearance_is_present) - payloadLen += (2 + BLE_HS_ADV_APPEARANCE_LEN); - - if(m_advData.tx_pwr_lvl_is_present) - payloadLen += (2 + BLE_HS_ADV_TX_PWR_LVL_LEN); - - if(m_advData.slave_itvl_range != nullptr) - payloadLen += (2 + BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN); - - for(auto &it : m_serviceUUIDs) { - if(it.getNative()->u.type == BLE_UUID_TYPE_16) { - int add = (m_advData.num_uuids16 > 0) ? 2 : 4; - if((payloadLen + add) > BLE_HS_ADV_MAX_SZ){ - m_advData.uuids16_is_complete = 0; - continue; - } - payloadLen += add; - - if(nullptr == (m_advData.uuids16 = (ble_uuid16_t*)realloc((void*)m_advData.uuids16, - (m_advData.num_uuids16 + 1) * sizeof(ble_uuid16_t)))) - { - NIMBLE_LOGC(LOG_TAG, "Error, no mem"); - abort(); - } - memcpy((void*)&m_advData.uuids16[m_advData.num_uuids16], - &it.getNative()->u16, sizeof(ble_uuid16_t)); - m_advData.uuids16_is_complete = 1; - m_advData.num_uuids16++; - } - if(it.getNative()->u.type == BLE_UUID_TYPE_32) { - int add = (m_advData.num_uuids32 > 0) ? 4 : 6; - if((payloadLen + add) > BLE_HS_ADV_MAX_SZ){ - m_advData.uuids32_is_complete = 0; - continue; - } - payloadLen += add; - - if(nullptr == (m_advData.uuids32 = (ble_uuid32_t*)realloc((void*)m_advData.uuids32, - (m_advData.num_uuids32 + 1) * sizeof(ble_uuid32_t)))) - { - NIMBLE_LOGC(LOG_TAG, "Error, no mem"); - abort(); - } - memcpy((void*)&m_advData.uuids32[m_advData.num_uuids32], - &it.getNative()->u32, sizeof(ble_uuid32_t)); - m_advData.uuids32_is_complete = 1; - m_advData.num_uuids32++; - } - if(it.getNative()->u.type == BLE_UUID_TYPE_128){ - int add = (m_advData.num_uuids128 > 0) ? 16 : 18; - if((payloadLen + add) > BLE_HS_ADV_MAX_SZ){ - m_advData.uuids128_is_complete = 0; - continue; - } - payloadLen += add; - - if(nullptr == (m_advData.uuids128 = (ble_uuid128_t*)realloc((void*)m_advData.uuids128, - (m_advData.num_uuids128 + 1) * sizeof(ble_uuid128_t)))) - { - NIMBLE_LOGC(LOG_TAG, "Error, no mem"); - abort(); - } - memcpy((void*)&m_advData.uuids128[m_advData.num_uuids128], - &it.getNative()->u128, sizeof(ble_uuid128_t)); - m_advData.uuids128_is_complete = 1; - m_advData.num_uuids128++; - } - } - - // check if there is room for the name, if not put it in scan data - if((payloadLen + (2 + m_advData.name_len)) > BLE_HS_ADV_MAX_SZ) { - if(m_scanResp && !m_customScanResponseData){ - m_scanData.name = m_advData.name; - m_scanData.name_len = m_advData.name_len; - if(m_scanData.name_len > BLE_HS_ADV_MAX_SZ - 2) { - m_scanData.name_len = BLE_HS_ADV_MAX_SZ - 2; - m_scanData.name_is_complete = 0; - } else { - m_scanData.name_is_complete = 1; - } - m_advData.name = nullptr; - m_advData.name_len = 0; - m_advData.name_is_complete = 0; - } else { - if(m_advData.tx_pwr_lvl_is_present) { - m_advData.tx_pwr_lvl_is_present = 0; - payloadLen -= (2 + 1); - } - // if not using scan response just cut the name down - // leaving 2 bytes for the data specifier. - if(m_advData.name_len > (BLE_HS_ADV_MAX_SZ - payloadLen - 2)) { - m_advData.name_len = (BLE_HS_ADV_MAX_SZ - payloadLen - 2); - m_advData.name_is_complete = 0; - } - } - } - - if(m_scanResp && !m_customScanResponseData) { - rc = ble_gap_adv_rsp_set_fields(&m_scanData); - switch(rc) { - case 0: - break; - - case BLE_HS_EBUSY: - NIMBLE_LOGE(LOG_TAG, "Already advertising"); - break; - - case BLE_HS_EMSGSIZE: - NIMBLE_LOGE(LOG_TAG, "Scan data too long"); - break; - - default: - NIMBLE_LOGE(LOG_TAG, "Error setting scan response data; rc=%d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); - break; - } - } - - if(rc == 0) { - rc = ble_gap_adv_set_fields(&m_advData); - switch(rc) { - case 0: - break; - - case BLE_HS_EBUSY: - NIMBLE_LOGE(LOG_TAG, "Already advertising"); - break; - - case BLE_HS_EMSGSIZE: - NIMBLE_LOGE(LOG_TAG, "Advertisement data too long"); - break; - - default: - NIMBLE_LOGE(LOG_TAG, "Error setting advertisement data; rc=%d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); - break; - } - } - - if(m_advData.num_uuids128 > 0) { - free((void*)m_advData.uuids128); - m_advData.uuids128 = nullptr; - m_advData.num_uuids128 = 0; - } - - if(m_advData.num_uuids32 > 0) { - free((void*)m_advData.uuids32); - m_advData.uuids32 = nullptr; - m_advData.num_uuids32 = 0; - } - - if(m_advData.num_uuids16 > 0) { - free((void*)m_advData.uuids16); - m_advData.uuids16 = nullptr; - m_advData.num_uuids16 = 0; - } - - if(rc !=0) { - return false; - } - - m_advDataSet = true; - } - -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - rc = ble_gap_adv_start(NimBLEDevice::m_own_addr_type, NULL, duration, - &m_advParams, - (pServer != nullptr) ? NimBLEServer::handleGapEvent : - NimBLEAdvertising::handleGapEvent, - (void*)this); -#else - rc = ble_gap_adv_start(NimBLEDevice::m_own_addr_type, NULL, duration, - &m_advParams, NimBLEAdvertising::handleGapEvent, this); -#endif - switch(rc) { - case 0: - break; - - case BLE_HS_EALREADY: - NIMBLE_LOGI(LOG_TAG, "Advertisement Already active"); - break; - - case BLE_HS_EINVAL: - NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Duration too long"); - break; - - case BLE_HS_EPREEMPTED: - NIMBLE_LOGE(LOG_TAG, "Unable to advertise - busy"); - break; - - case BLE_HS_ETIMEOUT_HCI: - case BLE_HS_EOS: - case BLE_HS_ECONTROLLER: - case BLE_HS_ENOTSYNCED: - NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Host Reset"); - break; - - default: - NIMBLE_LOGE(LOG_TAG, "Error enabling advertising; rc=%d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); - break; - } - - NIMBLE_LOGD(LOG_TAG, "<< Advertising start"); - return (rc == 0 || rc == BLE_HS_EALREADY); -} // start - - -/** - * @brief Stop advertising. - * @return True if advertising stopped successfully. - */ -bool NimBLEAdvertising::stop() { - NIMBLE_LOGD(LOG_TAG, ">> stop"); - - int rc = ble_gap_adv_stop(); - if (rc != 0 && rc != BLE_HS_EALREADY) { - NIMBLE_LOGE(LOG_TAG, "ble_gap_adv_stop rc=%d %s", - rc, NimBLEUtils::returnCodeToString(rc)); - return false; - } - - NIMBLE_LOGD(LOG_TAG, "<< stop"); - return true; -} // stop - - -/** - * @brief Handles the callback when advertising stops. - */ -void NimBLEAdvertising::advCompleteCB() { - if(m_advCompCB != nullptr) { - m_advCompCB(this); - } -} // advCompleteCB - - -/** - * @brief Check if currently advertising. - * @return true if advertising is active. - */ -bool NimBLEAdvertising::isAdvertising() { - return ble_gap_adv_active(); -} // isAdvertising - - -/* - * Host reset seems to clear advertising data, - * we need clear the flag so it reloads it. - */ -void NimBLEAdvertising::onHostSync() { - NIMBLE_LOGD(LOG_TAG, "Host re-synced"); - - m_advDataSet = false; - // If we were advertising forever, restart it now - if(m_duration == 0) { - start(m_duration, m_advCompCB); - } else { - // Otherwise we should tell the app that advertising stopped. - advCompleteCB(); - } -} // onHostSync - - -/** - * @brief Handler for gap events when not using peripheral role. - * @param [in] event the event data. - * @param [in] arg pointer to the advertising instance. - */ -/*STATIC*/ -int NimBLEAdvertising::handleGapEvent(struct ble_gap_event *event, void *arg) { - NimBLEAdvertising *pAdv = (NimBLEAdvertising*)arg; - - if(event->type == BLE_GAP_EVENT_ADV_COMPLETE) { - switch(event->adv_complete.reason) { - // Don't call the callback if host reset, we want to - // preserve the active flag until re-sync to restart advertising. - case BLE_HS_ETIMEOUT_HCI: - case BLE_HS_EOS: - case BLE_HS_ECONTROLLER: - case BLE_HS_ENOTSYNCED: - NIMBLE_LOGC(LOG_TAG, "host reset, rc=%d", event->adv_complete.reason); - NimBLEDevice::onReset(event->adv_complete.reason); - return 0; - default: - break; - } - pAdv->advCompleteCB(); - } - return 0; -} - - -/** - * @brief Add data to the payload to be advertised. - * @param [in] data The data to be added to the payload. - */ -void NimBLEAdvertisementData::addData(const std::string &data) { - if ((m_payload.length() + data.length()) > BLE_HS_ADV_MAX_SZ) { - NIMBLE_LOGE(LOG_TAG, "Advertisement data length exceeded"); - return; - } - m_payload.append(data); -} // addData - - -/** - * @brief Add data to the payload to be advertised. - * @param [in] data The data to be added to the payload. - * @param [in] length The size of data to be added to the payload. - */ -void NimBLEAdvertisementData::addData(char * data, size_t length) { - addData(std::string(data, length)); -} // addData - - -/** - * @brief Set the appearance. - * @param [in] appearance The appearance code value. - * - * See also: - * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml - */ -void NimBLEAdvertisementData::setAppearance(uint16_t appearance) { - char cdata[2]; - cdata[0] = 3; - cdata[1] = BLE_HS_ADV_TYPE_APPEARANCE; // 0x19 - addData(std::string(cdata, 2) + std::string((char*) &appearance, 2)); -} // setAppearance - - -/** - * @brief Set the advertisement flags. - * @param [in] flag The flags to be set in the advertisement. - * * BLE_HS_ADV_F_DISC_LTD - * * BLE_HS_ADV_F_DISC_GEN - * * BLE_HS_ADV_F_BREDR_UNSUP - must always use with NimBLE - */ -void NimBLEAdvertisementData::setFlags(uint8_t flag) { - char cdata[3]; - cdata[0] = 2; - cdata[1] = BLE_HS_ADV_TYPE_FLAGS; // 0x01 - cdata[2] = flag | BLE_HS_ADV_F_BREDR_UNSUP; - addData(std::string(cdata, 3)); -} // setFlag - - -/** - * @brief Set manufacturer specific data. - * @param [in] data The manufacturer data to advertise. - */ -void NimBLEAdvertisementData::setManufacturerData(const std::string &data) { - char cdata[2]; - cdata[0] = data.length() + 1; - cdata[1] = BLE_HS_ADV_TYPE_MFG_DATA ; // 0xff - addData(std::string(cdata, 2) + data); -} // setManufacturerData - - -/** - * @brief Set the URI to advertise. - * @param [in] uri The uri to advertise. - */ -void NimBLEAdvertisementData::setURI(const std::string &uri) { - char cdata[2]; - cdata[0] = uri.length() + 1; - cdata[1] = BLE_HS_ADV_TYPE_URI; - addData(std::string(cdata, 2) + uri); -} // setURI - - -/** - * @brief Set the complete name of this device. - * @param [in] name The name to advertise. - */ -void NimBLEAdvertisementData::setName(const std::string &name) { - char cdata[2]; - cdata[0] = name.length() + 1; - cdata[1] = BLE_HS_ADV_TYPE_COMP_NAME; // 0x09 - addData(std::string(cdata, 2) + name); -} // setName - - -/** - * @brief Set a single service to advertise as a complete list of services. - * @param [in] uuid The service to advertise. - */ -void NimBLEAdvertisementData::setCompleteServices(const NimBLEUUID &uuid) { - setServices(true, uuid.bitSize(), {uuid}); -} // setCompleteServices - - -/** - * @brief Set the complete list of 16 bit services to advertise. - * @param [in] v_uuid A vector of 16 bit UUID's to advertise. - */ -void NimBLEAdvertisementData::setCompleteServices16(const std::vector& v_uuid) { - setServices(true, 16, v_uuid); -} // setCompleteServices16 - - -/** - * @brief Set the complete list of 32 bit services to advertise. - * @param [in] v_uuid A vector of 32 bit UUID's to advertise. - */ -void NimBLEAdvertisementData::setCompleteServices32(const std::vector& v_uuid) { - setServices(true, 32, v_uuid); -} // setCompleteServices32 - - -/** - * @brief Set a single service to advertise as a partial list of services. - * @param [in] uuid The service to advertise. - */ -void NimBLEAdvertisementData::setPartialServices(const NimBLEUUID &uuid) { - setServices(false, uuid.bitSize(), {uuid}); -} // setPartialServices - - -/** - * @brief Set the partial list of services to advertise. - * @param [in] v_uuid A vector of 16 bit UUID's to advertise. - */ -void NimBLEAdvertisementData::setPartialServices16(const std::vector& v_uuid) { - setServices(false, 16, v_uuid); -} // setPartialServices16 - - -/** - * @brief Set the partial list of services to advertise. - * @param [in] v_uuid A vector of 32 bit UUID's to advertise. - */ -void NimBLEAdvertisementData::setPartialServices32(const std::vector& v_uuid) { - setServices(false, 32, v_uuid); -} // setPartialServices32 - - -/** - * @brief Utility function to create the list of service UUID's from a vector. - * @param [in] complete If true the vector is the complete set of services. - * @param [in] size The bit size of the UUID's in the vector. (16, 32, or 128). - * @param [in] v_uuid The vector of service UUID's to advertise. - */ -void NimBLEAdvertisementData::setServices(const bool complete, const uint8_t size, - const std::vector &v_uuid) -{ - char cdata[2]; - cdata[0] = (size / 8) * v_uuid.size() + 1; - switch(size) { - case 16: - cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS16 : BLE_HS_ADV_TYPE_INCOMP_UUIDS16; - break; - case 32: - cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS32 : BLE_HS_ADV_TYPE_INCOMP_UUIDS32; - break; - case 128: - cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS128 : BLE_HS_ADV_TYPE_INCOMP_UUIDS128; - break; - default: - return; - } - - std::string uuids; - - for(auto &it : v_uuid){ - if(it.bitSize() != size) { - NIMBLE_LOGE(LOG_TAG, "Service UUID(%d) invalid", size); - return; - } else { - switch(size) { - case 16: - uuids += std::string((char*)&it.getNative()->u16.value, 2); - break; - case 32: - uuids += std::string((char*)&it.getNative()->u32.value, 4); - break; - case 128: - uuids += std::string((char*)&it.getNative()->u128.value, 16); - break; - default: - return; - } - } - } - - addData(std::string(cdata, 2) + uuids); -} // setServices - - -/** - * @brief Set the service data (UUID + data) - * @param [in] uuid The UUID to set with the service data. - * @param [in] data The data to be associated with the service data advertised. - */ -void NimBLEAdvertisementData::setServiceData(const NimBLEUUID &uuid, const std::string &data) { - char cdata[2]; - switch (uuid.bitSize()) { - case 16: { - // [Len] [0x16] [UUID16] data - cdata[0] = data.length() + 3; - cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID16; // 0x16 - addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u16.value, 2) + data); - break; - } - - case 32: { - // [Len] [0x20] [UUID32] data - cdata[0] = data.length() + 5; - cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID32; // 0x20 - addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u32.value, 4) + data); - break; - } - - case 128: { - // [Len] [0x21] [UUID128] data - cdata[0] = data.length() + 17; - cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID128; // 0x21 - addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u128.value, 16) + data); - break; - } - - default: - return; - } -} // setServiceData - - -/** - * @brief Set the short name. - * @param [in] name The short name of the device. - */ -void NimBLEAdvertisementData::setShortName(const std::string &name) { - char cdata[2]; - cdata[0] = name.length() + 1; - cdata[1] = BLE_HS_ADV_TYPE_INCOMP_NAME; // 0x08 - addData(std::string(cdata, 2) + name); -} // setShortName - - -/** - * @brief Adds Tx power level to the advertisement data. - */ -void NimBLEAdvertisementData::addTxPower() { - char cdata[3]; - cdata[0] = BLE_HS_ADV_TX_PWR_LVL_LEN + 1; - cdata[1] = BLE_HS_ADV_TYPE_TX_PWR_LVL; - cdata[2] = NimBLEDevice::getPower(); - addData(cdata, 3); -} // addTxPower - - -/** - * @brief Set the preferred connection interval parameters. - * @param [in] min The minimum interval desired. - * @param [in] max The maximum interval desired. - */ -void NimBLEAdvertisementData::setPreferredParams(uint16_t min, uint16_t max) { - char cdata[6]; - cdata[0] = BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1; - cdata[1] = BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE; - cdata[2] = min; - cdata[3] = min >> 8; - cdata[4] = max; - cdata[5] = max >> 8; - addData(cdata, 6); -} // setPreferredParams - - -/** - * @brief Retrieve the payload that is to be advertised. - * @return The payload that is to be advertised. - */ -std::string NimBLEAdvertisementData::getPayload() { - return m_payload; -} // getPayload - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAdvertising.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAdvertising.h deleted file mode 100644 index dd72ede43..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAdvertising.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * NimBLEAdvertising.h - * - * Created: on March 3, 2020 - * Author H2zero - * - * Originally: - * - * BLEAdvertising.h - * - * Created on: Jun 21, 2017 - * Author: kolban - */ - -#ifndef MAIN_BLEADVERTISING_H_ -#define MAIN_BLEADVERTISING_H_ -#include "nimconfig.h" -#if (defined(CONFIG_BT_ENABLED) && \ - defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && \ - !CONFIG_BT_NIMBLE_EXT_ADV) || defined(_DOXYGEN_) - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "host/ble_gap.h" -#else -#include "nimble/nimble/host/include/host/ble_gap.h" -#endif - -/**** FIX COMPILATION ****/ -#undef min -#undef max -/**************************/ - -#include "NimBLEUUID.h" - -#include - -/* COMPATIBILITY - DO NOT USE */ -#define ESP_BLE_ADV_FLAG_LIMIT_DISC (0x01 << 0) -#define ESP_BLE_ADV_FLAG_GEN_DISC (0x01 << 1) -#define ESP_BLE_ADV_FLAG_BREDR_NOT_SPT (0x01 << 2) -#define ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT (0x01 << 3) -#define ESP_BLE_ADV_FLAG_DMT_HOST_SPT (0x01 << 4) -#define ESP_BLE_ADV_FLAG_NON_LIMIT_DISC (0x00 ) - /* ************************* */ - - -/** - * @brief Advertisement data set by the programmer to be published by the %BLE server. - */ -class NimBLEAdvertisementData { - // Only a subset of the possible BLE architected advertisement fields are currently exposed. Others will - // be exposed on demand/request or as time permits. - // -public: - void setAppearance(uint16_t appearance); - void setCompleteServices(const NimBLEUUID &uuid); - void setCompleteServices16(const std::vector &v_uuid); - void setCompleteServices32(const std::vector &v_uuid); - void setFlags(uint8_t); - void setManufacturerData(const std::string &data); - void setURI(const std::string &uri); - void setName(const std::string &name); - void setPartialServices(const NimBLEUUID &uuid); - void setPartialServices16(const std::vector &v_uuid); - void setPartialServices32(const std::vector &v_uuid); - void setServiceData(const NimBLEUUID &uuid, const std::string &data); - void setShortName(const std::string &name); - void addData(const std::string &data); // Add data to the payload. - void addData(char * data, size_t length); - void addTxPower(); - void setPreferredParams(uint16_t min, uint16_t max); - std::string getPayload(); // Retrieve the current advert payload. - -private: - friend class NimBLEAdvertising; - void setServices(const bool complete, const uint8_t size, - const std::vector &v_uuid); - std::string m_payload; // The payload of the advertisement. -}; // NimBLEAdvertisementData - - -/** - * @brief Perform and manage %BLE advertising. - * - * A %BLE server will want to perform advertising in order to make itself known to %BLE clients. - */ -class NimBLEAdvertising { -public: - NimBLEAdvertising(); - void addServiceUUID(const NimBLEUUID &serviceUUID); - void addServiceUUID(const char* serviceUUID); - void removeServiceUUID(const NimBLEUUID &serviceUUID); - bool start(uint32_t duration = 0, void (*advCompleteCB)(NimBLEAdvertising *pAdv) = nullptr); - bool stop(); - void setAppearance(uint16_t appearance); - void setName(const std::string &name); - void setManufacturerData(const std::string &data); - void setURI(const std::string &uri); - void setServiceData(const NimBLEUUID &uuid, const std::string &data); - void setAdvertisementType(uint8_t adv_type); - void setMaxInterval(uint16_t maxinterval); - void setMinInterval(uint16_t mininterval); - void setAdvertisementData(NimBLEAdvertisementData& advertisementData); - void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly); - void setScanResponseData(NimBLEAdvertisementData& advertisementData); - void setScanResponse(bool); - void setMinPreferred(uint16_t); - void setMaxPreferred(uint16_t); - void addTxPower(); - void reset(); - void advCompleteCB(); - bool isAdvertising(); - -private: - friend class NimBLEDevice; - friend class NimBLEServer; - - void onHostSync(); - static int handleGapEvent(struct ble_gap_event *event, void *arg); - - ble_hs_adv_fields m_advData; - ble_hs_adv_fields m_scanData; - ble_gap_adv_params m_advParams; - std::vector m_serviceUUIDs; - bool m_customAdvData; - bool m_customScanResponseData; - bool m_scanResp; - bool m_advDataSet; - void (*m_advCompCB)(NimBLEAdvertising *pAdv); - uint8_t m_slaveItvl[4]; - uint32_t m_duration; - std::vector m_svcData16; - std::vector m_svcData32; - std::vector m_svcData128; - std::vector m_name; - std::vector m_mfgData; - std::vector m_uri; -}; - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV */ -#endif /* MAIN_BLEADVERTISING_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAttValue.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAttValue.h deleted file mode 100644 index be346d502..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEAttValue.h +++ /dev/null @@ -1,447 +0,0 @@ -/* - * NimBLEAttValue.h - * - * Created: on March 18, 2021 - * Author H2zero - * - */ - -#ifndef MAIN_NIMBLEATTVALUE_H_ -#define MAIN_NIMBLEATTVALUE_H_ -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE -#include -#endif - -#include "NimBLELog.h" - -/**** FIX COMPILATION ****/ -#undef min -#undef max -/**************************/ - -#include -#include - -#ifndef CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED -# define CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED 0 -#endif - -#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED -# include -#endif - -#if !defined(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH) -# define CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH 20 -#elif CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH > BLE_ATT_ATTR_MAX_LEN -# error CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be larger than 512 (BLE_ATT_ATTR_MAX_LEN) -#elif CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH < 1 -# error CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be less than 1; Range = 1 : 512 -#endif - - -/* Used to determine if the type passed to a template has a c_str() and length() method. */ -template -struct Has_c_str_len : std::false_type {}; - -template -struct Has_c_str_len().c_str())), - decltype(void(std::declval().length()))> : std::true_type {}; - - -/** - * @brief A specialized container class to hold BLE attribute values. - * @details This class is designed to be more memory efficient than using\n - * standard container types for value storage, while being convertible to\n - * many different container classes. - */ -class NimBLEAttValue -{ - uint8_t* m_attr_value = nullptr; - uint16_t m_attr_max_len = 0; - uint16_t m_attr_len = 0; - uint16_t m_capacity = 0; -#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED - time_t m_timestamp = 0; -#endif - void deepCopy(const NimBLEAttValue & source); - -public: - /** - * @brief Default constructor. - * @param[in] init_len The initial size in bytes. - * @param[in] max_len The max size in bytes that the value can be. - */ - NimBLEAttValue(uint16_t init_len = CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH, - uint16_t max_len = BLE_ATT_ATTR_MAX_LEN); - - /** - * @brief Construct with an initial value from a buffer. - * @param value A pointer to the initial value to set. - * @param[in] len The size in bytes of the value to set. - * @param[in] max_len The max size in bytes that the value can be. - */ - NimBLEAttValue(const uint8_t *value, uint16_t len, - uint16_t max_len = BLE_ATT_ATTR_MAX_LEN); - - /** - * @brief Construct with an initializer list. - * @param list An initializer list containing the initial value to set. - * @param[in] max_len The max size in bytes that the value can be. - */ - NimBLEAttValue(std::initializer_list list, - uint16_t max_len = BLE_ATT_ATTR_MAX_LEN) - :NimBLEAttValue(list.begin(), (uint16_t)list.size(), max_len){} - - /** - * @brief Construct with an initial value from a const char string. - * @param value A pointer to the initial value to set. - * @param[in] max_len The max size in bytes that the value can be. - */ - NimBLEAttValue(const char *value, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN) - :NimBLEAttValue((uint8_t*)value, (uint16_t)strlen(value), max_len){} - - /** - * @brief Construct with an initial value from a std::string. - * @param str A std::string containing to the initial value to set. - * @param[in] max_len The max size in bytes that the value can be. - */ - NimBLEAttValue(const std::string str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN) - :NimBLEAttValue((uint8_t*)str.data(), (uint16_t)str.length(), max_len){} - - /** - * @brief Construct with an initial value from a std::vector. - * @param vec A std::vector containing to the initial value to set. - * @param[in] max_len The max size in bytes that the value can be. - */ - NimBLEAttValue(const std::vector vec, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN) - :NimBLEAttValue(&vec[0], (uint16_t)vec.size(), max_len){} - -#ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE - /** - * @brief Construct with an initial value from an Arduino String. - * @param str An Arduino String containing to the initial value to set. - * @param[in] max_len The max size in bytes that the value can be. - */ - NimBLEAttValue(const String str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN) - :NimBLEAttValue((uint8_t*)str.c_str(), str.length(), max_len){} -#endif - - /** @brief Copy constructor */ - NimBLEAttValue(const NimBLEAttValue & source) { deepCopy(source); } - - /** @brief Move constructor */ - NimBLEAttValue(NimBLEAttValue && source) { *this = std::move(source); } - - /** @brief Destructor */ - ~NimBLEAttValue(); - - /** @brief Returns the max size in bytes */ - uint16_t max_size() const { return m_attr_max_len; } - - /** @brief Returns the currently allocated capacity in bytes */ - uint16_t capacity() const { return m_capacity; } - - /** @brief Returns the current length of the value in bytes */ - uint16_t length() const { return m_attr_len; } - - /** @brief Returns the current size of the value in bytes */ - uint16_t size() const { return m_attr_len; } - - /** @brief Returns a pointer to the internal buffer of the value */ - const uint8_t* data() const { return m_attr_value; } - - /** @brief Returns a pointer to the internal buffer of the value as a const char* */ - const char* c_str() const { return (const char*)m_attr_value; } - - /** @brief Iterator begin */ - const uint8_t* begin() const { return m_attr_value; } - - /** @brief Iterator end */ - const uint8_t* end() const { return m_attr_value + m_attr_len; } - -#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED - /** @brief Returns a timestamp of when the value was last updated */ - time_t getTimeStamp() const { return m_timestamp; } - - /** @brief Set the timestamp to the current time */ - void setTimeStamp() { m_timestamp = time(nullptr); } - - /** - * @brief Set the timestamp to the specified time - * @param[in] t The timestamp value to set - */ - void setTimeStamp(time_t t) { m_timestamp = t; } -#else - time_t getTimeStamp() const { return 0; } - void setTimeStamp() { } - void setTimeStamp(time_t t) { } -#endif - - /** - * @brief Set the value from a buffer - * @param[in] value A ponter to a buffer containing the value. - * @param[in] len The length of the value in bytes. - * @returns True if successful. - */ - bool setValue(const uint8_t *value, uint16_t len); - - /** - * @brief Set value to the value of const char*. - * @param [in] s A ponter to a const char value to set. - */ - bool setValue(const char* s) { - return setValue((uint8_t*)s, (uint16_t)strlen(s)); } - - /** - * @brief Get a pointer to the value buffer with timestamp. - * @param[in] timestamp A ponter to a time_t variable to store the timestamp. - * @returns A pointer to the internal value buffer. - */ - const uint8_t* getValue(time_t *timestamp); - - /** - * @brief Append data to the value. - * @param[in] value A ponter to a data buffer with the value to append. - * @param[in] len The length of the value to append in bytes. - * @returns A reference to the appended NimBLEAttValue. - */ - NimBLEAttValue& append(const uint8_t *value, uint16_t len); - - - /*********************** Template Functions ************************/ - - /** - * @brief Template to set value to the value of val. - * @param [in] s The value to set. - * @details Only used for types without a `c_str()` method. - */ - template -#ifdef _DOXYGEN_ - bool -#else - typename std::enable_if::value, bool>::type -#endif - setValue(const T &s) { - return setValue((uint8_t*)&s, sizeof(T)); - } - - /** - * @brief Template to set value to the value of val. - * @param [in] s The value to set. - * @details Only used if the has a `c_str()` method. - */ - template -#ifdef _DOXYGEN_ - bool -#else - typename std::enable_if::value, bool>::type -#endif - setValue(const T & s) { - return setValue((uint8_t*)s.c_str(), (uint16_t)s.length()); - } - - /** - * @brief Template to return the value as a . - * @tparam T The type to convert the data to. - * @param [in] timestamp A pointer to a time_t struct to store the time the value was read. - * @param [in] skipSizeCheck If true it will skip checking if the data size is less than\n - * sizeof(). - * @return The data converted to or NULL if skipSizeCheck is false and the data is\n - * less than sizeof(). - * @details Use: getValue(×tamp, skipSizeCheck); - */ - template - T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) { - if(!skipSizeCheck && size() < sizeof(T)) { - return T(); - } - return *((T *)getValue(timestamp)); - } - - - /*********************** Operators ************************/ - - /** @brief Subscript operator */ - uint8_t operator [](int pos) const { - assert(pos < m_attr_len && "out of range"); return m_attr_value[pos]; } - - /** @brief Operator; Get the value as a std::vector. */ - operator std::vector() const { - return std::vector(m_attr_value, m_attr_value + m_attr_len); } - - /** @brief Operator; Get the value as a std::string. */ - operator std::string() const { - return std::string((char*)m_attr_value, m_attr_len); } - - /** @brief Operator; Get the value as a const uint8_t*. */ - operator const uint8_t*() const { return m_attr_value; } - - /** @brief Operator; Append another NimBLEAttValue. */ - NimBLEAttValue& operator +=(const NimBLEAttValue & source) { - return append(source.data(), source.size()); } - - /** @brief Operator; Set the value from a std::string source. */ - NimBLEAttValue& operator =(const std::string & source) { - setValue((uint8_t*)source.data(), (uint16_t)source.size()); return *this; } - - /** @brief Move assignment operator */ - NimBLEAttValue& operator =(NimBLEAttValue && source); - - /** @brief Copy assignment operator */ - NimBLEAttValue& operator =(const NimBLEAttValue & source); - - /** @brief Equality operator */ - bool operator ==(const NimBLEAttValue & source) { - return (m_attr_len == source.size()) ? - memcmp(m_attr_value, source.data(), m_attr_len) == 0 : false; } - - /** @brief Inequality operator */ - bool operator !=(const NimBLEAttValue & source){ return !(*this == source); } - -#ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE - /** @brief Operator; Get the value as an Arduino String value. */ - operator String() const { return String((char*)m_attr_value); } -#endif - -}; - - -inline NimBLEAttValue::NimBLEAttValue(uint16_t init_len, uint16_t max_len) { - m_attr_value = (uint8_t*)calloc(init_len + 1, 1); - assert(m_attr_value && "No Mem"); - m_attr_max_len = std::min(BLE_ATT_ATTR_MAX_LEN, (int)max_len); - m_attr_len = 0; - m_capacity = init_len; - setTimeStamp(0); -} - -inline NimBLEAttValue::NimBLEAttValue(const uint8_t *value, uint16_t len, uint16_t max_len) -: NimBLEAttValue(len, max_len) { - memcpy(m_attr_value, value, len); - m_attr_value[len] = '\0'; - m_attr_len = len; -} - -inline NimBLEAttValue::~NimBLEAttValue() { - if(m_attr_value != nullptr) { - free(m_attr_value); - } -} - -inline NimBLEAttValue& NimBLEAttValue::operator =(NimBLEAttValue && source) { - if (this != &source){ - free(m_attr_value); - - m_attr_value = source.m_attr_value; - m_attr_max_len = source.m_attr_max_len; - m_attr_len = source.m_attr_len; - m_capacity = source.m_capacity; - setTimeStamp(source.getTimeStamp()); - source.m_attr_value = nullptr; - } - return *this; -} - -inline NimBLEAttValue& NimBLEAttValue::operator =(const NimBLEAttValue & source) { - if (this != &source) { - deepCopy(source); - } - return *this; -} - -inline void NimBLEAttValue::deepCopy(const NimBLEAttValue & source) { - uint8_t* res = (uint8_t*)realloc( m_attr_value, source.m_capacity + 1); - assert(res && "deepCopy: realloc failed"); - - ble_npl_hw_enter_critical(); - m_attr_value = res; - m_attr_max_len = source.m_attr_max_len; - m_attr_len = source.m_attr_len; - m_capacity = source.m_capacity; - setTimeStamp(source.getTimeStamp()); - memcpy(m_attr_value, source.m_attr_value, m_attr_len + 1); - ble_npl_hw_exit_critical(0); -} - -inline const uint8_t* NimBLEAttValue::getValue(time_t *timestamp) { - if(timestamp != nullptr) { -#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED - *timestamp = m_timestamp; -#else - *timestamp = 0; -#endif - } - return m_attr_value; -} - -inline bool NimBLEAttValue::setValue(const uint8_t *value, uint16_t len) { - if (len > m_attr_max_len) { - NIMBLE_LOGE("NimBLEAttValue", "value exceeds max, len=%u, max=%u", - len, m_attr_max_len); - return false; - } - - uint8_t *res = m_attr_value; - if (len > m_capacity) { - res = (uint8_t*)realloc(m_attr_value, (len + 1)); - m_capacity = len; - } - assert(res && "setValue: realloc failed"); - -#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED - time_t t = time(nullptr); -#else - time_t t = 0; -#endif - - ble_npl_hw_enter_critical(); - m_attr_value = res; - memcpy(m_attr_value, value, len); - m_attr_value[len] = '\0'; - m_attr_len = len; - setTimeStamp(t); - ble_npl_hw_exit_critical(0); - return true; -} - -inline NimBLEAttValue& NimBLEAttValue::append(const uint8_t *value, uint16_t len) { - if (len < 1) { - return *this; - } - - if ((m_attr_len + len) > m_attr_max_len) { - NIMBLE_LOGE("NimBLEAttValue", "val > max, len=%u, max=%u", - len, m_attr_max_len); - return *this; - } - - uint8_t* res = m_attr_value; - uint16_t new_len = m_attr_len + len; - if (new_len > m_capacity) { - res = (uint8_t*)realloc(m_attr_value, (new_len + 1)); - m_capacity = new_len; - } - assert(res && "append: realloc failed"); - -#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED - time_t t = time(nullptr); -#else - time_t t = 0; -#endif - - ble_npl_hw_enter_critical(); - m_attr_value = res; - memcpy(m_attr_value + m_attr_len, value, len); - m_attr_len = new_len; - m_attr_value[m_attr_len] = '\0'; - setTimeStamp(t); - ble_npl_hw_exit_critical(0); - - return *this; -} - -#endif /*(CONFIG_BT_ENABLED) */ -#endif /* MAIN_NIMBLEATTVALUE_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEBeacon.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEBeacon.cpp deleted file mode 100644 index df24ced93..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEBeacon.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * NimBLEBeacon2.cpp - * - * Created: on March 15 2020 - * Author H2zero - * - * Originally: - * - * BLEBeacon.cpp - * - * Created on: Jan 4, 2018 - * Author: kolban - */ -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include -#include -#include "NimBLEBeacon.h" -#include "NimBLELog.h" - -#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8)) - -static const char* LOG_TAG = "NimBLEBeacon"; - - -/** - * @brief Construct a default beacon object. - */ -NimBLEBeacon::NimBLEBeacon() { - m_beaconData.manufacturerId = 0x4c00; - m_beaconData.subType = 0x02; - m_beaconData.subTypeLength = 0x15; - m_beaconData.major = 0; - m_beaconData.minor = 0; - m_beaconData.signalPower = 0; - memset(m_beaconData.proximityUUID, 0, sizeof(m_beaconData.proximityUUID)); -} // NimBLEBeacon - - -/** - * @brief Retrieve the data that is being advertised. - * @return The advertised data. - */ -std::string NimBLEBeacon::getData() { - return std::string((char*) &m_beaconData, sizeof(m_beaconData)); -} // getData - - -/** - * @brief Get the major value being advertised. - * @return The major value advertised. - */ -uint16_t NimBLEBeacon::getMajor() { - return m_beaconData.major; -} - - -/** - * @brief Get the manufacturer ID being advertised. - * @return The manufacturer ID value advertised. - */ -uint16_t NimBLEBeacon::getManufacturerId() { - return m_beaconData.manufacturerId; -} - - -/** - * @brief Get the minor value being advertised. - * @return minor value advertised. - */ -uint16_t NimBLEBeacon::getMinor() { - return m_beaconData.minor; -} - - -/** - * @brief Get the proximity UUID being advertised. - * @return The UUID advertised. - */ -NimBLEUUID NimBLEBeacon::getProximityUUID() { - return NimBLEUUID(m_beaconData.proximityUUID, 16, true); -} - - -/** - * @brief Get the signal power being advertised. - * @return signal power level advertised. - */ -int8_t NimBLEBeacon::getSignalPower() { - return m_beaconData.signalPower; -} - - -/** - * @brief Set the raw data for the beacon record. - * @param [in] data The raw beacon data. - */ -void NimBLEBeacon::setData(const std::string &data) { - if (data.length() != sizeof(m_beaconData)) { - NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d", - data.length(), sizeof(m_beaconData)); - return; - } - memcpy(&m_beaconData, data.data(), sizeof(m_beaconData)); -} // setData - - -/** - * @brief Set the major value. - * @param [in] major The major value. - */ -void NimBLEBeacon::setMajor(uint16_t major) { - m_beaconData.major = ENDIAN_CHANGE_U16(major); -} // setMajor - - -/** - * @brief Set the manufacturer ID. - * @param [in] manufacturerId The manufacturer ID value. - */ -void NimBLEBeacon::setManufacturerId(uint16_t manufacturerId) { - m_beaconData.manufacturerId = ENDIAN_CHANGE_U16(manufacturerId); -} // setManufacturerId - - -/** - * @brief Set the minor value. - * @param [in] minor The minor value. - */ -void NimBLEBeacon::setMinor(uint16_t minor) { - m_beaconData.minor = ENDIAN_CHANGE_U16(minor); -} // setMinor - - -/** - * @brief Set the proximity UUID. - * @param [in] uuid The proximity UUID. - */ -void NimBLEBeacon::setProximityUUID(const NimBLEUUID &uuid) { - NimBLEUUID temp_uuid = uuid; - temp_uuid.to128(); - std::reverse_copy(temp_uuid.getNative()->u128.value, - temp_uuid.getNative()->u128.value + 16, - m_beaconData.proximityUUID); -} // setProximityUUID - - -/** - * @brief Set the signal power. - * @param [in] signalPower The signal power value. - */ -void NimBLEBeacon::setSignalPower(int8_t signalPower) { - m_beaconData.signalPower = signalPower; -} // setSignalPower - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEBeacon.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEBeacon.h deleted file mode 100644 index 82ee61c53..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEBeacon.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * NimBLEBeacon2.h - * - * Created: on March 15 2020 - * Author H2zero - * - * Originally: - * - * BLEBeacon2.h - * - * Created on: Jan 4, 2018 - * Author: kolban - */ - -#ifndef MAIN_NIMBLEBEACON_H_ -#define MAIN_NIMBLEBEACON_H_ - -#include "NimBLEUUID.h" -/** - * @brief Representation of a beacon. - * See: - * * https://en.wikipedia.org/wiki/IBeacon - */ -class NimBLEBeacon { -private: - struct { - uint16_t manufacturerId; - uint8_t subType; - uint8_t subTypeLength; - uint8_t proximityUUID[16]; - uint16_t major; - uint16_t minor; - int8_t signalPower; - } __attribute__((packed)) m_beaconData; -public: - NimBLEBeacon(); - std::string getData(); - uint16_t getMajor(); - uint16_t getMinor(); - uint16_t getManufacturerId(); - NimBLEUUID getProximityUUID(); - int8_t getSignalPower(); - void setData(const std::string &data); - void setMajor(uint16_t major); - void setMinor(uint16_t minor); - void setManufacturerId(uint16_t manufacturerId); - void setProximityUUID(const NimBLEUUID &uuid); - void setSignalPower(int8_t signalPower); -}; // NimBLEBeacon - -#endif /* MAIN_NIMBLEBEACON_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLECharacteristic.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLECharacteristic.cpp deleted file mode 100644 index 03d8c55d6..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLECharacteristic.cpp +++ /dev/null @@ -1,661 +0,0 @@ -/* - * NimBLECharacteristic.cpp - * - * Created: on March 3, 2020 - * Author H2zero - * - * BLECharacteristic.cpp - * - * Created on: Jun 22, 2017 - * Author: kolban - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include "NimBLECharacteristic.h" -#include "NimBLE2904.h" -#include "NimBLEDevice.h" -#include "NimBLELog.h" - -#define NULL_HANDLE (0xffff) -#define NIMBLE_SUB_NOTIFY 0x0001 -#define NIMBLE_SUB_INDICATE 0x0002 - -static NimBLECharacteristicCallbacks defaultCallback; -static const char* LOG_TAG = "NimBLECharacteristic"; - - -/** - * @brief Construct a characteristic - * @param [in] uuid - UUID (const char*) for the characteristic. - * @param [in] properties - Properties for the characteristic. - * @param [in] max_len - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others). - * @param [in] pService - pointer to the service instance this characteristic belongs to. - */ -NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties, - uint16_t max_len, NimBLEService* pService) -: NimBLECharacteristic(NimBLEUUID(uuid), properties, max_len, pService) { -} - -/** - * @brief Construct a characteristic - * @param [in] uuid - UUID for the characteristic. - * @param [in] properties - Properties for the characteristic. - * @param [in] max_len - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others). - * @param [in] pService - pointer to the service instance this characteristic belongs to. - */ -NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties, - uint16_t max_len, NimBLEService* pService) -: m_value(std::min(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH , (int)max_len), max_len) { - m_uuid = uuid; - m_handle = NULL_HANDLE; - m_properties = properties; - m_pCallbacks = &defaultCallback; - m_pService = pService; - m_removed = 0; -} // NimBLECharacteristic - -/** - * @brief Destructor. - */ -NimBLECharacteristic::~NimBLECharacteristic() { - for(auto &it : m_dscVec) { - delete it; - } -} // ~NimBLECharacteristic - - -/** - * @brief Create a new BLE Descriptor associated with this characteristic. - * @param [in] uuid - The UUID of the descriptor. - * @param [in] properties - The properties of the descriptor. - * @param [in] max_len - The max length in bytes of the descriptor value. - * @return The new BLE descriptor. - */ -NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const char* uuid, uint32_t properties, uint16_t max_len) { - return createDescriptor(NimBLEUUID(uuid), properties, max_len); -} - - -/** - * @brief Create a new BLE Descriptor associated with this characteristic. - * @param [in] uuid - The UUID of the descriptor. - * @param [in] properties - The properties of the descriptor. - * @param [in] max_len - The max length in bytes of the descriptor value. - * @return The new BLE descriptor. - */ -NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) { - NimBLEDescriptor* pDescriptor = nullptr; - if(uuid == NimBLEUUID(uint16_t(0x2902))) { - assert(0 && "0x2902 descriptors cannot be manually created"); - } else if (uuid == NimBLEUUID(uint16_t(0x2904))) { - pDescriptor = new NimBLE2904(this); - } else { - pDescriptor = new NimBLEDescriptor(uuid, properties, max_len, this); - } - - addDescriptor(pDescriptor); - return pDescriptor; -} // createDescriptor - - -/** - * @brief Add a descriptor to the characteristic. - * @param [in] pDescriptor A pointer to the descriptor to add. - */ -void NimBLECharacteristic::addDescriptor(NimBLEDescriptor *pDescriptor) { - bool foundRemoved = false; - - if(pDescriptor->m_removed > 0) { - for(auto& it : m_dscVec) { - if(it == pDescriptor) { - foundRemoved = true; - pDescriptor->m_removed = 0; - } - } - } - - if(!foundRemoved) { - m_dscVec.push_back(pDescriptor); - } - - pDescriptor->setCharacteristic(this); - NimBLEDevice::getServer()->serviceChanged(); -} - - -/** - * @brief Remove a descriptor from the characteristic. - * @param[in] pDescriptor A pointer to the descriptor instance to remove from the characteristic. - * @param[in] deleteDsc If true it will delete the descriptor instance and free it's resources. - */ -void NimBLECharacteristic::removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc) { - // Check if the descriptor was already removed and if so, check if this - // is being called to delete the object and do so if requested. - // Otherwise, ignore the call and return. - if(pDescriptor->m_removed > 0) { - if(deleteDsc) { - for(auto it = m_dscVec.begin(); it != m_dscVec.end(); ++it) { - if ((*it) == pDescriptor) { - delete *it; - m_dscVec.erase(it); - break; - } - } - } - - return; - } - - pDescriptor->m_removed = deleteDsc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE; - NimBLEDevice::getServer()->serviceChanged(); -} // removeDescriptor - - -/** - * @brief Return the BLE Descriptor for the given UUID. - * @param [in] uuid The UUID of the descriptor. - * @return A pointer to the descriptor object or nullptr if not found. - */ -NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) { - return getDescriptorByUUID(NimBLEUUID(uuid)); -} // getDescriptorByUUID - - -/** - * @brief Return the BLE Descriptor for the given UUID. - * @param [in] uuid The UUID of the descriptor. - * @return A pointer to the descriptor object or nullptr if not found. - */ -NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uuid) { - for (auto &it : m_dscVec) { - if (it->getUUID() == uuid) { - return it; - } - } - return nullptr; -} // getDescriptorByUUID - -/** - * @brief Return the BLE Descriptor for the given handle. - * @param [in] handle The handle of the descriptor. - * @return A pointer to the descriptor object or nullptr if not found. - */ -NimBLEDescriptor *NimBLECharacteristic::getDescriptorByHandle(uint16_t handle) { - for (auto &it : m_dscVec) { - if (it->getHandle() == handle) { - return it; - } - } - return nullptr; -} - - -/** - * @brief Get the handle of the characteristic. - * @return The handle of the characteristic. - */ -uint16_t NimBLECharacteristic::getHandle() { - return m_handle; -} // getHandle - - -/** - * @brief Get the properties of the characteristic. - * @return The properties of the characteristic. - */ -uint16_t NimBLECharacteristic::getProperties() { - return m_properties; -} // getProperties - - -/** - * @brief Get the service associated with this characteristic. - */ -NimBLEService* NimBLECharacteristic::getService() { - return m_pService; -} // getService - - -void NimBLECharacteristic::setService(NimBLEService *pService) { - m_pService = pService; -} - - -/** - * @brief Get the UUID of the characteristic. - * @return The UUID of the characteristic. - */ -NimBLEUUID NimBLECharacteristic::getUUID() { - return m_uuid; -} // getUUID - - -/** - * @brief Retrieve the current value of the characteristic. - * @return The NimBLEAttValue containing the current characteristic value. - */ -NimBLEAttValue NimBLECharacteristic::getValue(time_t *timestamp) { - if(timestamp != nullptr) { - m_value.getValue(timestamp); - } - - return m_value; -} // getValue - - -/** - * @brief Retrieve the the current data length of the characteristic. - * @return The length of the current characteristic data. - */ -size_t NimBLECharacteristic::getDataLength() { - return m_value.size(); -} - - -/** - * @brief STATIC callback to handle events from the NimBLE stack. - */ -int NimBLECharacteristic::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg) -{ - const ble_uuid_t *uuid; - int rc; - struct ble_gap_conn_desc desc; - NimBLECharacteristic* pCharacteristic = (NimBLECharacteristic*)arg; - - NIMBLE_LOGD(LOG_TAG, "Characteristic %s %s event", pCharacteristic->getUUID().toString().c_str(), - ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR ? "Read" : "Write"); - - uuid = ctxt->chr->uuid; - if(ble_uuid_cmp(uuid, &pCharacteristic->getUUID().getNative()->u) == 0){ - switch(ctxt->op) { - case BLE_GATT_ACCESS_OP_READ_CHR: { - rc = ble_gap_conn_find(conn_handle, &desc); - assert(rc == 0); - - // If the packet header is only 8 bytes this is a follow up of a long read - // so we don't want to call the onRead() callback again. - if(ctxt->om->om_pkthdr_len > 8 || - pCharacteristic->m_value.size() <= (ble_att_mtu(desc.conn_handle) - 3)) { - pCharacteristic->m_pCallbacks->onRead(pCharacteristic); - pCharacteristic->m_pCallbacks->onRead(pCharacteristic, &desc); - } - - ble_npl_hw_enter_critical(); - rc = os_mbuf_append(ctxt->om, pCharacteristic->m_value.data(), pCharacteristic->m_value.size()); - ble_npl_hw_exit_critical(0); - return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; - } - - case BLE_GATT_ACCESS_OP_WRITE_CHR: { - uint16_t att_max_len = pCharacteristic->m_value.max_size(); - - if (ctxt->om->om_len > att_max_len) { - return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; - } - - uint8_t buf[att_max_len]; - size_t len = ctxt->om->om_len; - memcpy(buf, ctxt->om->om_data,len); - - os_mbuf *next; - next = SLIST_NEXT(ctxt->om, om_next); - while(next != NULL){ - if((len + next->om_len) > att_max_len) { - return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; - } - memcpy(&buf[len], next->om_data, next->om_len); - len += next->om_len; - next = SLIST_NEXT(next, om_next); - } - rc = ble_gap_conn_find(conn_handle, &desc); - assert(rc == 0); - pCharacteristic->setValue(buf, len); - pCharacteristic->m_pCallbacks->onWrite(pCharacteristic); - pCharacteristic->m_pCallbacks->onWrite(pCharacteristic, &desc); - return 0; - } - default: - break; - } - } - - return BLE_ATT_ERR_UNLIKELY; -} - - -/** - * @brief Get the number of clients subscribed to the characteristic. - * @returns Number of clients subscribed to notifications / indications. - */ -size_t NimBLECharacteristic::getSubscribedCount() { - return m_subscribedVec.size(); -} - - -/** - * @brief Set the subscribe status for this characteristic.\n - * This will maintain a vector of subscribed clients and their indicate/notify status. - */ -void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) { - ble_gap_conn_desc desc; - if(ble_gap_conn_find(event->subscribe.conn_handle, &desc) != 0) { - return; - } - - uint16_t subVal = 0; - if(event->subscribe.cur_notify > 0 && (m_properties & NIMBLE_PROPERTY::NOTIFY)) { - subVal |= NIMBLE_SUB_NOTIFY; - } - if(event->subscribe.cur_indicate && (m_properties & NIMBLE_PROPERTY::INDICATE)) { - subVal |= NIMBLE_SUB_INDICATE; - } - - NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d", - event->subscribe.conn_handle, subVal); - - if(!event->subscribe.cur_indicate && event->subscribe.prev_indicate) { - NimBLEDevice::getServer()->clearIndicateWait(event->subscribe.conn_handle); - } - - - auto it = m_subscribedVec.begin(); - for(;it != m_subscribedVec.end(); ++it) { - if((*it).first == event->subscribe.conn_handle) { - break; - } - } - - if(subVal > 0) { - if(it == m_subscribedVec.end()) { - m_subscribedVec.push_back({event->subscribe.conn_handle, subVal}); - } else { - (*it).second = subVal; - } - } else if(it != m_subscribedVec.end()) { - m_subscribedVec.erase(it); - } - - m_pCallbacks->onSubscribe(this, &desc, subVal); -} - - -/** - * @brief Send an indication. - */ -void NimBLECharacteristic::indicate() { - notify(false); -} // indicate - - -/** - * @brief Send an indication. - * @param[in] value A pointer to the data to send. - * @param[in] length The length of the data to send. - */ -void NimBLECharacteristic::indicate(const uint8_t* value, size_t length) { - notify(value, length, false); -} // indicate - - -/** - * @brief Send an indication. - * @param[in] value A std::vector containing the value to send as the notification value. - */ -void NimBLECharacteristic::indicate(const std::vector& value) { - notify(value.data(), value.size(), false); -} // indicate - - -/** - * @brief Send a notification or indication. - * @param[in] is_notification if true sends a notification, false sends an indication. - */ -void NimBLECharacteristic::notify(bool is_notification) { - notify(m_value.data(), m_value.length(), is_notification); -} // notify - - -/** - * @brief Send a notification or indication. - * @param[in] value A std::vector containing the value to send as the notification value. - * @param[in] is_notification if true sends a notification, false sends an indication. - */ -void NimBLECharacteristic::notify(const std::vector& value, bool is_notification) { - notify(value.data(), value.size(), is_notification); -} // notify - - -/** - * @brief Send a notification or indication. - * @param[in] value A pointer to the data to send. - * @param[in] length The length of the data to send. - * @param[in] is_notification if true sends a notification, false sends an indication. - */ -void NimBLECharacteristic::notify(const uint8_t* value, size_t length, bool is_notification) { - NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", length); - - if(!(m_properties & NIMBLE_PROPERTY::NOTIFY) && - !(m_properties & NIMBLE_PROPERTY::INDICATE)) - { - NIMBLE_LOGE(LOG_TAG, - "<< notify-Error; Notify/indicate not enabled for characteristic: %s", - std::string(getUUID()).c_str()); - } - - if (m_subscribedVec.size() == 0) { - NIMBLE_LOGD(LOG_TAG, "<< notify: No clients subscribed."); - return; - } - - m_pCallbacks->onNotify(this); - - bool reqSec = (m_properties & BLE_GATT_CHR_F_READ_AUTHEN) || - (m_properties & BLE_GATT_CHR_F_READ_AUTHOR) || - (m_properties & BLE_GATT_CHR_F_READ_ENC); - int rc = 0; - - for (auto &it : m_subscribedVec) { - uint16_t _mtu = getService()->getServer()->getPeerMTU(it.first) - 3; - - // check if connected and subscribed - if(_mtu == 0 || it.second == 0) { - continue; - } - - // check if security requirements are satisfied - if(reqSec) { - struct ble_gap_conn_desc desc; - rc = ble_gap_conn_find(it.first, &desc); - if(rc != 0 || !desc.sec_state.encrypted) { - continue; - } - } - - if (length > _mtu) { - NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu); - } - - if(is_notification && (!(it.second & NIMBLE_SUB_NOTIFY))) { - NIMBLE_LOGW(LOG_TAG, - "Sending notification to client subscribed to indications, sending indication instead"); - is_notification = false; - } - - if(!is_notification && (!(it.second & NIMBLE_SUB_INDICATE))) { - NIMBLE_LOGW(LOG_TAG, - "Sending indication to client subscribed to notification, sending notification instead"); - is_notification = true; - } - - // don't create the m_buf until we are sure to send the data or else - // we could be allocating a buffer that doesn't get released. - // We also must create it in each loop iteration because it is consumed with each host call. - os_mbuf *om = ble_hs_mbuf_from_flat(value, length); - - if(!is_notification && (m_properties & NIMBLE_PROPERTY::INDICATE)) { - if(!NimBLEDevice::getServer()->setIndicateWait(it.first)) { - NIMBLE_LOGE(LOG_TAG, "prior Indication in progress"); - os_mbuf_free_chain(om); - return; - } - - rc = ble_gattc_indicate_custom(it.first, m_handle, om); - if(rc != 0){ - NimBLEDevice::getServer()->clearIndicateWait(it.first); - } - } else { - ble_gattc_notify_custom(it.first, m_handle, om); - } - } - - NIMBLE_LOGD(LOG_TAG, "<< notify"); -} // Notify - - -/** - * @brief Set the callback handlers for this characteristic. - * @param [in] pCallbacks An instance of a NimBLECharacteristicCallbacks class\n - * used to define any callbacks for the characteristic. - */ -void NimBLECharacteristic::setCallbacks(NimBLECharacteristicCallbacks* pCallbacks) { - if (pCallbacks != nullptr){ - m_pCallbacks = pCallbacks; - } else { - m_pCallbacks = &defaultCallback; - } -} // setCallbacks - -/** - * @brief Get the callback handlers for this characteristic. - */ -NimBLECharacteristicCallbacks* NimBLECharacteristic::getCallbacks() { - return m_pCallbacks; -} //getCallbacks - - -/** - * @brief Set the value of the characteristic from a data buffer . - * @param [in] data The data buffer to set for the characteristic. - * @param [in] length The number of bytes in the data buffer. - */ -void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) { -#if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4 - char* pHex = NimBLEUtils::buildHexData(nullptr, data, length); - NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", - length, pHex, getUUID().toString().c_str()); - free(pHex); -#endif - - m_value.setValue(data, length); - NIMBLE_LOGD(LOG_TAG, "<< setValue"); -} // setValue - - -/** - * @brief Set the value of the characteristic from a `std::vector`.\n - * @param [in] vec The std::vector reference to set the characteristic value from. - */ -void NimBLECharacteristic::setValue(const std::vector& vec) { - return setValue((uint8_t*)&vec[0], vec.size()); -}// setValue - - -/** - * @brief Return a string representation of the characteristic. - * @return A string representation of the characteristic. - */ -std::string NimBLECharacteristic::toString() { - std::string res = "UUID: " + m_uuid.toString() + ", handle : 0x"; - char hex[5]; - snprintf(hex, sizeof(hex), "%04x", m_handle); - res += hex; - res += " "; - if (m_properties & BLE_GATT_CHR_PROP_READ ) res += "Read "; - if (m_properties & BLE_GATT_CHR_PROP_WRITE) res += "Write "; - if (m_properties & BLE_GATT_CHR_PROP_WRITE_NO_RSP) res += "WriteNoResponse "; - if (m_properties & BLE_GATT_CHR_PROP_BROADCAST) res += "Broadcast "; - if (m_properties & BLE_GATT_CHR_PROP_NOTIFY) res += "Notify "; - if (m_properties & BLE_GATT_CHR_PROP_INDICATE) res += "Indicate "; - return res; -} // toString - - -NimBLECharacteristicCallbacks::~NimBLECharacteristicCallbacks() {} - - -/** - * @brief Callback function to support a read request. - * @param [in] pCharacteristic The characteristic that is the source of the event. - */ -void NimBLECharacteristicCallbacks::onRead(NimBLECharacteristic* pCharacteristic) { - NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onRead: default"); -} // onRead - -/** - * @brief Callback function to support a read request. - * @param [in] pCharacteristic The characteristic that is the source of the event. - * @param [in] desc The connection description struct that is associated with the peer that performed the read. - */ -void NimBLECharacteristicCallbacks::onRead(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc) { - NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onRead: default"); -} // onRead - -/** - * @brief Callback function to support a write request. - * @param [in] pCharacteristic The characteristic that is the source of the event. - */ -void NimBLECharacteristicCallbacks::onWrite(NimBLECharacteristic* pCharacteristic) { - NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onWrite: default"); -} // onWrite - -/** - * @brief Callback function to support a write request. - * @param [in] pCharacteristic The characteristic that is the source of the event. - * @param [in] desc The connection description struct that is associated with the peer that performed the write. - */ -void NimBLECharacteristicCallbacks::onWrite(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc) { - NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onWrite: default"); -} // onWrite - -/** - * @brief Callback function to support a Notify request. - * @param [in] pCharacteristic The characteristic that is the source of the event. - */ -void NimBLECharacteristicCallbacks::onNotify(NimBLECharacteristic* pCharacteristic) { - NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onNotify: default"); -} // onNotify - - -/** - * @brief Callback function to support a Notify/Indicate Status report. - * @param [in] pCharacteristic The characteristic that is the source of the event. - * @param [in] s Status of the notification/indication. - * @param [in] code Additional return code from the NimBLE stack. - */ -void NimBLECharacteristicCallbacks::onStatus(NimBLECharacteristic* pCharacteristic, Status s, int code) { - NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onStatus: default"); -} // onStatus - - -/** - * @brief Callback function called when a client changes subscription status. - * @param [in] pCharacteristic The characteristic that is the source of the event. - * @param [in] desc The connection description struct that is associated with the client. - * @param [in] subValue The subscription status: - * * 0 = Un-Subscribed - * * 1 = Notifications - * * 2 = Indications - * * 3 = Notifications and Indications - */ -void NimBLECharacteristicCallbacks::onSubscribe(NimBLECharacteristic* pCharacteristic, - ble_gap_conn_desc* desc, - uint16_t subValue) -{ - NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onSubscribe: default"); -} - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLECharacteristic.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLECharacteristic.h deleted file mode 100644 index 0f84e2d9b..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLECharacteristic.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - * NimBLECharacteristic.h - * - * Created: on March 3, 2020 - * Author H2zero - * - * Originally: - * BLECharacteristic.h - * - * Created on: Jun 22, 2017 - * Author: kolban - */ - -#ifndef MAIN_NIMBLECHARACTERISTIC_H_ -#define MAIN_NIMBLECHARACTERISTIC_H_ -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "host/ble_hs.h" -#else -#include "nimble/nimble/host/include/host/ble_hs.h" -#endif - -/**** FIX COMPILATION ****/ -#undef min -#undef max -/**************************/ - -typedef enum { - READ = BLE_GATT_CHR_F_READ, - READ_ENC = BLE_GATT_CHR_F_READ_ENC, - READ_AUTHEN = BLE_GATT_CHR_F_READ_AUTHEN, - READ_AUTHOR = BLE_GATT_CHR_F_READ_AUTHOR, - WRITE = BLE_GATT_CHR_F_WRITE, - WRITE_NR = BLE_GATT_CHR_F_WRITE_NO_RSP, - WRITE_ENC = BLE_GATT_CHR_F_WRITE_ENC, - WRITE_AUTHEN = BLE_GATT_CHR_F_WRITE_AUTHEN, - WRITE_AUTHOR = BLE_GATT_CHR_F_WRITE_AUTHOR, - BROADCAST = BLE_GATT_CHR_F_BROADCAST, - NOTIFY = BLE_GATT_CHR_F_NOTIFY, - INDICATE = BLE_GATT_CHR_F_INDICATE -} NIMBLE_PROPERTY; - -#include "NimBLEService.h" -#include "NimBLEDescriptor.h" -#include "NimBLEAttValue.h" - -#include -#include - -class NimBLEService; -class NimBLEDescriptor; -class NimBLECharacteristicCallbacks; - - -/** - * @brief The model of a %BLE Characteristic. - * - * A BLE Characteristic is an identified value container that manages a value. It is exposed by a BLE server and - * can be read and written to by a %BLE client. - */ -class NimBLECharacteristic { -public: - NimBLECharacteristic(const char* uuid, - uint16_t properties = - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE, - uint16_t max_len = BLE_ATT_ATTR_MAX_LEN, - NimBLEService* pService = nullptr); - NimBLECharacteristic(const NimBLEUUID &uuid, - uint16_t properties = - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE, - uint16_t max_len = BLE_ATT_ATTR_MAX_LEN, - NimBLEService* pService = nullptr); - - ~NimBLECharacteristic(); - - uint16_t getHandle(); - NimBLEUUID getUUID(); - std::string toString(); - void indicate(); - void indicate(const uint8_t* value, size_t length); - void indicate(const std::vector& value); - void notify(bool is_notification = true); - void notify(const uint8_t* value, size_t length, bool is_notification = true); - void notify(const std::vector& value, bool is_notification = true); - size_t getSubscribedCount(); - void addDescriptor(NimBLEDescriptor *pDescriptor); - NimBLEDescriptor* getDescriptorByUUID(const char* uuid); - NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid); - NimBLEDescriptor* getDescriptorByHandle(uint16_t handle); - void removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc = false); - NimBLEService* getService(); - uint16_t getProperties(); - NimBLEAttValue getValue(time_t *timestamp = nullptr); - size_t getDataLength(); - void setValue(const uint8_t* data, size_t size); - void setValue(const std::vector& vec); - void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks); - NimBLEDescriptor* createDescriptor(const char* uuid, - uint32_t properties = - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE, - uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);; - NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid, - uint32_t properties = - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE, - uint16_t max_len = BLE_ATT_ATTR_MAX_LEN); - - NimBLECharacteristicCallbacks* getCallbacks(); - - - /*********************** Template Functions ************************/ - - /** - * @brief Template to set the characteristic value to val. - * @param [in] s The value to set. - */ - template - void setValue(const T &s) { m_value.setValue(s); } - - /** - * @brief Template to convert the characteristic data to . - * @tparam T The type to convert the data to. - * @param [in] timestamp (Optional) A pointer to a time_t struct to store the time the value was read. - * @param [in] skipSizeCheck (Optional) If true it will skip checking if the data size is less than sizeof(). - * @return The data converted to or NULL if skipSizeCheck is false and the data is less than sizeof(). - * @details Use: getValue(×tamp, skipSizeCheck); - */ - template - T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) { - return m_value.getValue(timestamp, skipSizeCheck); - } - - /** - * @brief Template to send a notification from a class type that has a c_str() and length() method. - * @tparam T The a reference to a class containing the data to send. - * @param[in] value The value to set. - * @param[in] is_notification if true sends a notification, false sends an indication. - * @details Only used if the has a `c_str()` method. - */ - template -#ifdef _DOXYGEN_ - void -#else - typename std::enable_if::value, void>::type -#endif - notify(const T& value, bool is_notification = true) { - notify((uint8_t*)value.c_str(), value.length(), is_notification); - } - - /** - * @brief Template to send an indication from a class type that has a c_str() and length() method. - * @tparam T The a reference to a class containing the data to send. - * @param[in] value The value to set. - * @details Only used if the has a `c_str()` method. - */ - template -#ifdef _DOXYGEN_ - void -#else - typename std::enable_if::value, void>::type -#endif - indicate(const T& value) { - indicate((uint8_t*)value.c_str(), value.length()); - } - -private: - - friend class NimBLEServer; - friend class NimBLEService; - - void setService(NimBLEService *pService); - void setSubscribe(struct ble_gap_event *event); - static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg); - - NimBLEUUID m_uuid; - uint16_t m_handle; - uint16_t m_properties; - NimBLECharacteristicCallbacks* m_pCallbacks; - NimBLEService* m_pService; - NimBLEAttValue m_value; - std::vector m_dscVec; - uint8_t m_removed; - - std::vector> m_subscribedVec; -}; // NimBLECharacteristic - - -/** - * @brief Callbacks that can be associated with a %BLE characteristic to inform of events. - * - * When a server application creates a %BLE characteristic, we may wish to be informed when there is either - * a read or write request to the characteristic's value. An application can register a - * sub-classed instance of this class and will be notified when such an event happens. - */ -class NimBLECharacteristicCallbacks { -public: - -/** - * @brief An enum to provide the callback the status of the - * notification/indication, implemented for backward compatibility. - * @deprecated To be removed in the future as the NimBLE stack return code is also provided. - */ - typedef enum { - SUCCESS_INDICATE, - SUCCESS_NOTIFY, - ERROR_INDICATE_DISABLED, - ERROR_NOTIFY_DISABLED, - ERROR_GATT, - ERROR_NO_CLIENT, - ERROR_INDICATE_TIMEOUT, - ERROR_INDICATE_FAILURE - }Status; - - virtual ~NimBLECharacteristicCallbacks(); - virtual void onRead(NimBLECharacteristic* pCharacteristic); - virtual void onRead(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc); - virtual void onWrite(NimBLECharacteristic* pCharacteristic); - virtual void onWrite(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc); - virtual void onNotify(NimBLECharacteristic* pCharacteristic); - virtual void onStatus(NimBLECharacteristic* pCharacteristic, Status s, int code); - virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc, uint16_t subValue); -}; - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */ -#endif /*MAIN_NIMBLECHARACTERISTIC_H_*/ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.cpp deleted file mode 100644 index a83e23b4a..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.cpp +++ /dev/null @@ -1,1299 +0,0 @@ -/* - * NimBLEClient.cpp - * - * Created: on Jan 26 2020 - * Author H2zero - * - * Originally: - * BLEClient.cpp - * - * Created on: Mar 22, 2017 - * Author: kolban - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) - -#include "NimBLEClient.h" -#include "NimBLEDevice.h" -#include "NimBLELog.h" - -#include -#include -#include - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "nimble/nimble_port.h" -#else -#include "nimble/porting/nimble/include/nimble/nimble_port.h" -#endif - -static const char* LOG_TAG = "NimBLEClient"; -static NimBLEClientCallbacks defaultCallbacks; - -/* - * Design - * ------ - * When we perform a getService() request, we are asking the BLE server to return each of the services - * that it exposes. For each service, we receive a callback which contains details - * of the exposed service including its UUID. - * - * The objects we will invent for a NimBLEClient will be as follows: - * * NimBLERemoteService - A model of a remote service. - * * NimBLERemoteCharacteristic - A model of a remote characteristic - * * NimBLERemoteDescriptor - A model of a remote descriptor. - * - * Since there is a hierarchical relationship here, we will have the idea that from a NimBLERemoteService will own - * zero or more remote characteristics and a NimBLERemoteCharacteristic will own zero or more remote NimBLEDescriptors. - * - * We will assume that a NimBLERemoteService contains a vector of owned characteristics - * and that a NimBLECharacteristic contains a vector of owned descriptors. - * - * - */ - - -/** - * @brief Constructor, private - only callable by NimBLEDevice::createClient - * to ensure proper handling of the list of client objects. - */ -NimBLEClient::NimBLEClient(const NimBLEAddress &peerAddress) : m_peerAddress(peerAddress) { - m_pClientCallbacks = &defaultCallbacks; - m_conn_id = BLE_HS_CONN_HANDLE_NONE; - m_connectTimeout = 30000; - m_deleteCallbacks = false; - m_pTaskData = nullptr; - m_connEstablished = false; - m_lastErr = 0; -#if CONFIG_BT_NIMBLE_EXT_ADV - m_phyMask = BLE_GAP_LE_PHY_1M_MASK | - BLE_GAP_LE_PHY_2M_MASK | - BLE_GAP_LE_PHY_CODED_MASK; -#endif - - m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default) - m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default) - m_pConnParams.itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN; // min_int = 0x10*1.25ms = 20ms - m_pConnParams.itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX; // max_int = 0x20*1.25ms = 40ms - m_pConnParams.latency = BLE_GAP_INITIAL_CONN_LATENCY; // number of packets allowed to skip (extends max interval) - m_pConnParams.supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT; // timeout = 400*10ms = 4000ms - m_pConnParams.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units - m_pConnParams.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units - - memset(&m_dcTimer, 0, sizeof(m_dcTimer)); - ble_npl_callout_init(&m_dcTimer, nimble_port_get_dflt_eventq(), - NimBLEClient::dcTimerCb, this); -} // NimBLEClient - - -/** - * @brief Destructor, private - only callable by NimBLEDevice::deleteClient - * to ensure proper disconnect and removal from device list. - */ -NimBLEClient::~NimBLEClient() { - // We may have allocated service references associated with this client. - // Before we are finished with the client, we must release resources. - deleteServices(); - - if(m_deleteCallbacks && m_pClientCallbacks != &defaultCallbacks) { - delete m_pClientCallbacks; - } - - ble_npl_callout_deinit(&m_dcTimer); - -} // ~NimBLEClient - - -/** - * @brief If we have asked to disconnect and the event does not - * occur within the supervision timeout + added delay, this will - * be called to reset the host in the case of a stalled controller. - */ -void NimBLEClient::dcTimerCb(ble_npl_event *event) { - /* NimBLEClient *pClient = (NimBLEClient*)event->arg; - NIMBLE_LOGC(LOG_TAG, "Timed out disconnecting from %s - resetting host", - std::string(pClient->getPeerAddress()).c_str()); - */ - ble_hs_sched_reset(BLE_HS_ECONTROLLER); -} - - -/** - * @brief Delete all service objects created by this client and clear the vector. - */ -void NimBLEClient::deleteServices() { - NIMBLE_LOGD(LOG_TAG, ">> deleteServices"); - // Delete all the services. - for(auto &it: m_servicesVector) { - delete it; - } - m_servicesVector.clear(); - - NIMBLE_LOGD(LOG_TAG, "<< deleteServices"); -} // deleteServices - - -/** - * @brief Delete service by UUID - * @param [in] uuid The UUID of the service to be deleted from the local database. - * @return Number of services left. - */ -size_t NimBLEClient::deleteService(const NimBLEUUID &uuid) { - NIMBLE_LOGD(LOG_TAG, ">> deleteService"); - // Delete the requested service. - for(auto it = m_servicesVector.begin(); it != m_servicesVector.end(); ++it) { - if((*it)->getUUID() == uuid) { - delete *it; - m_servicesVector.erase(it); - break; - } - } - - NIMBLE_LOGD(LOG_TAG, "<< deleteService"); - - return m_servicesVector.size(); -} // deleteServices - - -/** - * @brief Connect to the BLE Server. - * @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n - * have created and clears the vectors after successful connection. - * @return True on success. - */ -bool NimBLEClient::connect(bool deleteAttributes) { - return connect(m_peerAddress, deleteAttributes); -} - -/** - * @brief Connect to an advertising device. - * @param [in] device The device to connect to. - * @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n - * have created and clears the vectors after successful connection. - * @return True on success. - */ -bool NimBLEClient::connect(NimBLEAdvertisedDevice* device, bool deleteAttributes) { - NimBLEAddress address(device->getAddress()); - return connect(address, deleteAttributes); -} - - -/** - * @brief Connect to the BLE Server. - * @param [in] address The address of the server. - * @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n - * have created and clears the vectors after successful connection. - * @return True on success. - */ -bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes) { - NIMBLE_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str()); - - if(!NimBLEDevice::m_synced) { - NIMBLE_LOGC(LOG_TAG, "Host reset, wait for sync."); - return false; - } - - if(isConnected() || m_connEstablished || m_pTaskData != nullptr) { - NIMBLE_LOGE(LOG_TAG, "Client busy, connected to %s, id=%d", - std::string(m_peerAddress).c_str(), getConnId()); - return false; - } - - ble_addr_t peerAddr_t; - memcpy(&peerAddr_t.val, address.getNative(),6); - peerAddr_t.type = address.getType(); - if(ble_gap_conn_find_by_addr(&peerAddr_t, NULL) == 0) { - NIMBLE_LOGE(LOG_TAG, "A connection to %s already exists", - address.toString().c_str()); - return false; - } - - if(address == NimBLEAddress("")) { - NIMBLE_LOGE(LOG_TAG, "Invalid peer address;(NULL)"); - return false; - } else { - m_peerAddress = address; - } - - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {this, cur_task, 0, nullptr}; - m_pTaskData = &taskData; - int rc = 0; - - /* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for - * timeout (default value of m_connectTimeout). - * Loop on BLE_HS_EBUSY if the scan hasn't stopped yet. - */ - do { -#if CONFIG_BT_NIMBLE_EXT_ADV - rc = ble_gap_ext_connect(NimBLEDevice::m_own_addr_type, - &peerAddr_t, - m_connectTimeout, - m_phyMask, - &m_pConnParams, - &m_pConnParams, - &m_pConnParams, - NimBLEClient::handleGapEvent, - this); - -#else - rc = ble_gap_connect(NimBLEDevice::m_own_addr_type, &peerAddr_t, - m_connectTimeout, &m_pConnParams, - NimBLEClient::handleGapEvent, this); -#endif - switch (rc) { - case 0: - break; - - case BLE_HS_EBUSY: - // Scan was still running, stop it and try again - if (!NimBLEDevice::getScan()->stop()) { - rc = BLE_HS_EUNKNOWN; - } - break; - - case BLE_HS_EDONE: - // A connection to this device already exists, do not connect twice. - NIMBLE_LOGE(LOG_TAG, "Already connected to device; addr=%s", - std::string(m_peerAddress).c_str()); - break; - - case BLE_HS_EALREADY: - // Already attempting to connect to this device, cancel the previous - // attempt and report failure here so we don't get 2 connections. - NIMBLE_LOGE(LOG_TAG, "Already attempting to connect to %s - cancelling", - std::string(m_peerAddress).c_str()); - ble_gap_conn_cancel(); - break; - - default: - NIMBLE_LOGE(LOG_TAG, "Failed to connect to %s, rc=%d; %s", - std::string(m_peerAddress).c_str(), - rc, NimBLEUtils::returnCodeToString(rc)); - break; - } - - } while (rc == BLE_HS_EBUSY); - - m_lastErr = rc; - - if(rc != 0) { - m_pTaskData = nullptr; - return false; - } - -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif - // Wait for the connect timeout time +1 second for the connection to complete - if(ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) { - m_pTaskData = nullptr; - // If a connection was made but no response from MTU exchange; disconnect - if(isConnected()) { - NIMBLE_LOGE(LOG_TAG, "Connect timeout - no response"); - disconnect(); - } else { - // workaround; if the controller doesn't cancel the connection - // at the timeout, cancel it here. - NIMBLE_LOGE(LOG_TAG, "Connect timeout - cancelling"); - ble_gap_conn_cancel(); - } - - return false; - - } else if(taskData.rc != 0){ - m_lastErr = taskData.rc; - NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s", - taskData.rc, - NimBLEUtils::returnCodeToString(taskData.rc)); - // If the failure was not a result of a disconnection - // make sure we disconnect now to avoid dangling connections - if(isConnected()) { - disconnect(); - } - return false; - } else { - NIMBLE_LOGI(LOG_TAG, "Connection established"); - } - - if(deleteAttributes) { - deleteServices(); - } - - m_connEstablished = true; - m_pClientCallbacks->onConnect(this); - - NIMBLE_LOGD(LOG_TAG, "<< connect()"); - // Check if still connected before returning - return isConnected(); -} // connect - - -/** - * @brief Initiate a secure connection (pair/bond) with the server.\n - * Called automatically when a characteristic or descriptor requires encryption or authentication to access it. - * @return True on success. - */ -bool NimBLEClient::secureConnection() { - NIMBLE_LOGD(LOG_TAG, ">> secureConnection()"); - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {this, cur_task, 0, nullptr}; - - int retryCount = 1; - - do { - m_pTaskData = &taskData; - - int rc = NimBLEDevice::startSecurity(m_conn_id); - if(rc != 0 && rc != BLE_HS_EALREADY){ - m_lastErr = rc; - m_pTaskData = nullptr; - return false; - } - -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - } while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--); - - if(taskData.rc != 0){ - m_lastErr = taskData.rc; - NIMBLE_LOGE(LOG_TAG, "secureConnection: failed rc=%d", taskData.rc); - return false; - } - - NIMBLE_LOGD(LOG_TAG, "<< secureConnection: success"); - return true; -} // secureConnection - - -/** - * @brief Disconnect from the peer. - * @return Error code from NimBLE stack, 0 = success. - */ -int NimBLEClient::disconnect(uint8_t reason) { - NIMBLE_LOGD(LOG_TAG, ">> disconnect()"); - int rc = 0; - if(isConnected()) { - // If the timer was already started, ignore this call. - if(ble_npl_callout_is_active(&m_dcTimer)) { - NIMBLE_LOGI(LOG_TAG, "Already disconnecting, timer started"); - return BLE_HS_EALREADY; - } - - ble_gap_conn_desc desc; - if(ble_gap_conn_find(m_conn_id, &desc) != 0){ - NIMBLE_LOGI(LOG_TAG, "Connection ID not found"); - return BLE_HS_EALREADY; - } - - // We use a timer to detect a controller error in the event that it does - // not inform the stack when disconnection is complete. - // This is a common error in certain esp-idf versions. - // The disconnect timeout time is the supervision timeout time + 1 second. - // In the case that the event happens shortly after the supervision timeout - // we don't want to prematurely reset the host. - ble_npl_time_t ticks; - ble_npl_time_ms_to_ticks((desc.supervision_timeout + 100) * 10, &ticks); - ble_npl_callout_reset(&m_dcTimer, ticks); - - rc = ble_gap_terminate(m_conn_id, reason); - if (rc != 0) { - if(rc != BLE_HS_EALREADY) { - ble_npl_callout_stop(&m_dcTimer); - } - NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s", - rc, NimBLEUtils::returnCodeToString(rc)); - } - } else { - NIMBLE_LOGD(LOG_TAG, "Not connected to any peers"); - } - - NIMBLE_LOGD(LOG_TAG, "<< disconnect()"); - m_lastErr = rc; - return rc; -} // disconnect - - -#if CONFIG_BT_NIMBLE_EXT_ADV -/** - * @brief Set the PHY types to use when connecting to a server. - * @param [in] mask A bitmask indicating what PHYS to connect with.\n - * The available bits are: - * * 0x01 BLE_GAP_LE_PHY_1M_MASK - * * 0x02 BLE_GAP_LE_PHY_2M_MASK - * * 0x04 BLE_GAP_LE_PHY_CODED_MASK - */ -void NimBLEClient::setConnectPhy(uint8_t mask) { - m_phyMask = mask; -} -#endif - - -/** - * @brief Set the connection parameters to use when connecting to a server. - * @param [in] minInterval The minimum connection interval in 1.25ms units. - * @param [in] maxInterval The maximum connection interval in 1.25ms units. - * @param [in] latency The number of packets allowed to skip (extends max interval). - * @param [in] timeout The timeout time in 10ms units before disconnecting. - * @param [in] scanInterval The scan interval to use when attempting to connect in 0.625ms units. - * @param [in] scanWindow The scan window to use when attempting to connect in 0.625ms units. - */ -void NimBLEClient::setConnectionParams(uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout, - uint16_t scanInterval, uint16_t scanWindow)/*, - uint16_t minConnTime, uint16_t maxConnTime)*/ -{ - - m_pConnParams.scan_itvl = scanInterval; - m_pConnParams.scan_window = scanWindow; - m_pConnParams.itvl_min = minInterval; - m_pConnParams.itvl_max = maxInterval; - m_pConnParams.latency = latency; - m_pConnParams.supervision_timeout = timeout; - - // These are not used by NimBLE at this time - Must leave at defaults - //m_pConnParams->min_ce_len = minConnTime; // Minimum length of connection event in 0.625ms units - //m_pConnParams->max_ce_len = maxConnTime; // Maximum length of connection event in 0.625ms units - - int rc = NimBLEUtils::checkConnParams(&m_pConnParams); - assert(rc == 0 && "Invalid Connection parameters"); -} // setConnectionParams - - -/** - * @brief Update the connection parameters: - * * Can only be used after a connection has been established. - * @param [in] minInterval The minimum connection interval in 1.25ms units. - * @param [in] maxInterval The maximum connection interval in 1.25ms units. - * @param [in] latency The number of packets allowed to skip (extends max interval). - * @param [in] timeout The timeout time in 10ms units before disconnecting. - */ -void NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout) -{ - ble_gap_upd_params params; - - params.latency = latency; - params.itvl_max = maxInterval; - params.itvl_min = minInterval; - params.supervision_timeout = timeout; - // These are not used by NimBLE at this time - Must leave at defaults - params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; - params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; - - int rc = ble_gap_update_params(m_conn_id, ¶ms); - if(rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); - } -} // updateConnParams - - -/** - * @brief Request an update of the data packet length. - * * Can only be used after a connection has been established. - * @details Sends a data length update request to the server the client is connected to. - * The Data Length Extension (DLE) allows to increase the Data Channel Payload from 27 bytes to up to 251 bytes. - * The server needs to support the Bluetooth 4.2 specifications, to be capable of DLE. - * @param [in] tx_octets The preferred number of payload octets to use (Range 0x001B-0x00FB). - */ -void NimBLEClient::setDataLen(uint16_t tx_octets) { -#if defined(CONFIG_NIMBLE_CPP_IDF) && !defined(ESP_IDF_VERSION) || \ - (ESP_IDF_VERSION_MAJOR * 100 + ESP_IDF_VERSION_MINOR * 10 + ESP_IDF_VERSION_PATCH) < 432 - return; -#else - uint16_t tx_time = (tx_octets + 14) * 8; - - int rc = ble_gap_set_data_len(m_conn_id, tx_octets, tx_time); - if(rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Set data length error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); - } -#endif -} // setDataLen - - -/** - * @brief Get detailed information about the current peer connection. - */ -NimBLEConnInfo NimBLEClient::getConnInfo() { - NimBLEConnInfo connInfo; - if (!isConnected()) { - NIMBLE_LOGE(LOG_TAG, "Not connected"); - } else { - int rc = ble_gap_conn_find(m_conn_id, &connInfo.m_desc); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Connection info not found"); - } - } - - return connInfo; -} // getConnInfo - - -/** - * @brief Set the timeout to wait for connection attempt to complete. - * @param [in] time The number of seconds before timeout. - */ -void NimBLEClient::setConnectTimeout(uint8_t time) { - m_connectTimeout = (uint32_t)(time * 1000); -} // setConnectTimeout - - -/** - * @brief Get the connection id for this client. - * @return The connection id. - */ -uint16_t NimBLEClient::getConnId() { - return m_conn_id; -} // getConnId - - -/** - * @brief Retrieve the address of the peer. - */ -NimBLEAddress NimBLEClient::getPeerAddress() { - return m_peerAddress; -} // getPeerAddress - - -/** - * @brief Set the peer address. - * @param [in] address The address of the peer that this client is - * connected or should connect to. - */ -void NimBLEClient::setPeerAddress(const NimBLEAddress &address) { - if(isConnected()) { - NIMBLE_LOGE(LOG_TAG, "Cannot set peer address while connected"); - return; - } - - m_peerAddress = address; - NIMBLE_LOGD(LOG_TAG, "Peer address set: %s", std::string(m_peerAddress).c_str()); -} // setPeerAddress - - -/** - * @brief Ask the BLE server for the RSSI value. - * @return The RSSI value. - */ -int NimBLEClient::getRssi() { - NIMBLE_LOGD(LOG_TAG, ">> getRssi()"); - if (!isConnected()) { - NIMBLE_LOGE(LOG_TAG, "<< getRssi(): Not connected"); - return 0; - } - - int8_t rssiValue = 0; - int rc = ble_gap_conn_rssi(m_conn_id, &rssiValue); - if(rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Failed to read RSSI error code: %d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); - m_lastErr = rc; - return 0; - } - - return rssiValue; -} // getRssi - - -/** - * @brief Get iterator to the beginning of the vector of remote service pointers. - * @return An iterator to the beginning of the vector of remote service pointers. - */ -std::vector::iterator NimBLEClient::begin() { - return m_servicesVector.begin(); -} - - -/** - * @brief Get iterator to the end of the vector of remote service pointers. - * @return An iterator to the end of the vector of remote service pointers. - */ -std::vector::iterator NimBLEClient::end() { - return m_servicesVector.end(); -} - - -/** - * @brief Get the service BLE Remote Service instance corresponding to the uuid. - * @param [in] uuid The UUID of the service being sought. - * @return A pointer to the service or nullptr if not found. - */ -NimBLERemoteService* NimBLEClient::getService(const char* uuid) { - return getService(NimBLEUUID(uuid)); -} // getService - - -/** - * @brief Get the service object corresponding to the uuid. - * @param [in] uuid The UUID of the service being sought. - * @return A pointer to the service or nullptr if not found. - */ -NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) { - NIMBLE_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str()); - - for(auto &it: m_servicesVector) { - if(it->getUUID() == uuid) { - NIMBLE_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str()); - return it; - } - } - - size_t prev_size = m_servicesVector.size(); - if(retrieveServices(&uuid)) { - if(m_servicesVector.size() > prev_size) { - return m_servicesVector.back(); - } - - // If the request was successful but 16/32 bit uuid not found - // try again with the 128 bit uuid. - if(uuid.bitSize() == BLE_UUID_TYPE_16 || - uuid.bitSize() == BLE_UUID_TYPE_32) - { - NimBLEUUID uuid128(uuid); - uuid128.to128(); - if(retrieveServices(&uuid128)) { - if(m_servicesVector.size() > prev_size) { - return m_servicesVector.back(); - } - } - } else { - // If the request was successful but the 128 bit uuid not found - // try again with the 16 bit uuid. - NimBLEUUID uuid16(uuid); - uuid16.to16(); - // if the uuid was 128 bit but not of the BLE base type this check will fail - if (uuid16.bitSize() == BLE_UUID_TYPE_16) { - if(retrieveServices(&uuid16)) { - if(m_servicesVector.size() > prev_size) { - return m_servicesVector.back(); - } - } - } - } - } - - NIMBLE_LOGD(LOG_TAG, "<< getService: not found"); - return nullptr; -} // getService - - -/** - * @brief Get a pointer to the vector of found services. - * @param [in] refresh If true the current services vector will be cleared and\n - * all services will be retrieved from the peripheral.\n - * If false the vector will be returned with the currently stored services. - * @return A pointer to the vector of available services. - */ -std::vector* NimBLEClient::getServices(bool refresh) { - if(refresh) { - deleteServices(); - - if (!retrieveServices()) { - NIMBLE_LOGE(LOG_TAG, "Error: Failed to get services"); - } - else{ - NIMBLE_LOGI(LOG_TAG, "Found %d services", m_servicesVector.size()); - } - } - return &m_servicesVector; -} // getServices - - -/** - * @brief Retrieves the full database of attributes that the peripheral has available. - * @return True if successful. - */ -bool NimBLEClient::discoverAttributes() { - deleteServices(); - - if (!retrieveServices()){ - return false; - } - - - for(auto svc: m_servicesVector) { - if (!svc->retrieveCharacteristics()) { - return false; - } - - for(auto chr: svc->m_characteristicVector) { - if (!chr->retrieveDescriptors()) { - return false; - } - } - } - - return true; -} // discoverAttributes - - -/** - * @brief Ask the remote %BLE server for its services.\n - * Here we ask the server for its set of services and wait until we have received them all. - * @return true on success otherwise false if an error occurred - */ -bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) { -/** - * Design - * ------ - * We invoke ble_gattc_disc_all_svcs. This will request a list of the services exposed by the - * peer BLE partner to be returned in the callback function provided. - */ - - NIMBLE_LOGD(LOG_TAG, ">> retrieveServices"); - - if(!isConnected()){ - NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve services -aborting"); - return false; - } - - int rc = 0; - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {this, cur_task, 0, nullptr}; - - if(uuid_filter == nullptr) { - rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, &taskData); - } else { - rc = ble_gattc_disc_svc_by_uuid(m_conn_id, &uuid_filter->getNative()->u, - NimBLEClient::serviceDiscoveredCB, &taskData); - } - - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_svcs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); - m_lastErr = rc; - return false; - } - -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif - - // wait until we have all the services - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - m_lastErr = taskData.rc; - - if(taskData.rc == 0){ - NIMBLE_LOGD(LOG_TAG, "<< retrieveServices"); - return true; - } - else { - NIMBLE_LOGE(LOG_TAG, "Could not retrieve services"); - return false; - } -} // getServices - - -/** - * @brief STATIC Callback for the service discovery API function.\n - * When a service is found or there is none left or there was an error - * the API will call this and report findings. - */ -int NimBLEClient::serviceDiscoveredCB( - uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_svc *service, void *arg) -{ - NIMBLE_LOGD(LOG_TAG,"Service Discovered >> status: %d handle: %d", - error->status, (error->status == 0) ? service->start_handle : -1); - - ble_task_data_t *pTaskData = (ble_task_data_t*)arg; - NimBLEClient *client = (NimBLEClient*)pTaskData->pATT; - - // Make sure the service discovery is for this device - if(client->getConnId() != conn_handle){ - return 0; - } - - if(error->status == 0) { - // Found a service - add it to the vector - NimBLERemoteService* pRemoteService = new NimBLERemoteService(client, service); - client->m_servicesVector.push_back(pRemoteService); - return 0; - } - - if(error->status == BLE_HS_EDONE) { - pTaskData->rc = 0; - } else { - NIMBLE_LOGE(LOG_TAG, "serviceDiscoveredCB() rc=%d %s", - error->status, - NimBLEUtils::returnCodeToString(error->status)); - pTaskData->rc = error->status; - } - - xTaskNotifyGive(pTaskData->task); - - NIMBLE_LOGD(LOG_TAG,"<< Service Discovered"); - return error->status; -} - - -/** - * @brief Get the value of a specific characteristic associated with a specific service. - * @param [in] serviceUUID The service that owns the characteristic. - * @param [in] characteristicUUID The characteristic whose value we wish to read. - * @returns characteristic value or an empty string if not found - */ -NimBLEAttValue NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID) { - NIMBLE_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s", - serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); - - NimBLEAttValue ret; - NimBLERemoteService* pService = getService(serviceUUID); - - if(pService != nullptr) { - NimBLERemoteCharacteristic* pChar = pService->getCharacteristic(characteristicUUID); - if(pChar != nullptr) { - ret = pChar->readValue(); - } - } - - NIMBLE_LOGD(LOG_TAG, "<< getValue"); - return ret; -} // getValue - - -/** - * @brief Set the value of a specific characteristic associated with a specific service. - * @param [in] serviceUUID The service that owns the characteristic. - * @param [in] characteristicUUID The characteristic whose value we wish to write. - * @param [in] value The value to write to the characteristic. - * @param [in] response If true, uses write with response operation. - * @returns true if successful otherwise false - */ -bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID, - const NimBLEAttValue &value, bool response) -{ - NIMBLE_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s", - serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); - - bool ret = false; - NimBLERemoteService* pService = getService(serviceUUID); - - if(pService != nullptr) { - NimBLERemoteCharacteristic* pChar = pService->getCharacteristic(characteristicUUID); - if(pChar != nullptr) { - ret = pChar->writeValue(value, response); - } - } - - NIMBLE_LOGD(LOG_TAG, "<< setValue"); - return ret; -} // setValue - - -/** - * @brief Get the remote characteristic with the specified handle. - * @param [in] handle The handle of the desired characteristic. - * @returns The matching remote characteristic, nullptr otherwise. - */ -NimBLERemoteCharacteristic* NimBLEClient::getCharacteristic(const uint16_t handle) -{ - NimBLERemoteService *pService = nullptr; - for(auto it = m_servicesVector.begin(); it != m_servicesVector.end(); ++it) { - if ((*it)->getStartHandle() <= handle && handle <= (*it)->getEndHandle()) { - pService = *it; - break; - } - } - - if (pService != nullptr) { - for (auto it = pService->begin(); it != pService->end(); ++it) { - if ((*it)->getHandle() == handle) { - return *it; - } - } - } - - return nullptr; -} - -/** - * @brief Get the current mtu of this connection. - * @returns The MTU value. - */ -uint16_t NimBLEClient::getMTU() { - return ble_att_mtu(m_conn_id); -} // getMTU - - -/** - * @brief Handle a received GAP event. - * @param [in] event The event structure sent by the NimBLE stack. - * @param [in] arg A pointer to the client instance that registered for this callback. - */ - /*STATIC*/ -int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { - NimBLEClient* client = (NimBLEClient*)arg; - int rc; - - NIMBLE_LOGD(LOG_TAG, "Got Client event %s", NimBLEUtils::gapEventToString(event->type)); - - switch(event->type) { - - case BLE_GAP_EVENT_DISCONNECT: { - rc = event->disconnect.reason; - // If Host reset tell the device now before returning to prevent - // any errors caused by calling host functions before resyncing. - switch(rc) { - case BLE_HS_ECONTROLLER: - case BLE_HS_ETIMEOUT_HCI: - case BLE_HS_ENOTSYNCED: - case BLE_HS_EOS: - NIMBLE_LOGC(LOG_TAG, "Disconnect - host reset, rc=%d", rc); - NimBLEDevice::onReset(rc); - break; - default: - // Check that the event is for this client. - if(client->m_conn_id != event->disconnect.conn.conn_handle) { - return 0; - } - break; - } - - // Stop the disconnect timer since we are now disconnected. - ble_npl_callout_stop(&client->m_dcTimer); - - // Remove the device from ignore list so we will scan it again - NimBLEDevice::removeIgnored(client->m_peerAddress); - - // No longer connected, clear the connection ID. - client->m_conn_id = BLE_HS_CONN_HANDLE_NONE; - - // If we received a connected event but did not get established (no PDU) - // then a disconnect event will be sent but we should not send it to the - // app for processing. Instead we will ensure the task is released - // and report the error. - if(!client->m_connEstablished) - break; - - NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); - - client->m_connEstablished = false; - client->m_pClientCallbacks->onDisconnect(client); - break; - } // BLE_GAP_EVENT_DISCONNECT - - case BLE_GAP_EVENT_CONNECT: { - // If we aren't waiting for this connection response - // we should drop the connection immediately. - if(client->isConnected() || client->m_pTaskData == nullptr) { - ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM); - return 0; - } - - rc = event->connect.status; - if (rc == 0) { - NIMBLE_LOGI(LOG_TAG, "Connected event"); - - client->m_conn_id = event->connect.conn_handle; - - rc = ble_gattc_exchange_mtu(client->m_conn_id, NULL,NULL); - if(rc != 0) { - NIMBLE_LOGE(LOG_TAG, "MTU exchange error; rc=%d %s", - rc, NimBLEUtils::returnCodeToString(rc)); - break; - } - - // In the case of a multiconnecting device we ignore this device when - // scanning since we are already connected to it - NimBLEDevice::addIgnored(client->m_peerAddress); - } else { - client->m_conn_id = BLE_HS_CONN_HANDLE_NONE; - break; - } - - return 0; - } // BLE_GAP_EVENT_CONNECT - - case BLE_GAP_EVENT_NOTIFY_RX: { - if(client->m_conn_id != event->notify_rx.conn_handle) - return 0; - - // If a notification comes before this flag is set we might - // access a vector while it is being cleared in connect() - if(!client->m_connEstablished) { - return 0; - } - - NIMBLE_LOGD(LOG_TAG, "Notify Recieved for handle: %d", - event->notify_rx.attr_handle); - - for(auto &it: client->m_servicesVector) { - // Dont waste cycles searching services without this handle in its range - if(it->getEndHandle() < event->notify_rx.attr_handle) { - continue; - } - - auto cVector = &it->m_characteristicVector; - NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d", - it->getUUID().toString().c_str(), - event->notify_rx.attr_handle); - - auto characteristic = cVector->cbegin(); - for(; characteristic != cVector->cend(); ++characteristic) { - if((*characteristic)->m_handle == event->notify_rx.attr_handle) - break; - } - - if(characteristic != cVector->cend()) { - NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", - (*characteristic)->toString().c_str()); - - uint32_t data_len = OS_MBUF_PKTLEN(event->notify_rx.om); - (*characteristic)->m_value.setValue(event->notify_rx.om->om_data, data_len); - - if ((*characteristic)->m_notifyCallback != nullptr) { - NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s", - (*characteristic)->toString().c_str()); - (*characteristic)->m_notifyCallback(*characteristic, event->notify_rx.om->om_data, - data_len, !event->notify_rx.indication); - } - break; - } - } - - return 0; - } // BLE_GAP_EVENT_NOTIFY_RX - - case BLE_GAP_EVENT_CONN_UPDATE_REQ: - case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: { - if(client->m_conn_id != event->conn_update_req.conn_handle){ - return 0; - } - NIMBLE_LOGD(LOG_TAG, "Peer requesting to update connection parameters"); - NIMBLE_LOGD(LOG_TAG, "MinInterval: %d, MaxInterval: %d, Latency: %d, Timeout: %d", - event->conn_update_req.peer_params->itvl_min, - event->conn_update_req.peer_params->itvl_max, - event->conn_update_req.peer_params->latency, - event->conn_update_req.peer_params->supervision_timeout); - - rc = client->m_pClientCallbacks->onConnParamsUpdateRequest(client, - event->conn_update_req.peer_params) ? 0 : BLE_ERR_CONN_PARMS; - - - if(!rc && event->type == BLE_GAP_EVENT_CONN_UPDATE_REQ ) { - event->conn_update_req.self_params->itvl_min = client->m_pConnParams.itvl_min; - event->conn_update_req.self_params->itvl_max = client->m_pConnParams.itvl_max; - event->conn_update_req.self_params->latency = client->m_pConnParams.latency; - event->conn_update_req.self_params->supervision_timeout = client->m_pConnParams.supervision_timeout; - } - - NIMBLE_LOGD(LOG_TAG, "%s peer params", (rc == 0) ? "Accepted" : "Rejected"); - return rc; - } // BLE_GAP_EVENT_CONN_UPDATE_REQ, BLE_GAP_EVENT_L2CAP_UPDATE_REQ - - case BLE_GAP_EVENT_CONN_UPDATE: { - if(client->m_conn_id != event->conn_update.conn_handle){ - return 0; - } - if(event->conn_update.status == 0) { - NIMBLE_LOGI(LOG_TAG, "Connection parameters updated."); - } else { - NIMBLE_LOGE(LOG_TAG, "Update connection parameters failed."); - } - return 0; - } // BLE_GAP_EVENT_CONN_UPDATE - - case BLE_GAP_EVENT_ENC_CHANGE: { - if(client->m_conn_id != event->enc_change.conn_handle){ - return 0; - } - - if(event->enc_change.status == 0 || - event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING)) - { - struct ble_gap_conn_desc desc; - rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc); - assert(rc == 0); - - if (event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING)) { - // Key is missing, try deleting. - ble_store_util_delete_peer(&desc.peer_id_addr); - } else if(NimBLEDevice::m_securityCallbacks != nullptr) { - NimBLEDevice::m_securityCallbacks->onAuthenticationComplete(&desc); - } else { - client->m_pClientCallbacks->onAuthenticationComplete(&desc); - } - } - - rc = event->enc_change.status; - break; - } //BLE_GAP_EVENT_ENC_CHANGE - - case BLE_GAP_EVENT_MTU: { - if(client->m_conn_id != event->mtu.conn_handle){ - return 0; - } - NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d", - event->mtu.conn_handle, - event->mtu.value); - rc = 0; - break; - } // BLE_GAP_EVENT_MTU - - case BLE_GAP_EVENT_PASSKEY_ACTION: { - struct ble_sm_io pkey = {0,0}; - - if(client->m_conn_id != event->passkey.conn_handle) - return 0; - - if (event->passkey.params.action == BLE_SM_IOACT_DISP) { - pkey.action = event->passkey.params.action; - pkey.passkey = NimBLEDevice::m_passkey; // This is the passkey to be entered on peer - rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); - NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc); - - } else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) { - NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp); - pkey.action = event->passkey.params.action; - // Compatibility only - Do not use, should be removed the in future - if(NimBLEDevice::m_securityCallbacks != nullptr) { - pkey.numcmp_accept = NimBLEDevice::m_securityCallbacks->onConfirmPIN(event->passkey.params.numcmp); - //////////////////////////////////////////////////// - } else { - pkey.numcmp_accept = client->m_pClientCallbacks->onConfirmPIN(event->passkey.params.numcmp); - } - - rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); - NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc); - - //TODO: Handle out of band pairing - } else if (event->passkey.params.action == BLE_SM_IOACT_OOB) { - static uint8_t tem_oob[16] = {0}; - pkey.action = event->passkey.params.action; - for (int i = 0; i < 16; i++) { - pkey.oob[i] = tem_oob[i]; - } - rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); - NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc); - //////// - } else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) { - NIMBLE_LOGD(LOG_TAG, "Enter the passkey"); - pkey.action = event->passkey.params.action; - - // Compatibility only - Do not use, should be removed the in future - if(NimBLEDevice::m_securityCallbacks != nullptr) { - pkey.passkey = NimBLEDevice::m_securityCallbacks->onPassKeyRequest(); - ///////////////////////////////////////////// - } else { - pkey.passkey = client->m_pClientCallbacks->onPassKeyRequest(); - } - - rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); - NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc); - - } else if (event->passkey.params.action == BLE_SM_IOACT_NONE) { - NIMBLE_LOGD(LOG_TAG, "No passkey action required"); - } - - return 0; - } // BLE_GAP_EVENT_PASSKEY_ACTION - - default: { - return 0; - } - } // Switch - - if(client->m_pTaskData != nullptr) { - client->m_pTaskData->rc = rc; - if(client->m_pTaskData->task) { - xTaskNotifyGive(client->m_pTaskData->task); - } - client->m_pTaskData = nullptr; - } - - return 0; -} // handleGapEvent - - -/** - * @brief Are we connected to a server? - * @return True if we are connected and false if we are not connected. - */ -bool NimBLEClient::isConnected() { - return m_conn_id != BLE_HS_CONN_HANDLE_NONE; -} // isConnected - - -/** - * @brief Set the callbacks that will be invoked when events are received. - * @param [in] pClientCallbacks A pointer to a class to receive the event callbacks. - * @param [in] deleteCallbacks If true this will delete the callback class sent when the client is destructed. - */ -void NimBLEClient::setClientCallbacks(NimBLEClientCallbacks* pClientCallbacks, bool deleteCallbacks) { - if (pClientCallbacks != nullptr){ - m_pClientCallbacks = pClientCallbacks; - } else { - m_pClientCallbacks = &defaultCallbacks; - } - m_deleteCallbacks = deleteCallbacks; -} // setClientCallbacks - - -/** - * @brief Return a string representation of this client. - * @return A string representation of this client. - */ -std::string NimBLEClient::toString() { - std::string res = "peer address: " + m_peerAddress.toString(); - res += "\nServices:\n"; - - for(auto &it: m_servicesVector) { - res += it->toString() + "\n"; - } - - return res; -} // toString - - -/** - * @brief Get the last error code reported by the NimBLE host - * @return int, the NimBLE error code. - */ -int NimBLEClient::getLastError() { - return m_lastErr; -} // getLastError - - -void NimBLEClientCallbacks::onConnect(NimBLEClient* pClient) { - NIMBLE_LOGD("NimBLEClientCallbacks", "onConnect: default"); -} - -void NimBLEClientCallbacks::onDisconnect(NimBLEClient* pClient) { - NIMBLE_LOGD("NimBLEClientCallbacks", "onDisconnect: default"); -} - -bool NimBLEClientCallbacks::onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params) { - NIMBLE_LOGD("NimBLEClientCallbacks", "onConnParamsUpdateRequest: default"); - return true; -} - -uint32_t NimBLEClientCallbacks::onPassKeyRequest(){ - NIMBLE_LOGD("NimBLEClientCallbacks", "onPassKeyRequest: default: 123456"); - return 123456; -} -/* -void NimBLEClientCallbacks::onPassKeyNotify(uint32_t pass_key){ - NIMBLE_LOGD("NimBLEClientCallbacks", "onPassKeyNotify: default: %d", pass_key); -} - -bool NimBLEClientCallbacks::onSecurityRequest(){ - NIMBLE_LOGD("NimBLEClientCallbacks", "onSecurityRequest: default: true"); - return true; -}*/ -void NimBLEClientCallbacks::onAuthenticationComplete(ble_gap_conn_desc* desc){ - NIMBLE_LOGD("NimBLEClientCallbacks", "onAuthenticationComplete: default"); -} -bool NimBLEClientCallbacks::onConfirmPIN(uint32_t pin){ - NIMBLE_LOGD("NimBLEClientCallbacks", "onConfirmPIN: default: true"); - return true; -} - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.h deleted file mode 100644 index d3c16b727..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * NimBLEClient.h - * - * Created: on Jan 26 2020 - * Author H2zero - * - * Originally: - * BLEClient.h - * - * Created on: Mar 22, 2017 - * Author: kolban - */ - -#ifndef MAIN_NIMBLECLIENT_H_ -#define MAIN_NIMBLECLIENT_H_ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) - -#include "NimBLEAddress.h" -#include "NimBLEUUID.h" -#include "NimBLEUtils.h" -#include "NimBLEConnInfo.h" -#include "NimBLEAttValue.h" -#include "NimBLEAdvertisedDevice.h" -#include "NimBLERemoteService.h" - -#include -#include - -class NimBLERemoteService; -class NimBLERemoteCharacteristic; -class NimBLEClientCallbacks; -class NimBLEAdvertisedDevice; - -/** - * @brief A model of a %BLE client. - */ -class NimBLEClient { -public: - bool connect(NimBLEAdvertisedDevice* device, bool deleteAttributes = true); - bool connect(const NimBLEAddress &address, bool deleteAttributes = true); - bool connect(bool deleteAttributes = true); - int disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); - NimBLEAddress getPeerAddress(); - void setPeerAddress(const NimBLEAddress &address); - int getRssi(); - std::vector* getServices(bool refresh = false); - std::vector::iterator begin(); - std::vector::iterator end(); - NimBLERemoteService* getService(const char* uuid); - NimBLERemoteService* getService(const NimBLEUUID &uuid); - void deleteServices(); - size_t deleteService(const NimBLEUUID &uuid); - NimBLEAttValue getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID); - bool setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID, - const NimBLEAttValue &value, bool response = false); - NimBLERemoteCharacteristic* getCharacteristic(const uint16_t handle); - bool isConnected(); - void setClientCallbacks(NimBLEClientCallbacks *pClientCallbacks, - bool deleteCallbacks = true); - std::string toString(); - uint16_t getConnId(); - uint16_t getMTU(); - bool secureConnection(); - void setConnectTimeout(uint8_t timeout); - void setConnectionParams(uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout, - uint16_t scanInterval=16, uint16_t scanWindow=16); - void updateConnParams(uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout); - void setDataLen(uint16_t tx_octets); - bool discoverAttributes(); - NimBLEConnInfo getConnInfo(); - int getLastError(); -#if CONFIG_BT_NIMBLE_EXT_ADV - void setConnectPhy(uint8_t mask); -#endif - -private: - NimBLEClient(const NimBLEAddress &peerAddress); - ~NimBLEClient(); - - friend class NimBLEDevice; - friend class NimBLERemoteService; - - static int handleGapEvent(struct ble_gap_event *event, void *arg); - static int serviceDiscoveredCB(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_svc *service, - void *arg); - static void dcTimerCb(ble_npl_event *event); - bool retrieveServices(const NimBLEUUID *uuid_filter = nullptr); - - NimBLEAddress m_peerAddress; - int m_lastErr; - uint16_t m_conn_id; - bool m_connEstablished; - bool m_deleteCallbacks; - int32_t m_connectTimeout; - NimBLEClientCallbacks* m_pClientCallbacks; - ble_task_data_t* m_pTaskData; - ble_npl_callout m_dcTimer; -#if CONFIG_BT_NIMBLE_EXT_ADV - uint8_t m_phyMask; -#endif - - std::vector m_servicesVector; - -private: - friend class NimBLEClientCallbacks; - ble_gap_conn_params m_pConnParams; - -}; // class NimBLEClient - - -/** - * @brief Callbacks associated with a %BLE client. - */ -class NimBLEClientCallbacks { -public: - virtual ~NimBLEClientCallbacks() {}; - - /** - * @brief Called after client connects. - * @param [in] pClient A pointer to the calling client object. - */ - virtual void onConnect(NimBLEClient* pClient); - - /** - * @brief Called when disconnected from the server. - * @param [in] pClient A pointer to the calling client object. - */ - virtual void onDisconnect(NimBLEClient* pClient); - - /** - * @brief Called when server requests to update the connection parameters. - * @param [in] pClient A pointer to the calling client object. - * @param [in] params A pointer to the struct containing the connection parameters requested. - * @return True to accept the parameters. - */ - virtual bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params); - - /** - * @brief Called when server requests a passkey for pairing. - * @return The passkey to be sent to the server. - */ - virtual uint32_t onPassKeyRequest(); - - /*virtual void onPassKeyNotify(uint32_t pass_key); - virtual bool onSecurityRequest();*/ - - /** - * @brief Called when the pairing procedure is complete. - * @param [in] desc A pointer to the struct containing the connection information.\n - * This can be used to check the status of the connection encryption/pairing. - */ - virtual void onAuthenticationComplete(ble_gap_conn_desc* desc); - - /** - * @brief Called when using numeric comparision for pairing. - * @param [in] pin The pin to compare with the server. - * @return True to accept the pin. - */ - virtual bool onConfirmPIN(uint32_t pin); -}; - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ -#endif /* MAIN_NIMBLECLIENT_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEConnInfo.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEConnInfo.h deleted file mode 100644 index e357d8cbc..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEConnInfo.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef NIMBLECONNINFO_H_ -#define NIMBLECONNINFO_H_ - -#include "NimBLEAddress.h" - -/** - * @brief Connection information. - */ -class NimBLEConnInfo { -friend class NimBLEServer; -friend class NimBLEClient; - ble_gap_conn_desc m_desc; - NimBLEConnInfo() { m_desc = {}; } - NimBLEConnInfo(ble_gap_conn_desc desc) { m_desc = desc; } -public: - /** @brief Gets the over-the-air address of the connected peer */ - NimBLEAddress getAddress() { return NimBLEAddress(m_desc.peer_ota_addr); } - - /** @brief Gets the ID address of the connected peer */ - NimBLEAddress getIdAddress() { return NimBLEAddress(m_desc.peer_id_addr); } - - /** @brief Gets the connection handle of the connected peer */ - uint16_t getConnHandle() { return m_desc.conn_handle; } - - /** @brief Gets the connection interval for this connection (in 1.25ms units) */ - uint16_t getConnInterval() { return m_desc.conn_itvl; } - - /** @brief Gets the supervision timeout for this connection (in 10ms units) */ - uint16_t getConnTimeout() { return m_desc.supervision_timeout; } - - /** @brief Gets the allowable latency for this connection (unit = number of intervals) */ - uint16_t getConnLatency() { return m_desc.conn_latency; } - - /** @brief Gets the maximum transmission unit size for this connection (in bytes) */ - uint16_t getMTU() { return ble_att_mtu(m_desc.conn_handle); } - - /** @brief Check if we are in the master role in this connection */ - bool isMaster() { return (m_desc.role == BLE_GAP_ROLE_MASTER); } - - /** @brief Check if we are in the slave role in this connection */ - bool isSlave() { return (m_desc.role == BLE_GAP_ROLE_SLAVE); } - - /** @brief Check if we are connected to a bonded peer */ - bool isBonded() { return (m_desc.sec_state.bonded == 1); } - - /** @brief Check if the connection in encrypted */ - bool isEncrypted() { return (m_desc.sec_state.encrypted == 1); } - - /** @brief Check if the the connection has been authenticated */ - bool isAuthenticated() { return (m_desc.sec_state.authenticated == 1); } - - /** @brief Gets the key size used to encrypt the connection */ - uint8_t getSecKeySize() { return m_desc.sec_state.key_size; } -}; -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDescriptor.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDescriptor.cpp deleted file mode 100644 index e2e6c1bc8..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDescriptor.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* - * NimBLEDescriptor.cpp - * - * Created: on March 10, 2020 - * Author H2zero - * - * Originally: - * - * BLEDescriptor.cpp - * - * Created on: Jun 22, 2017 - * Author: kolban - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include "NimBLEService.h" -#include "NimBLEDescriptor.h" -#include "NimBLELog.h" - -#include - -#define NULL_HANDLE (0xffff) - -static const char* LOG_TAG = "NimBLEDescriptor"; -static NimBLEDescriptorCallbacks defaultCallbacks; - - -/** - * @brief Construct a descriptor - * @param [in] uuid - UUID (const char*) for the descriptor. - * @param [in] properties - Properties for the descriptor. - * @param [in] max_len - The maximum length in bytes that the descriptor value can hold. (Default: 512 bytes for esp32, 20 for all others). - * @param [in] pCharacteristic - pointer to the characteristic instance this descriptor belongs to. - */ -NimBLEDescriptor::NimBLEDescriptor(const char* uuid, uint16_t properties, uint16_t max_len, - NimBLECharacteristic* pCharacteristic) -: NimBLEDescriptor(NimBLEUUID(uuid), properties, max_len, pCharacteristic) { -} - - -/** - * @brief Construct a descriptor - * @param [in] uuid - UUID (const char*) for the descriptor. - * @param [in] properties - Properties for the descriptor. - * @param [in] max_len - The maximum length in bytes that the descriptor value can hold. (Default: 512 bytes for esp32, 20 for all others). - * @param [in] pCharacteristic - pointer to the characteristic instance this descriptor belongs to. - */ -NimBLEDescriptor::NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, uint16_t max_len, - NimBLECharacteristic* pCharacteristic) -: m_value(std::min(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH , (int)max_len), max_len) { - m_uuid = uuid; - m_handle = NULL_HANDLE; // Handle is initially unknown. - m_pCharacteristic = pCharacteristic; - m_pCallbacks = &defaultCallbacks; // No initial callback. - m_properties = 0; - m_removed = 0; - - if (properties & BLE_GATT_CHR_F_READ) { // convert uint16_t properties to uint8_t - m_properties |= BLE_ATT_F_READ; - } - if (properties & (BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_WRITE)) { - m_properties |= BLE_ATT_F_WRITE; - } - if (properties & BLE_GATT_CHR_F_READ_ENC) { - m_properties |= BLE_ATT_F_READ_ENC; - } - if (properties & BLE_GATT_CHR_F_READ_AUTHEN) { - m_properties |= BLE_ATT_F_READ_AUTHEN; - } - if (properties & BLE_GATT_CHR_F_READ_AUTHOR) { - m_properties |= BLE_ATT_F_READ_AUTHOR; - } - if (properties & BLE_GATT_CHR_F_WRITE_ENC) { - m_properties |= BLE_ATT_F_WRITE_ENC; - } - if (properties & BLE_GATT_CHR_F_WRITE_AUTHEN) { - m_properties |= BLE_ATT_F_WRITE_AUTHEN; - } - if (properties & BLE_GATT_CHR_F_WRITE_AUTHOR) { - m_properties |= BLE_ATT_F_WRITE_AUTHOR; - } - -} // NimBLEDescriptor - - -/** - * @brief NimBLEDescriptor destructor. - */ -NimBLEDescriptor::~NimBLEDescriptor() { -} // ~NimBLEDescriptor - -/** - * @brief Get the BLE handle for this descriptor. - * @return The handle for this descriptor. - */ -uint16_t NimBLEDescriptor::getHandle() { - return m_handle; -} // getHandle - - -/** - * @brief Get the length of the value of this descriptor. - * @return The length (in bytes) of the value of this descriptor. - */ -size_t NimBLEDescriptor::getLength() { - return m_value.size(); -} // getLength - - -/** - * @brief Get the UUID of the descriptor. - */ -NimBLEUUID NimBLEDescriptor::getUUID() { - return m_uuid; -} // getUUID - - -/** - * @brief Get the value of this descriptor. - * @return The NimBLEAttValue of this descriptor. - */ -NimBLEAttValue NimBLEDescriptor::getValue(time_t *timestamp) { - if (timestamp != nullptr) { - m_value.getValue(timestamp); - } - - return m_value; -} // getValue - - -/** - * @brief Get the value of this descriptor as a string. - * @return A std::string instance containing a copy of the descriptor's value. - */ -std::string NimBLEDescriptor::getStringValue() { - return std::string(m_value); -} - - -/** - * @brief Get the characteristic this descriptor belongs to. - * @return A pointer to the characteristic this descriptor belongs to. - */ -NimBLECharacteristic* NimBLEDescriptor::getCharacteristic() { - return m_pCharacteristic; -} // getCharacteristic - - -int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg) { - (void)conn_handle; - (void)attr_handle; - - const ble_uuid_t *uuid; - int rc; - struct ble_gap_conn_desc desc; - NimBLEDescriptor* pDescriptor = (NimBLEDescriptor*)arg; - - NIMBLE_LOGD(LOG_TAG, "Descriptor %s %s event", pDescriptor->getUUID().toString().c_str(), - ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC ? "Read" : "Write"); - - uuid = ctxt->chr->uuid; - if(ble_uuid_cmp(uuid, &pDescriptor->getUUID().getNative()->u) == 0){ - switch(ctxt->op) { - case BLE_GATT_ACCESS_OP_READ_DSC: { - rc = ble_gap_conn_find(conn_handle, &desc); - assert(rc == 0); - - // If the packet header is only 8 bytes this is a follow up of a long read - // so we don't want to call the onRead() callback again. - if(ctxt->om->om_pkthdr_len > 8 || - pDescriptor->m_value.size() <= (ble_att_mtu(desc.conn_handle) - 3)) { - pDescriptor->m_pCallbacks->onRead(pDescriptor); - } - - ble_npl_hw_enter_critical(); - rc = os_mbuf_append(ctxt->om, pDescriptor->m_value.data(), pDescriptor->m_value.size()); - ble_npl_hw_exit_critical(0); - return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; - } - - case BLE_GATT_ACCESS_OP_WRITE_DSC: { - uint16_t att_max_len = pDescriptor->m_value.max_size(); - - if (ctxt->om->om_len > att_max_len) { - return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; - } - - uint8_t buf[att_max_len]; - size_t len = ctxt->om->om_len; - memcpy(buf, ctxt->om->om_data,len); - os_mbuf *next; - next = SLIST_NEXT(ctxt->om, om_next); - while(next != NULL){ - if((len + next->om_len) > att_max_len) { - return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; - } - memcpy(&buf[len], next->om_data, next->om_len); - len += next->om_len; - next = SLIST_NEXT(next, om_next); - } - - pDescriptor->setValue(buf, len); - pDescriptor->m_pCallbacks->onWrite(pDescriptor); - return 0; - } - default: - break; - } - } - - return BLE_ATT_ERR_UNLIKELY; -} - -/** - * @brief Set the callback handlers for this descriptor. - * @param [in] pCallbacks An instance of a callback structure used to define any callbacks for the descriptor. - */ -void NimBLEDescriptor::setCallbacks(NimBLEDescriptorCallbacks* pCallbacks) { - if (pCallbacks != nullptr){ - m_pCallbacks = pCallbacks; - } else { - m_pCallbacks = &defaultCallbacks; - } -} // setCallbacks - - -/** - * @brief Set the handle of this descriptor. - * Set the handle of this descriptor to be the supplied value. - * @param [in] handle The handle to be associated with this descriptor. - * @return N/A. - */ -void NimBLEDescriptor::setHandle(uint16_t handle) { - NIMBLE_LOGD(LOG_TAG, ">> setHandle(0x%.2x): Setting descriptor handle to be 0x%.2x", handle, handle); - m_handle = handle; - NIMBLE_LOGD(LOG_TAG, "<< setHandle()"); -} // setHandle - - -/** - * @brief Set the value of the descriptor. - * @param [in] data The data to set for the descriptor. - * @param [in] length The length of the data in bytes. - */ -void NimBLEDescriptor::setValue(const uint8_t* data, size_t length) { - m_value.setValue(data, length); -} // setValue - - -/** - * @brief Set the value of the descriptor from a `std::vector`.\n - * @param [in] vec The std::vector reference to set the descriptor value from. - */ -void NimBLEDescriptor::setValue(const std::vector& vec) { - return setValue((uint8_t*)&vec[0], vec.size()); -} // setValue - - -/** - * @brief Set the characteristic this descriptor belongs to. - * @param [in] pChar A pointer to the characteristic this descriptor belongs to. - */ -void NimBLEDescriptor::setCharacteristic(NimBLECharacteristic* pChar) { - m_pCharacteristic = pChar; -} // setCharacteristic - - -/** - * @brief Return a string representation of the descriptor. - * @return A string representation of the descriptor. - */ -std::string NimBLEDescriptor::toString() { - char hex[5]; - snprintf(hex, sizeof(hex), "%04x", m_handle); - std::string res = "UUID: " + m_uuid.toString() + ", handle: 0x" + hex; - return res; -} // toString - - -NimBLEDescriptorCallbacks::~NimBLEDescriptorCallbacks() {} - -/** - * @brief Callback function to support a read request. - * @param [in] pDescriptor The descriptor that is the source of the event. - */ -void NimBLEDescriptorCallbacks::onRead(NimBLEDescriptor* pDescriptor) { - (void)pDescriptor; - NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onRead: default"); -} // onRead - - -/** - * @brief Callback function to support a write request. - * @param [in] pDescriptor The descriptor that is the source of the event. - */ -void NimBLEDescriptorCallbacks::onWrite(NimBLEDescriptor* pDescriptor) { - (void)pDescriptor; - NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onWrite: default"); -} // onWrite - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDescriptor.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDescriptor.h deleted file mode 100644 index 4ee9a6243..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDescriptor.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * NimBLEDescriptor.h - * - * Created: on March 10, 2020 - * Author H2zero - * - * Originally: - * - * BLEDescriptor.h - * - * Created on: Jun 22, 2017 - * Author: kolban - */ - -#ifndef MAIN_NIMBLEDESCRIPTOR_H_ -#define MAIN_NIMBLEDESCRIPTOR_H_ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include "NimBLECharacteristic.h" -#include "NimBLEUUID.h" -#include "NimBLEAttValue.h" - -#include - -class NimBLEService; -class NimBLECharacteristic; -class NimBLEDescriptorCallbacks; - - -/** - * @brief A model of a %BLE descriptor. - */ -class NimBLEDescriptor { -public: - NimBLEDescriptor(const char* uuid, uint16_t properties, - uint16_t max_len, - NimBLECharacteristic* pCharacteristic = nullptr); - - NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, - uint16_t max_len, - NimBLECharacteristic* pCharacteristic = nullptr); - - ~NimBLEDescriptor(); - - uint16_t getHandle(); - NimBLEUUID getUUID(); - std::string toString(); - void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks); - NimBLECharacteristic* getCharacteristic(); - - size_t getLength(); - NimBLEAttValue getValue(time_t *timestamp = nullptr); - std::string getStringValue(); - - void setValue(const uint8_t* data, size_t size); - void setValue(const std::vector& vec); - - /*********************** Template Functions ************************/ - - /** - * @brief Template to set the characteristic value to val. - * @param [in] s The value to set. - */ - template - void setValue(const T &s) { m_value.setValue(s); } - - /** - * @brief Template to convert the descriptor data to . - * @tparam T The type to convert the data to. - * @param [in] timestamp (Optional) A pointer to a time_t struct to store the time the value was read. - * @param [in] skipSizeCheck (Optional) If true it will skip checking if the data size is less than sizeof(). - * @return The data converted to or NULL if skipSizeCheck is false and the data is less than sizeof(). - * @details Use: getValue(×tamp, skipSizeCheck); - */ - template - T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) { - return m_value.getValue(timestamp, skipSizeCheck); - } - -private: - friend class NimBLECharacteristic; - friend class NimBLEService; - friend class NimBLE2904; - - static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg); - void setHandle(uint16_t handle); - void setCharacteristic(NimBLECharacteristic* pChar); - - NimBLEUUID m_uuid; - uint16_t m_handle; - NimBLEDescriptorCallbacks* m_pCallbacks; - NimBLECharacteristic* m_pCharacteristic; - uint8_t m_properties; - NimBLEAttValue m_value; - uint8_t m_removed; -}; // NimBLEDescriptor - - -/** - * @brief Callbacks that can be associated with a %BLE descriptors to inform of events. - * - * When a server application creates a %BLE descriptor, we may wish to be informed when there is either - * a read or write request to the descriptors value. An application can register a - * sub-classed instance of this class and will be notified when such an event happens. - */ -class NimBLEDescriptorCallbacks { -public: - virtual ~NimBLEDescriptorCallbacks(); - virtual void onRead(NimBLEDescriptor* pDescriptor); - virtual void onWrite(NimBLEDescriptor* pDescriptor); -}; - -#include "NimBLE2904.h" - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */ -#endif /* MAIN_NIMBLEDESCRIPTOR_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp deleted file mode 100644 index d2553b0e8..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp +++ /dev/null @@ -1,1213 +0,0 @@ -/* - * NimBLEDevice.cpp - * - * Created: on Jan 24 2020 - * Author H2zero - * - * Originally: - * - * BLEDevice.cpp - * - * Created on: Mar 16, 2017 - * Author: kolban - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "NimBLEDevice.h" -#include "NimBLEUtils.h" - -#ifdef ESP_PLATFORM -# include "esp_err.h" -# include "esp_bt.h" -# include "nvs_flash.h" -# if defined(CONFIG_NIMBLE_CPP_IDF) -# include "esp_nimble_hci.h" -# include "nimble/nimble_port.h" -# include "nimble/nimble_port_freertos.h" -# include "host/ble_hs.h" -# include "host/ble_hs_pvcy.h" -# include "host/util/util.h" -# include "services/gap/ble_svc_gap.h" -# include "services/gatt/ble_svc_gatt.h" -# else -# include "nimble/esp_port/esp-hci/include/esp_nimble_hci.h" -# endif -#else -# include "nimble/nimble/controller/include/controller/ble_phy.h" -#endif - -#ifndef CONFIG_NIMBLE_CPP_IDF -# include "nimble/porting/nimble/include/nimble/nimble_port.h" -# include "nimble/porting/npl/freertos/include/nimble/nimble_port_freertos.h" -# include "nimble/nimble/host/include/host/ble_hs.h" -# include "nimble/nimble/host/include/host/ble_hs_pvcy.h" -# include "nimble/nimble/host/util/include/host/util/util.h" -# include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h" -# include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h" -#endif - -#if defined(ESP_PLATFORM) && defined(CONFIG_ENABLE_ARDUINO_DEPENDS) -# include "esp32-hal-bt.h" -#endif - -#include "NimBLELog.h" - -static const char* LOG_TAG = "NimBLEDevice"; - -/** - * Singletons for the NimBLEDevice. - */ -static bool initialized = false; -#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) -NimBLEScan* NimBLEDevice::m_pScan = nullptr; -#endif -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) -NimBLEServer* NimBLEDevice::m_pServer = nullptr; -#endif -uint32_t NimBLEDevice::m_passkey = 123456; -bool NimBLEDevice::m_synced = false; -#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) -# if CONFIG_BT_NIMBLE_EXT_ADV -NimBLEExtAdvertising* NimBLEDevice::m_bleAdvertising = nullptr; -# else -NimBLEAdvertising* NimBLEDevice::m_bleAdvertising = nullptr; -# endif -#endif - -gap_event_handler NimBLEDevice::m_customGapHandler = nullptr; -ble_gap_event_listener NimBLEDevice::m_listener; -#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL) -std::list NimBLEDevice::m_cList; -#endif -std::list NimBLEDevice::m_ignoreList; -std::vector NimBLEDevice::m_whiteList; -NimBLESecurityCallbacks* NimBLEDevice::m_securityCallbacks = nullptr; -uint8_t NimBLEDevice::m_own_addr_type = BLE_OWN_ADDR_PUBLIC; -#ifdef ESP_PLATFORM -uint16_t NimBLEDevice::m_scanDuplicateSize = CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE; -uint8_t NimBLEDevice::m_scanFilterMode = CONFIG_BTDM_SCAN_DUPL_TYPE; -#endif - -/** - * @brief Create a new instance of a server. - * @return A new instance of the server. - */ -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) -/* STATIC */ NimBLEServer* NimBLEDevice::createServer() { - if(NimBLEDevice::m_pServer == nullptr) { - NimBLEDevice::m_pServer = new NimBLEServer(); - ble_gatts_reset(); - ble_svc_gap_init(); - ble_svc_gatt_init(); - } - - return m_pServer; -} // createServer - - -/** - * @brief Get the instance of the server. - * @return A pointer to the server instance. - */ -/* STATIC */ NimBLEServer* NimBLEDevice::getServer() { - return m_pServer; -} // getServer -#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - - -#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) -# if CONFIG_BT_NIMBLE_EXT_ADV -/** - * @brief Get the instance of the advertising object. - * @return A pointer to the advertising object. - */ -NimBLEExtAdvertising* NimBLEDevice::getAdvertising() { - if(m_bleAdvertising == nullptr) { - m_bleAdvertising = new NimBLEExtAdvertising(); - } - return m_bleAdvertising; -} - - -/** - * @brief Convenience function to begin advertising. - * @param [in] inst_id The extended advertisement instance ID to start. - * @param [in] duration How long to advertise for in milliseconds, 0 = forever (default). - * @param [in] max_events Maximum number of advertisement events to send, 0 = no limit (default). - * @return True if advertising started successfully. - */ -bool NimBLEDevice::startAdvertising(uint8_t inst_id, - int duration, - int max_events) { - return getAdvertising()->start(inst_id, duration, max_events); -} // startAdvertising - - -/** - * @brief Convenience function to stop advertising a data set. - * @param [in] inst_id The extended advertisement instance ID to stop advertising. - * @return True if advertising stopped successfully. - */ -bool NimBLEDevice::stopAdvertising(uint8_t inst_id) { - return getAdvertising()->stop(inst_id); -} // stopAdvertising - -# endif - -# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) -/** - * @brief Get the instance of the advertising object. - * @return A pointer to the advertising object. - */ -NimBLEAdvertising* NimBLEDevice::getAdvertising() { - if(m_bleAdvertising == nullptr) { - m_bleAdvertising = new NimBLEAdvertising(); - } - return m_bleAdvertising; -} - - -/** - * @brief Convenience function to begin advertising. - * @return True if advertising started successfully. - */ -bool NimBLEDevice::startAdvertising() { - return getAdvertising()->start(); -} // startAdvertising -# endif - -/** - * @brief Convenience function to stop all advertising. - * @return True if advertising stopped successfully. - */ -bool NimBLEDevice::stopAdvertising() { - return getAdvertising()->stop(); -} // stopAdvertising -#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) - - -/** - * @brief Retrieve the Scan object that we use for scanning. - * @return The scanning object reference. This is a singleton object. The caller should not - * try and release/delete it. - */ -#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) -/* STATIC */ -NimBLEScan* NimBLEDevice::getScan() { - if (m_pScan == nullptr) { - m_pScan = new NimBLEScan(); - } - return m_pScan; -} // getScan -#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) - - -/** - * @brief Creates a new client object and maintains a list of all client objects - * each client can connect to 1 peripheral device. - * @param [in] peerAddress An optional peer address that is copied to the new client - * object, allows for calling NimBLEClient::connect(bool) without a device or address parameter. - * @return A reference to the new client object. - */ -#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) -/* STATIC */ -NimBLEClient* NimBLEDevice::createClient(NimBLEAddress peerAddress) { - if(m_cList.size() >= NIMBLE_MAX_CONNECTIONS) { - NIMBLE_LOGW(LOG_TAG,"Number of clients exceeds Max connections. Cur=%d Max=%d", - m_cList.size(), NIMBLE_MAX_CONNECTIONS); - } - - NimBLEClient* pClient = new NimBLEClient(peerAddress); - m_cList.push_back(pClient); - - return pClient; -} // createClient - - -/** - * @brief Delete the client object and remove it from the list.\n - * Checks if it is connected or trying to connect and disconnects/stops it first. - * @param [in] pClient A pointer to the client object. - */ -/* STATIC */ -bool NimBLEDevice::deleteClient(NimBLEClient* pClient) { - if(pClient == nullptr) { - return false; - } - - // Set the connection established flag to false to stop notifications - // from accessing the attribute vectors while they are being deleted. - pClient->m_connEstablished = false; - int rc =0; - - if(pClient->isConnected()) { - rc = pClient->disconnect(); - if (rc != 0 && rc != BLE_HS_EALREADY && rc != BLE_HS_ENOTCONN) { - return false; - } - - while(pClient->isConnected()) { - taskYIELD(); - } - // Since we set the flag to false the app will not get a callback - // in the disconnect event so we call it here for good measure. - pClient->m_pClientCallbacks->onDisconnect(pClient); - - } else if(pClient->m_pTaskData != nullptr) { - rc = ble_gap_conn_cancel(); - if (rc != 0 && rc != BLE_HS_EALREADY) { - return false; - } - while(pClient->m_pTaskData != nullptr) { - taskYIELD(); - } - } - - m_cList.remove(pClient); - delete pClient; - - return true; -} // deleteClient - - -/** - * @brief Get the list of created client objects. - * @return A pointer to the list of clients. - */ -/* STATIC */ -std::list* NimBLEDevice::getClientList() { - return &m_cList; -} // getClientList - - -/** - * @brief Get the number of created client objects. - * @return Number of client objects created. - */ -/* STATIC */ -size_t NimBLEDevice::getClientListSize() { - return m_cList.size(); -} // getClientList - - -/** - * @brief Get a reference to a client by connection ID. - * @param [in] conn_id The client connection ID to search for. - * @return A pointer to the client object with the spcified connection ID. - */ -/* STATIC */ -NimBLEClient* NimBLEDevice::getClientByID(uint16_t conn_id) { - for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) { - if((*it)->getConnId() == conn_id) { - return (*it); - } - } - assert(0); - return nullptr; -} // getClientByID - - -/** - * @brief Get a reference to a client by peer address. - * @param [in] peer_addr The address of the peer to search for. - * @return A pointer to the client object with the peer address. - */ -/* STATIC */ -NimBLEClient* NimBLEDevice::getClientByPeerAddress(const NimBLEAddress &peer_addr) { - for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) { - if((*it)->getPeerAddress().equals(peer_addr)) { - return (*it); - } - } - return nullptr; -} // getClientPeerAddress - - -/** - * @brief Finds the first disconnected client in the list. - * @return A pointer to the first client object that is not connected to a peer. - */ -/* STATIC */ -NimBLEClient* NimBLEDevice::getDisconnectedClient() { - for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it) { - if(!(*it)->isConnected()) { - return (*it); - } - } - return nullptr; -} // getDisconnectedClient - -#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) - -#ifdef ESP_PLATFORM -/** - * @brief Set the transmission power. - * @param [in] powerLevel The power level to set, can be one of: - * * ESP_PWR_LVL_N12 = 0, Corresponding to -12dbm - * * ESP_PWR_LVL_N9 = 1, Corresponding to -9dbm - * * ESP_PWR_LVL_N6 = 2, Corresponding to -6dbm - * * ESP_PWR_LVL_N3 = 3, Corresponding to -3dbm - * * ESP_PWR_LVL_N0 = 4, Corresponding to 0dbm - * * ESP_PWR_LVL_P3 = 5, Corresponding to +3dbm - * * ESP_PWR_LVL_P6 = 6, Corresponding to +6dbm - * * ESP_PWR_LVL_P9 = 7, Corresponding to +9dbm - * @param [in] powerType The BLE function to set the power level for, can be one of: - * * ESP_BLE_PWR_TYPE_CONN_HDL0 = 0, For connection handle 0 - * * ESP_BLE_PWR_TYPE_CONN_HDL1 = 1, For connection handle 1 - * * ESP_BLE_PWR_TYPE_CONN_HDL2 = 2, For connection handle 2 - * * ESP_BLE_PWR_TYPE_CONN_HDL3 = 3, For connection handle 3 - * * ESP_BLE_PWR_TYPE_CONN_HDL4 = 4, For connection handle 4 - * * ESP_BLE_PWR_TYPE_CONN_HDL5 = 5, For connection handle 5 - * * ESP_BLE_PWR_TYPE_CONN_HDL6 = 6, For connection handle 6 - * * ESP_BLE_PWR_TYPE_CONN_HDL7 = 7, For connection handle 7 - * * ESP_BLE_PWR_TYPE_CONN_HDL8 = 8, For connection handle 8 - * * ESP_BLE_PWR_TYPE_ADV = 9, For advertising - * * ESP_BLE_PWR_TYPE_SCAN = 10, For scan - * * ESP_BLE_PWR_TYPE_DEFAULT = 11, For default, if not set other, it will use default value - */ -/* STATIC */ -void NimBLEDevice::setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType) { - NIMBLE_LOGD(LOG_TAG, ">> setPower: %d (type: %d)", powerLevel, powerType); - - esp_err_t errRc = esp_ble_tx_power_set(powerType, powerLevel); - if (errRc != ESP_OK) { - NIMBLE_LOGE(LOG_TAG, "esp_ble_tx_power_set: rc=%d", errRc); - } - - NIMBLE_LOGD(LOG_TAG, "<< setPower"); -} // setPower - - -/** - * @brief Get the transmission power. - * @param [in] powerType The power level to set, can be one of: - * * ESP_BLE_PWR_TYPE_CONN_HDL0 = 0, For connection handle 0 - * * ESP_BLE_PWR_TYPE_CONN_HDL1 = 1, For connection handle 1 - * * ESP_BLE_PWR_TYPE_CONN_HDL2 = 2, For connection handle 2 - * * ESP_BLE_PWR_TYPE_CONN_HDL3 = 3, For connection handle 3 - * * ESP_BLE_PWR_TYPE_CONN_HDL4 = 4, For connection handle 4 - * * ESP_BLE_PWR_TYPE_CONN_HDL5 = 5, For connection handle 5 - * * ESP_BLE_PWR_TYPE_CONN_HDL6 = 6, For connection handle 6 - * * ESP_BLE_PWR_TYPE_CONN_HDL7 = 7, For connection handle 7 - * * ESP_BLE_PWR_TYPE_CONN_HDL8 = 8, For connection handle 8 - * * ESP_BLE_PWR_TYPE_ADV = 9, For advertising - * * ESP_BLE_PWR_TYPE_SCAN = 10, For scan - * * ESP_BLE_PWR_TYPE_DEFAULT = 11, For default, if not set other, it will use default value - * @return the power level currently used by the type specified. - */ -/* STATIC */ -int NimBLEDevice::getPower(esp_ble_power_type_t powerType) { - switch(esp_ble_tx_power_get(powerType)) { - case ESP_PWR_LVL_N12: - return -12; - case ESP_PWR_LVL_N9: - return -9; - case ESP_PWR_LVL_N6: - return -6; - case ESP_PWR_LVL_N3: - return -3; - case ESP_PWR_LVL_N0: - return 0; - case ESP_PWR_LVL_P3: - return 3; - case ESP_PWR_LVL_P6: - return 6; - case ESP_PWR_LVL_P9: - return 9; - default: - return BLE_HS_ADV_TX_PWR_LVL_AUTO; - } -} // getPower - -#else - -void NimBLEDevice::setPower(int dbm) { - ble_phy_txpwr_set(dbm); -} - - -int NimBLEDevice::getPower() { - return ble_phy_txpwr_get(); -} -#endif - -/** - * @brief Get our device address. - * @return A NimBLEAddress object of our public address if we have one, - * if not then our current random address. - */ -/* STATIC*/ -NimBLEAddress NimBLEDevice::getAddress() { - ble_addr_t addr = {BLE_ADDR_PUBLIC, 0}; - - if(BLE_HS_ENOADDR == ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, addr.val, NULL)) { - NIMBLE_LOGD(LOG_TAG, "Public address not found, checking random"); - addr.type = BLE_ADDR_RANDOM; - ble_hs_id_copy_addr(BLE_ADDR_RANDOM, addr.val, NULL); - } - - return NimBLEAddress(addr); -} // getAddress - - -/** - * @brief Return a string representation of the address of this device. - * @return A string representation of this device address. - */ -/* STATIC */ -std::string NimBLEDevice::toString() { - return getAddress().toString(); -} // toString - - -/** - * @brief Setup local mtu that will be used to negotiate mtu during request from client peer. - * @param [in] mtu Value to set local mtu: - * * This should be larger than 23 and lower or equal to BLE_ATT_MTU_MAX = 527. - */ -/* STATIC */ -int NimBLEDevice::setMTU(uint16_t mtu) { - NIMBLE_LOGD(LOG_TAG, ">> setLocalMTU: %d", mtu); - - int rc = ble_att_set_preferred_mtu(mtu); - - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Could not set local mtu value to: %d", mtu); - } - - NIMBLE_LOGD(LOG_TAG, "<< setLocalMTU"); - return rc; -} // setMTU - - -/** - * @brief Get local MTU value set. - * @return The current preferred MTU setting. - */ -/* STATIC */ -uint16_t NimBLEDevice::getMTU() { - return ble_att_preferred_mtu(); -} - - -#ifdef ESP_PLATFORM -/** - * @brief Set the duplicate filter cache size for filtering scanned devices. - * @param [in] cacheSize The number of advertisements filtered before the cache is reset.\n - * Range is 10-1000, a larger value will reduce how often the same devices are reported. - * @details Must only be called before calling NimBLEDevice::init. - */ -/*STATIC*/ -void NimBLEDevice::setScanDuplicateCacheSize(uint16_t cacheSize) { - if(initialized) { - NIMBLE_LOGE(LOG_TAG, "Cannot change scan cache size while initialized"); - return; - } else if(cacheSize > 1000 || cacheSize <10) { - NIMBLE_LOGE(LOG_TAG, "Invalid scan cache size; min=10 max=1000"); - return; - } - - m_scanDuplicateSize = cacheSize; -} - - -/** - * @brief Set the duplicate filter mode for filtering scanned devices. - * @param [in] mode One of three possible options: - * * CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE (0) (default)\n - Filter by device address only, advertisements from the same address will be reported only once. - * * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA (1)\n - Filter by data only, advertisements with the same data will only be reported once,\n - even from different addresses. - * * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE (2)\n - Filter by address and data, advertisements from the same address will be reported only once,\n - except if the data in the advertisement has changed, then it will be reported again. - * @details Must only be called before calling NimBLEDevice::init. - */ -/*STATIC*/ -void NimBLEDevice::setScanFilterMode(uint8_t mode) { - if(initialized) { - NIMBLE_LOGE(LOG_TAG, "Cannot change scan duplicate type while initialized"); - return; - } else if(mode > 2) { - NIMBLE_LOGE(LOG_TAG, "Invalid scan duplicate type"); - return; - } - - m_scanFilterMode = mode; -} -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) -/** - * @brief Gets the number of bonded peers stored - */ -/*STATIC*/ -int NimBLEDevice::getNumBonds() { - ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; - int num_peers, rc; - - rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS)); - if (rc !=0) { - return 0; - } - - return num_peers; -} - - -/** - * @brief Deletes all bonding information. - */ -/*STATIC*/ -void NimBLEDevice::deleteAllBonds() { - ble_store_clear(); -} - - -/** - * @brief Deletes a peer bond. - * @param [in] address The address of the peer with which to delete bond info. - * @returns true on success. - */ -/*STATIC*/ -bool NimBLEDevice::deleteBond(const NimBLEAddress &address) { - ble_addr_t delAddr; - memcpy(&delAddr.val, address.getNative(),6); - delAddr.type = address.getType(); - - int rc = ble_gap_unpair(&delAddr); - if (rc != 0) { - return false; - } - - return true; -} - - -/** - * @brief Checks if a peer device is bonded. - * @param [in] address The address to check for bonding. - * @returns true if bonded. - */ -/*STATIC*/ -bool NimBLEDevice::isBonded(const NimBLEAddress &address) { - ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; - int num_peers, rc; - - rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS)); - if (rc != 0) { - return false; - } - - for (int i = 0; i < num_peers; i++) { - NimBLEAddress storedAddr(peer_id_addrs[i]); - if(storedAddr == address) { - return true; - } - } - - return false; -} - - -/** - * @brief Get the address of a bonded peer device by index. - * @param [in] index The index to retrieve the peer address of. - * @returns NimBLEAddress of the found bonded peer or nullptr if not found. - */ -/*STATIC*/ -NimBLEAddress NimBLEDevice::getBondedAddress(int index) { - ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; - int num_peers, rc; - - rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS)); - if (rc != 0) { - return nullptr; - } - - if (index > num_peers || index < 0) { - return nullptr; - } - - return NimBLEAddress(peer_id_addrs[index]); -} -#endif - -/** - * @brief Checks if a peer device is whitelisted. - * @param [in] address The address to check for in the whitelist. - * @returns true if the address is in the whitelist. - */ -/*STATIC*/ -bool NimBLEDevice::onWhiteList(const NimBLEAddress & address) { - for (auto &it : m_whiteList) { - if (it == address) { - return true; - } - } - - return false; -} - - -/** - * @brief Add a peer address to the whitelist. - * @param [in] address The address to add to the whitelist. - * @returns true if successful. - */ -/*STATIC*/ -bool NimBLEDevice::whiteListAdd(const NimBLEAddress & address) { - if (NimBLEDevice::onWhiteList(address)) { - return true; - } - - m_whiteList.push_back(address); - std::vector wlVec; - wlVec.reserve(m_whiteList.size()); - - for (auto &it : m_whiteList) { - ble_addr_t wlAddr; - memcpy(&wlAddr.val, it.getNative(), 6); - wlAddr.type = it.getType(); - wlVec.push_back(wlAddr); - } - - int rc = ble_gap_wl_set(&wlVec[0], wlVec.size()); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Failed adding to whitelist rc=%d", rc); - return false; - } - - return true; -} - - -/** - * @brief Remove a peer address from the whitelist. - * @param [in] address The address to remove from the whitelist. - * @returns true if successful. - */ -/*STATIC*/ -bool NimBLEDevice::whiteListRemove(const NimBLEAddress & address) { - if (!NimBLEDevice::onWhiteList(address)) { - return true; - } - - std::vector wlVec; - wlVec.reserve(m_whiteList.size()); - - for (auto &it : m_whiteList) { - if (it != address) { - ble_addr_t wlAddr; - memcpy(&wlAddr.val, it.getNative(), 6); - wlAddr.type = it.getType(); - wlVec.push_back(wlAddr); - } - } - - int rc = ble_gap_wl_set(&wlVec[0], wlVec.size()); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Failed removing from whitelist rc=%d", rc); - return false; - } - - // Don't remove from the list unless NimBLE returned success - for (auto it = m_whiteList.begin(); it < m_whiteList.end(); ++it) { - if ((*it) == address) { - m_whiteList.erase(it); - break; - } - } - - return true; -} - - -/** - * @brief Gets the count of addresses in the whitelist. - * @returns The number of addresses in the whitelist. - */ -/*STATIC*/ -size_t NimBLEDevice::getWhiteListCount() { - return m_whiteList.size(); -} - - -/** - * @brief Gets the address at the vector index. - * @param [in] index The vector index to retrieve the address from. - * @returns the NimBLEAddress at the whitelist index or nullptr if not found. - */ -/*STATIC*/ -NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) { - if (index > m_whiteList.size()) { - NIMBLE_LOGE(LOG_TAG, "Invalid index; %u", index); - return nullptr; - } - return m_whiteList[index]; -} - - -/** - * @brief Host reset, we pass the message so we don't make calls until resynced. - * @param [in] reason The reason code for the reset. - */ -/* STATIC */ -void NimBLEDevice::onReset(int reason) -{ - if(!m_synced) { - return; - } - - m_synced = false; - - NIMBLE_LOGC(LOG_TAG, "Resetting state; reason=%d, %s", reason, - NimBLEUtils::returnCodeToString(reason)); - -#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) - if(initialized) { - if(m_pScan != nullptr) { - m_pScan->onHostReset(); - } - } -#endif -} // onReset - - -/** - * @brief Host resynced with controller, all clear to make calls to the stack. - */ -/* STATIC */ -void NimBLEDevice::onSync(void) -{ - NIMBLE_LOGI(LOG_TAG, "NimBle host synced."); - // This check is needed due to potentially being called multiple times in succession - // If this happens, the call to scan start may get stuck or cause an advertising fault. - if(m_synced) { - return; - } - - /* Make sure we have proper identity address set (public preferred) */ - int rc = ble_hs_util_ensure_addr(0); - assert(rc == 0); - -#ifndef ESP_PLATFORM - rc = ble_hs_id_infer_auto(m_own_addr_type, &m_own_addr_type); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "error determining address type; rc=%d", rc); - return; - } -#endif - - // Yield for housekeeping before returning to operations. - // Occasionally triggers exception without. - taskYIELD(); - - m_synced = true; - - if(initialized) { -#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) - if(m_pScan != nullptr) { - m_pScan->onHostSync(); - } -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) - if(m_bleAdvertising != nullptr) { - m_bleAdvertising->onHostSync(); - } -#endif - } -} // onSync - - -/** - * @brief The main host task. - */ -/* STATIC */ -void NimBLEDevice::host_task(void *param) -{ - NIMBLE_LOGI(LOG_TAG, "BLE Host Task Started"); - - /* This function will return only when nimble_port_stop() is executed */ - nimble_port_run(); - - nimble_port_freertos_deinit(); -} // host_task - - -/** - * @brief Initialize the %BLE environment. - * @param [in] deviceName The device name of the device. - */ -/* STATIC */ -void NimBLEDevice::init(const std::string &deviceName) { - if(!initialized){ - int rc=0; -#ifdef ESP_PLATFORM - esp_err_t errRc = ESP_OK; - -#ifdef CONFIG_ENABLE_ARDUINO_DEPENDS - // make sure the linker includes esp32-hal-bt.c so Arduino init doesn't release BLE memory. - btStarted(); -#endif - - errRc = nvs_flash_init(); - - if (errRc == ESP_ERR_NVS_NO_FREE_PAGES || errRc == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_ERROR_CHECK(nvs_flash_erase()); - errRc = nvs_flash_init(); - } - - ESP_ERROR_CHECK(errRc); - - esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); - - esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); -#if defined (CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32S3) - bt_cfg.bluetooth_mode = ESP_BT_MODE_BLE; -#else - bt_cfg.mode = ESP_BT_MODE_BLE; - bt_cfg.ble_max_conn = CONFIG_BT_NIMBLE_MAX_CONNECTIONS; -#endif - bt_cfg.normal_adv_size = m_scanDuplicateSize; - bt_cfg.scan_duplicate_type = m_scanFilterMode; - - ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg)); - ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE)); - ESP_ERROR_CHECK(esp_nimble_hci_init()); -#endif - nimble_port_init(); - - // Setup callbacks for host events - ble_hs_cfg.reset_cb = NimBLEDevice::onReset; - ble_hs_cfg.sync_cb = NimBLEDevice::onSync; - - // Set initial security capabilities - ble_hs_cfg.sm_io_cap = BLE_HS_IO_NO_INPUT_OUTPUT; - ble_hs_cfg.sm_bonding = 0; - ble_hs_cfg.sm_mitm = 0; - ble_hs_cfg.sm_sc = 1; - ble_hs_cfg.sm_our_key_dist = 1; - ble_hs_cfg.sm_their_key_dist = 3; - - ble_hs_cfg.store_status_cb = ble_store_util_status_rr; /*TODO: Implement handler for this*/ - - // Set the device name. - rc = ble_svc_gap_device_name_set(deviceName.c_str()); - assert(rc == 0); - - ble_store_config_init(); - - nimble_port_freertos_init(NimBLEDevice::host_task); - } - - // Wait for host and controller to sync before returning and accepting new tasks - while(!m_synced){ - taskYIELD(); - } - - initialized = true; // Set the initialization flag to ensure we are only initialized once. -} // init - - -/** - * @brief Shutdown the NimBLE stack/controller. - * @param [in] clearAll If true, deletes all server/advertising/scan/client objects after deinitializing. - * @note If clearAll is true when called, any references to the created objects become invalid. - */ -/* STATIC */ -void NimBLEDevice::deinit(bool clearAll) { - int ret = nimble_port_stop(); - if (ret == 0) { - nimble_port_deinit(); -#ifdef ESP_PLATFORM - ret = esp_nimble_hci_and_controller_deinit(); - if (ret != ESP_OK) { - NIMBLE_LOGE(LOG_TAG, "esp_nimble_hci_and_controller_deinit() failed with error: %d", ret); - } -#endif - initialized = false; - m_synced = false; - - if(clearAll) { -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - if(NimBLEDevice::m_pServer != nullptr) { - delete NimBLEDevice::m_pServer; - NimBLEDevice::m_pServer = nullptr; - } -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) - if(NimBLEDevice::m_bleAdvertising != nullptr) { - delete NimBLEDevice::m_bleAdvertising; - NimBLEDevice::m_bleAdvertising = nullptr; - } -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) - if(NimBLEDevice::m_pScan != nullptr) { - delete NimBLEDevice::m_pScan; - NimBLEDevice::m_pScan= nullptr; - } -#endif - -#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL) - for(auto &it : m_cList) { - deleteClient(it); - m_cList.clear(); - } -#endif - - m_ignoreList.clear(); - - if(m_securityCallbacks != nullptr) { - delete m_securityCallbacks; - } - } - } -} // deinit - -/** - * @brief Set the BLEDevice's name - * @param [in] deviceName The device name of the device. - */ -/* STATIC */ -void NimBLEDevice::setDeviceName(const std::string &deviceName) { - ble_svc_gap_device_name_set(deviceName.c_str()); -} // setDeviceName - - -/** - * @brief Check if the initialization is complete. - * @return true if initialized. - */ -/*STATIC*/ -bool NimBLEDevice::getInitialized() { - return initialized; -} // getInitialized - - -/** - * @brief Set the authorization mode for this device. - * @param bonding If true we allow bonding, false no bonding will be performed. - * @param mitm If true we are capable of man in the middle protection, false if not. - * @param sc If true we will perform secure connection pairing, false we will use legacy pairing. - */ -/*STATIC*/ -void NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc) { - NIMBLE_LOGD(LOG_TAG, "Setting bonding: %d, mitm: %d, sc: %d",bonding,mitm,sc); - ble_hs_cfg.sm_bonding = bonding; - ble_hs_cfg.sm_mitm = mitm; - ble_hs_cfg.sm_sc = sc; -} // setSecurityAuth - - -/** - * @brief Set the authorization mode for this device. - * @param auth_req A bitmap indicating what modes are supported.\n - * The available bits are defined as: - * * 0x01 BLE_SM_PAIR_AUTHREQ_BOND - * * 0x04 BLE_SM_PAIR_AUTHREQ_MITM - * * 0x08 BLE_SM_PAIR_AUTHREQ_SC - * * 0x10 BLE_SM_PAIR_AUTHREQ_KEYPRESS - not yet supported. - */ -/*STATIC*/ -void NimBLEDevice::setSecurityAuth(uint8_t auth_req) { - NimBLEDevice::setSecurityAuth((auth_req & BLE_SM_PAIR_AUTHREQ_BOND)>0, - (auth_req & BLE_SM_PAIR_AUTHREQ_MITM)>0, - (auth_req & BLE_SM_PAIR_AUTHREQ_SC)>0); -} // setSecurityAuth - - -/** - * @brief Set the Input/Output capabilities of this device. - * @param iocap One of the following values: - * * 0x00 BLE_HS_IO_DISPLAY_ONLY DisplayOnly IO capability - * * 0x01 BLE_HS_IO_DISPLAY_YESNO DisplayYesNo IO capability - * * 0x02 BLE_HS_IO_KEYBOARD_ONLY KeyboardOnly IO capability - * * 0x03 BLE_HS_IO_NO_INPUT_OUTPUT NoInputNoOutput IO capability - * * 0x04 BLE_HS_IO_KEYBOARD_DISPLAY KeyboardDisplay Only IO capability - */ -/*STATIC*/ -void NimBLEDevice::setSecurityIOCap(uint8_t iocap) { - ble_hs_cfg.sm_io_cap = iocap; -} // setSecurityIOCap - - -/** - * @brief If we are the initiator of the security procedure this sets the keys we will distribute. - * @param init_key A bitmap indicating which keys to distribute during pairing.\n - * The available bits are defined as: - * * 0x01: BLE_SM_PAIR_KEY_DIST_ENC - Distribute the encryption key. - * * 0x02: BLE_SM_PAIR_KEY_DIST_ID - Distribute the ID key (IRK). - * * 0x04: BLE_SM_PAIR_KEY_DIST_SIGN - * * 0x08: BLE_SM_PAIR_KEY_DIST_LINK - */ -/*STATIC*/ -void NimBLEDevice::setSecurityInitKey(uint8_t init_key) { - ble_hs_cfg.sm_our_key_dist = init_key; -} // setsSecurityInitKey - - -/** - * @brief Set the keys we are willing to accept during pairing. - * @param resp_key A bitmap indicating which keys to accept during pairing. - * The available bits are defined as: - * * 0x01: BLE_SM_PAIR_KEY_DIST_ENC - Accept the encryption key. - * * 0x02: BLE_SM_PAIR_KEY_DIST_ID - Accept the ID key (IRK). - * * 0x04: BLE_SM_PAIR_KEY_DIST_SIGN - * * 0x08: BLE_SM_PAIR_KEY_DIST_LINK - */ -/*STATIC*/ -void NimBLEDevice::setSecurityRespKey(uint8_t resp_key) { - ble_hs_cfg.sm_their_key_dist = resp_key; -} // setsSecurityRespKey - - -/** - * @brief Set the passkey the server will ask for when pairing. - * @param [in] pin The passkey to use. - */ -/*STATIC*/ -void NimBLEDevice::setSecurityPasskey(uint32_t pin) { - m_passkey = pin; -} // setSecurityPasskey - - -/** - * @brief Get the current passkey used for pairing. - * @return The current passkey. - */ -/*STATIC*/ -uint32_t NimBLEDevice::getSecurityPasskey() { - return m_passkey; -} // getSecurityPasskey - - -/** - * @brief Set callbacks that will be used to handle encryption negotiation events and authentication events - * @param [in] callbacks Pointer to NimBLESecurityCallbacks class - * @deprecated For backward compatibility, New code should use client/server callback methods. - */ -/*STATIC*/ -void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) { - NimBLEDevice::m_securityCallbacks = callbacks; -} // setSecurityCallbacks - - -#ifdef ESP_PLATFORM -/** - * @brief Set the own address type. - * @param [in] own_addr_type Own Bluetooth Device address type.\n - * The available bits are defined as: - * * 0x00: BLE_OWN_ADDR_PUBLIC - * * 0x01: BLE_OWN_ADDR_RANDOM - * * 0x02: BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT - * * 0x03: BLE_OWN_ADDR_RPA_RANDOM_DEFAULT - * @param [in] useNRPA If true, and address type is random, uses a non-resolvable random address. - */ -/*STATIC*/ -void NimBLEDevice::setOwnAddrType(uint8_t own_addr_type, bool useNRPA) { - m_own_addr_type = own_addr_type; - switch (own_addr_type) { -#ifdef CONFIG_IDF_TARGET_ESP32 - case BLE_OWN_ADDR_PUBLIC: - ble_hs_pvcy_rpa_config(NIMBLE_HOST_DISABLE_PRIVACY); - break; -#endif - case BLE_OWN_ADDR_RANDOM: - setSecurityInitKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID); -#ifdef CONFIG_IDF_TARGET_ESP32 - ble_hs_pvcy_rpa_config(useNRPA ? NIMBLE_HOST_ENABLE_NRPA : NIMBLE_HOST_ENABLE_RPA); -#endif - break; - case BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT: - case BLE_OWN_ADDR_RPA_RANDOM_DEFAULT: - setSecurityInitKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID); -#ifdef CONFIG_IDF_TARGET_ESP32 - ble_hs_pvcy_rpa_config(NIMBLE_HOST_ENABLE_RPA); -#endif - break; - } -} // setOwnAddrType -#endif - -/** - * @brief Start the connection securing and authorization for this connection. - * @param conn_id The connection id of the peer device. - * @returns NimBLE stack return code, 0 = success. - */ -/* STATIC */ -int NimBLEDevice::startSecurity(uint16_t conn_id) { - int rc = ble_gap_security_initiate(conn_id); - if(rc != 0){ - NIMBLE_LOGE(LOG_TAG, "ble_gap_security_initiate: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); - } - - return rc; -} // startSecurity - - -/** - * @brief Check if the device address is on our ignore list. - * @param [in] address The address to look for. - * @return True if ignoring. - */ -/*STATIC*/ -bool NimBLEDevice::isIgnored(const NimBLEAddress &address) { - for(auto &it : m_ignoreList) { - if(it.equals(address)){ - return true; - } - } - - return false; -} - - -/** - * @brief Add a device to the ignore list. - * @param [in] address The address of the device we want to ignore. - */ -/*STATIC*/ -void NimBLEDevice::addIgnored(const NimBLEAddress &address) { - m_ignoreList.push_back(address); -} - - -/** - * @brief Remove a device from the ignore list. - * @param [in] address The address of the device we want to remove from the list. - */ -/*STATIC*/ -void NimBLEDevice::removeIgnored(const NimBLEAddress &address) { - for(auto it = m_ignoreList.begin(); it != m_ignoreList.end(); ++it) { - if((*it).equals(address)){ - m_ignoreList.erase(it); - return; - } - } -} - - -/** - * @brief Set a custom callback for gap events. - * @param [in] handler The function to call when gap events occur. - */ -/*STATIC*/ -void NimBLEDevice::setCustomGapHandler(gap_event_handler handler) { - m_customGapHandler = handler; - int rc = ble_gap_event_listener_register(&m_listener, m_customGapHandler, NULL); - if(rc == BLE_HS_EALREADY){ - NIMBLE_LOGI(LOG_TAG, "Already listening to GAP events."); - } - else{ - assert(rc == 0); - } -} // setCustomGapHandler - -#endif // CONFIG_BT_ENABLED diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.h deleted file mode 100644 index 8d4d849e4..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.h +++ /dev/null @@ -1,241 +0,0 @@ -/* - * NimBLEDevice.h - * - * Created: on Jan 24 2020 - * Author H2zero - * - * Originally: - * - * BLEDevice.h - * - * Created on: Mar 16, 2017 - * Author: kolban - */ - -#ifndef MAIN_NIMBLEDEVICE_H_ -#define MAIN_NIMBLEDEVICE_H_ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) -#include "NimBLEScan.h" -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) -# if CONFIG_BT_NIMBLE_EXT_ADV -# include "NimBLEExtAdvertising.h" -# else -# include "NimBLEAdvertising.h" -# endif -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) -#include "NimBLEClient.h" -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) -#include "NimBLEServer.h" -#endif - -#include "NimBLEUtils.h" -#include "NimBLESecurity.h" -#include "NimBLEAddress.h" - -#ifdef ESP_PLATFORM -# include "esp_bt.h" -#endif - -#include -#include -#include - -#define BLEDevice NimBLEDevice -#define BLEClient NimBLEClient -#define BLERemoteService NimBLERemoteService -#define BLERemoteCharacteristic NimBLERemoteCharacteristic -#define BLERemoteDescriptor NimBLERemoteDescriptor -#define BLEAdvertisedDevice NimBLEAdvertisedDevice -#define BLEScan NimBLEScan -#define BLEUUID NimBLEUUID -#define BLESecurity NimBLESecurity -#define BLESecurityCallbacks NimBLESecurityCallbacks -#define BLEAddress NimBLEAddress -#define BLEUtils NimBLEUtils -#define BLEClientCallbacks NimBLEClientCallbacks -#define BLEAdvertisedDeviceCallbacks NimBLEAdvertisedDeviceCallbacks -#define BLEScanResults NimBLEScanResults -#define BLEServer NimBLEServer -#define BLEService NimBLEService -#define BLECharacteristic NimBLECharacteristic -#define BLEAdvertising NimBLEAdvertising -#define BLEServerCallbacks NimBLEServerCallbacks -#define BLECharacteristicCallbacks NimBLECharacteristicCallbacks -#define BLEAdvertisementData NimBLEAdvertisementData -#define BLEDescriptor NimBLEDescriptor -#define BLE2902 NimBLE2902 -#define BLE2904 NimBLE2904 -#define BLEDescriptorCallbacks NimBLEDescriptorCallbacks -#define BLEBeacon NimBLEBeacon -#define BLEEddystoneTLM NimBLEEddystoneTLM -#define BLEEddystoneURL NimBLEEddystoneURL - -#ifdef CONFIG_BT_NIMBLE_MAX_CONNECTIONS -#define NIMBLE_MAX_CONNECTIONS CONFIG_BT_NIMBLE_MAX_CONNECTIONS -#else -#define NIMBLE_MAX_CONNECTIONS CONFIG_NIMBLE_MAX_CONNECTIONS -#endif - -typedef int (*gap_event_handler)(ble_gap_event *event, void *arg); - -extern "C" void ble_store_config_init(void); - -/** - * @brief A model of a %BLE Device from which all the BLE roles are created. - */ -class NimBLEDevice { -public: - static void init(const std::string &deviceName); - static void deinit(bool clearAll = false); - static void setDeviceName(const std::string &deviceName); - static bool getInitialized(); - static NimBLEAddress getAddress(); - static std::string toString(); - static bool whiteListAdd(const NimBLEAddress & address); - static bool whiteListRemove(const NimBLEAddress & address); - static bool onWhiteList(const NimBLEAddress & address); - static size_t getWhiteListCount(); - static NimBLEAddress getWhiteListAddress(size_t index); - -#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) - static NimBLEScan* getScan(); -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - static NimBLEServer* createServer(); - static NimBLEServer* getServer(); -#endif - -#ifdef ESP_PLATFORM - static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT); - static int getPower(esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT); - static void setOwnAddrType(uint8_t own_addr_type, bool useNRPA=false); - static void setScanDuplicateCacheSize(uint16_t cacheSize); - static void setScanFilterMode(uint8_t type); -#else - static void setPower(int dbm); - static int getPower(); -#endif - - static void setCustomGapHandler(gap_event_handler handler); - static void setSecurityAuth(bool bonding, bool mitm, bool sc); - static void setSecurityAuth(uint8_t auth_req); - static void setSecurityIOCap(uint8_t iocap); - static void setSecurityInitKey(uint8_t init_key); - static void setSecurityRespKey(uint8_t init_key); - static void setSecurityPasskey(uint32_t pin); - static uint32_t getSecurityPasskey(); - static void setSecurityCallbacks(NimBLESecurityCallbacks* pCallbacks); - static int startSecurity(uint16_t conn_id); - static int setMTU(uint16_t mtu); - static uint16_t getMTU(); - static bool isIgnored(const NimBLEAddress &address); - static void addIgnored(const NimBLEAddress &address); - static void removeIgnored(const NimBLEAddress &address); - -#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) -# if CONFIG_BT_NIMBLE_EXT_ADV - static NimBLEExtAdvertising* getAdvertising(); - static bool startAdvertising(uint8_t inst_id, - int duration = 0, - int max_events = 0); - static bool stopAdvertising(uint8_t inst_id); - static bool stopAdvertising(); -# endif -# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) - static NimBLEAdvertising* getAdvertising(); - static bool startAdvertising(); - static bool stopAdvertising(); -# endif -#endif - -#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL) - static NimBLEClient* createClient(NimBLEAddress peerAddress = NimBLEAddress("")); - static bool deleteClient(NimBLEClient* pClient); - static NimBLEClient* getClientByID(uint16_t conn_id); - static NimBLEClient* getClientByPeerAddress(const NimBLEAddress &peer_addr); - static NimBLEClient* getDisconnectedClient(); - static size_t getClientListSize(); - static std::list* getClientList(); -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - static bool deleteBond(const NimBLEAddress &address); - static int getNumBonds(); - static bool isBonded(const NimBLEAddress &address); - static void deleteAllBonds(); - static NimBLEAddress getBondedAddress(int index); -#endif - -private: -#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL) - friend class NimBLEClient; -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) - friend class NimBLEScan; -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - friend class NimBLEServer; - friend class NimBLECharacteristic; -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) - friend class NimBLEAdvertising; -# if CONFIG_BT_NIMBLE_EXT_ADV - friend class NimBLEExtAdvertising; - friend class NimBLEExtAdvertisement; -# endif -#endif - - static void onReset(int reason); - static void onSync(void); - static void host_task(void *param); - static bool m_synced; - -#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) - static NimBLEScan* m_pScan; -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - static NimBLEServer* m_pServer; -#endif - -#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) -# if CONFIG_BT_NIMBLE_EXT_ADV - static NimBLEExtAdvertising* m_bleAdvertising; -# else - static NimBLEAdvertising* m_bleAdvertising; -# endif -#endif - -#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL) - static std::list m_cList; -#endif - static std::list m_ignoreList; - static NimBLESecurityCallbacks* m_securityCallbacks; - static uint32_t m_passkey; - static ble_gap_event_listener m_listener; - static gap_event_handler m_customGapHandler; - static uint8_t m_own_addr_type; -#ifdef ESP_PLATFORM - static uint16_t m_scanDuplicateSize; - static uint8_t m_scanFilterMode; -#endif - static std::vector m_whiteList; -}; - - -#endif // CONFIG_BT_ENABLED -#endif // MAIN_NIMBLEDEVICE_H_ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEEddystoneTLM.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEEddystoneTLM.cpp deleted file mode 100644 index 7a9c5102c..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEEddystoneTLM.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * NimBLEEddystoneTLM.cpp - * - * Created: on March 15 2020 - * Author H2zero - * - * Originally: - * - * BLEEddystoneTLM.cpp - * - * Created on: Mar 12, 2018 - * Author: pcbreflux - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "NimBLEEddystoneTLM.h" -#include "NimBLELog.h" - -#include -#include - -#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8)) -#define ENDIAN_CHANGE_U32(x) ((((x)&0xFF000000)>>24) + (((x)&0x00FF0000)>>8)) + ((((x)&0xFF00)<<8) + (((x)&0xFF)<<24)) - -static const char LOG_TAG[] = "NimBLEEddystoneTLM"; - -/** - * @brief Construct a default EddystoneTLM beacon object. - */ -NimBLEEddystoneTLM::NimBLEEddystoneTLM() { - beaconUUID = 0xFEAA; - m_eddystoneData.frameType = EDDYSTONE_TLM_FRAME_TYPE; - m_eddystoneData.version = 0; - m_eddystoneData.volt = 3300; // 3300mV = 3.3V - m_eddystoneData.temp = (uint16_t) ((float) 23.00 * 256); // 8.8 fixed format - m_eddystoneData.advCount = 0; - m_eddystoneData.tmil = 0; -} // NimBLEEddystoneTLM - - -/** - * @brief Retrieve the data that is being advertised. - * @return The advertised data. - */ -std::string NimBLEEddystoneTLM::getData() { - return std::string((char*) &m_eddystoneData, sizeof(m_eddystoneData)); -} // getData - - -/** - * @brief Get the UUID being advertised. - * @return The UUID advertised. - */ -NimBLEUUID NimBLEEddystoneTLM::getUUID() { - return NimBLEUUID(beaconUUID); -} // getUUID - - -/** - * @brief Get the version being advertised. - * @return The version number. - */ -uint8_t NimBLEEddystoneTLM::getVersion() { - return m_eddystoneData.version; -} // getVersion - - -/** - * @brief Get the battery voltage. - * @return The battery voltage. - */ -uint16_t NimBLEEddystoneTLM::getVolt() { - return ENDIAN_CHANGE_U16(m_eddystoneData.volt); -} // getVolt - - -/** - * @brief Get the temperature being advertised. - * @return The temperature value. - */ -float NimBLEEddystoneTLM::getTemp() { - return ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f; -} // getTemp - -/** - * @brief Get the count of advertisements sent. - * @return The number of advertisements. - */ -uint32_t NimBLEEddystoneTLM::getCount() { - return ENDIAN_CHANGE_U32(m_eddystoneData.advCount); -} // getCount - - -/** - * @brief Get the advertisement time. - * @return The advertisement time. - */ -uint32_t NimBLEEddystoneTLM::getTime() { - return (ENDIAN_CHANGE_U32(m_eddystoneData.tmil)) / 10; -} // getTime - - -/** - * @brief Get a string representation of the beacon. - * @return The string representation. - */ -std::string NimBLEEddystoneTLM::toString() { - std::string out = ""; - uint32_t rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil); - char val[12]; - - out += "Version "; // + std::string(m_eddystoneData.version); - snprintf(val, sizeof(val), "%d", m_eddystoneData.version); - out += val; - out += "\n"; - out += "Battery Voltage "; // + ENDIAN_CHANGE_U16(m_eddystoneData.volt); - snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U16(m_eddystoneData.volt)); - out += val; - out += " mV\n"; - - out += "Temperature "; - snprintf(val, sizeof(val), "%.2f", ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f); - out += val; - out += " C\n"; - - out += "Adv. Count "; - snprintf(val, sizeof(val), "%" PRIu32, ENDIAN_CHANGE_U32(m_eddystoneData.advCount)); - out += val; - out += "\n"; - - out += "Time in seconds "; - snprintf(val, sizeof(val), "%" PRIu32, rawsec/10); - out += val; - out += "\n"; - - out += "Time "; - - snprintf(val, sizeof(val), "%04" PRIu32, rawsec / 864000); - out += val; - out += "."; - - snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 36000) % 24); - out += val; - out += ":"; - - snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 600) % 60); - out += val; - out += ":"; - - snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 10) % 60); - out += val; - out += "\n"; - - return out; -} // toString - - -/** - * @brief Set the raw data for the beacon advertisement. - * @param [in] data The raw data to advertise. - */ -void NimBLEEddystoneTLM::setData(const std::string &data) { - if (data.length() != sizeof(m_eddystoneData)) { - NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d", - data.length(), sizeof(m_eddystoneData)); - return; - } - memcpy(&m_eddystoneData, data.data(), data.length()); -} // setData - - -/** - * @brief Set the UUID to advertise. - * @param [in] l_uuid The UUID. - */ -void NimBLEEddystoneTLM::setUUID(const NimBLEUUID &l_uuid) { - beaconUUID = l_uuid.getNative()->u16.value; -} // setUUID - - -/** - * @brief Set the version to advertise. - * @param [in] version The version number. - */ -void NimBLEEddystoneTLM::setVersion(uint8_t version) { - m_eddystoneData.version = version; -} // setVersion - - -/** - * @brief Set the battery voltage to advertise. - * @param [in] volt The voltage in millivolts. - */ -void NimBLEEddystoneTLM::setVolt(uint16_t volt) { - m_eddystoneData.volt = volt; -} // setVolt - - -/** - * @brief Set the temperature to advertise. - * @param [in] temp The temperature value. - */ -void NimBLEEddystoneTLM::setTemp(float temp) { - m_eddystoneData.temp = (uint16_t)temp; -} // setTemp - - -/** - * @brief Set the advertisement count. - * @param [in] advCount The advertisement number. - */ -void NimBLEEddystoneTLM::setCount(uint32_t advCount) { - m_eddystoneData.advCount = advCount; -} // setCount - - -/** - * @brief Set the advertisement time. - * @param [in] tmil The advertisement time in milliseconds. - */ -void NimBLEEddystoneTLM::setTime(uint32_t tmil) { - m_eddystoneData.tmil = tmil; -} // setTime - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEEddystoneTLM.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEEddystoneTLM.h deleted file mode 100644 index 265c81b45..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEEddystoneTLM.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * NimBLEEddystoneTLM.h - * - * Created: on March 15 2020 - * Author H2zero - * - * Originally: - * - * BLEEddystoneTLM.h - * - * Created on: Mar 12, 2018 - * Author: pcbreflux - */ - -#ifndef _NimBLEEddystoneTLM_H_ -#define _NimBLEEddystoneTLM_H_ - -#include "NimBLEUUID.h" - -#include - -#define EDDYSTONE_TLM_FRAME_TYPE 0x20 - -/** - * @brief Representation of a beacon. - * See: - * * https://github.com/google/eddystone - */ -class NimBLEEddystoneTLM { -public: - NimBLEEddystoneTLM(); - std::string getData(); - NimBLEUUID getUUID(); - uint8_t getVersion(); - uint16_t getVolt(); - float getTemp(); - uint32_t getCount(); - uint32_t getTime(); - std::string toString(); - void setData(const std::string &data); - void setUUID(const NimBLEUUID &l_uuid); - void setVersion(uint8_t version); - void setVolt(uint16_t volt); - void setTemp(float temp); - void setCount(uint32_t advCount); - void setTime(uint32_t tmil); - -private: - uint16_t beaconUUID; - struct { - uint8_t frameType; - uint8_t version; - uint16_t volt; - uint16_t temp; - uint32_t advCount; - uint32_t tmil; - } __attribute__((packed)) m_eddystoneData; - -}; // NimBLEEddystoneTLM - -#endif /* _NimBLEEddystoneTLM_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEEddystoneURL.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEEddystoneURL.cpp deleted file mode 100644 index 73829d79e..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEEddystoneURL.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * NimBLEEddystoneURL.cpp - * - * Created: on March 15 2020 - * Author H2zero - * - * Originally: - * - * BLEEddystoneURL.cpp - * - * Created on: Mar 12, 2018 - * Author: pcbreflux - */ -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "NimBLEEddystoneURL.h" -#include "NimBLELog.h" - -#include - -static const char LOG_TAG[] = "NimBLEEddystoneURL"; - - -/** - * @brief Construct a default EddystoneURL beacon object. - */ -NimBLEEddystoneURL::NimBLEEddystoneURL() { - beaconUUID = 0xFEAA; - lengthURL = 0; - m_eddystoneData.frameType = EDDYSTONE_URL_FRAME_TYPE; - m_eddystoneData.advertisedTxPower = 0; - memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url)); -} // BLEEddystoneURL - - -/** - * @brief Retrieve the data that is being advertised. - * @return The advertised data. - */ -std::string NimBLEEddystoneURL::getData() { - return std::string((char*) &m_eddystoneData, sizeof(m_eddystoneData)); -} // getData - - -/** - * @brief Get the UUID being advertised. - * @return The UUID advertised. - */ -NimBLEUUID NimBLEEddystoneURL::getUUID() { - return NimBLEUUID(beaconUUID); -} // getUUID - - -/** - * @brief Get the transmit power being advertised. - * @return The transmit power. - */ -int8_t NimBLEEddystoneURL::getPower() { - return m_eddystoneData.advertisedTxPower; -} // getPower - - -/** - * @brief Get the raw URL being advertised. - * @return The raw URL. - */ -std::string NimBLEEddystoneURL::getURL() { - return std::string((char*) &m_eddystoneData.url, sizeof(m_eddystoneData.url)); -} // getURL - - -/** - * @brief Get the full URL being advertised. - * @return The full URL. - */ -std::string NimBLEEddystoneURL::getDecodedURL() { - std::string decodedURL = ""; - - switch (m_eddystoneData.url[0]) { - case 0x00: - decodedURL += "http://www."; - break; - case 0x01: - decodedURL += "https://www."; - break; - case 0x02: - decodedURL += "http://"; - break; - case 0x03: - decodedURL += "https://"; - break; - default: - decodedURL += m_eddystoneData.url[0]; - } - - for (int i = 1; i < lengthURL; i++) { - if (m_eddystoneData.url[i] > 33 && m_eddystoneData.url[i] < 127) { - decodedURL += m_eddystoneData.url[i]; - } else { - switch (m_eddystoneData.url[i]) { - case 0x00: - decodedURL += ".com/"; - break; - case 0x01: - decodedURL += ".org/"; - break; - case 0x02: - decodedURL += ".edu/"; - break; - case 0x03: - decodedURL += ".net/"; - break; - case 0x04: - decodedURL += ".info/"; - break; - case 0x05: - decodedURL += ".biz/"; - break; - case 0x06: - decodedURL += ".gov/"; - break; - case 0x07: - decodedURL += ".com"; - break; - case 0x08: - decodedURL += ".org"; - break; - case 0x09: - decodedURL += ".edu"; - break; - case 0x0A: - decodedURL += ".net"; - break; - case 0x0B: - decodedURL += ".info"; - break; - case 0x0C: - decodedURL += ".biz"; - break; - case 0x0D: - decodedURL += ".gov"; - break; - default: - break; - } - } - } - return decodedURL; -} // getDecodedURL - - - -/** - * @brief Set the raw data for the beacon advertisement. - * @param [in] data The raw data to advertise. - */ -void NimBLEEddystoneURL::setData(const std::string &data) { - if (data.length() > sizeof(m_eddystoneData)) { - NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and max expected %d", - data.length(), sizeof(m_eddystoneData)); - return; - } - memset(&m_eddystoneData, 0, sizeof(m_eddystoneData)); - memcpy(&m_eddystoneData, data.data(), data.length()); - lengthURL = data.length() - (sizeof(m_eddystoneData) - sizeof(m_eddystoneData.url)); -} // setData - - -/** - * @brief Set the UUID to advertise. - * @param [in] l_uuid The UUID. - */ -void NimBLEEddystoneURL::setUUID(const NimBLEUUID &l_uuid) { - beaconUUID = l_uuid.getNative()->u16.value; -} // setUUID - - -/** - * @brief Set the transmit power to advertise. - * @param [in] advertisedTxPower The transmit power level. - */ -void NimBLEEddystoneURL::setPower(int8_t advertisedTxPower) { - m_eddystoneData.advertisedTxPower = advertisedTxPower; -} // setPower - - -/** - * @brief Set the URL to advertise. - * @param [in] url The URL. - */ -void NimBLEEddystoneURL::setURL(const std::string &url) { - if (url.length() > sizeof(m_eddystoneData.url)) { - NIMBLE_LOGE(LOG_TAG, "Unable to set the url ... length passed in was %d and max expected %d", - url.length(), sizeof(m_eddystoneData.url)); - return; - } - memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url)); - memcpy(m_eddystoneData.url, url.data(), url.length()); - lengthURL = url.length(); -} // setURL - - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEEddystoneURL.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEEddystoneURL.h deleted file mode 100644 index 9c5f37f80..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEEddystoneURL.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * NimBLEEddystoneURL.h - * - * Created: on March 15 2020 - * Author H2zero - * - * Originally: - * - * BLEEddystoneURL.h - * - * Created on: Mar 12, 2018 - * Author: pcbreflux - */ - -#ifndef _NIMBLEEddystoneURL_H_ -#define _NIMBLEEddystoneURL_H_ -#include "NimBLEUUID.h" - -#include - -#define EDDYSTONE_URL_FRAME_TYPE 0x10 - -/** - * @brief Representation of a beacon. - * See: - * * https://github.com/google/eddystone - */ -class NimBLEEddystoneURL { -public: - NimBLEEddystoneURL(); - std::string getData(); - NimBLEUUID getUUID(); - int8_t getPower(); - std::string getURL(); - std::string getDecodedURL(); - void setData(const std::string &data); - void setUUID(const NimBLEUUID &l_uuid); - void setPower(int8_t advertisedTxPower); - void setURL(const std::string &url); - -private: - uint16_t beaconUUID; - uint8_t lengthURL; - struct { - uint8_t frameType; - int8_t advertisedTxPower; - uint8_t url[16]; - } __attribute__((packed)) m_eddystoneData; - -}; // NIMBLEEddystoneURL - -#endif /* _NIMBLEEddystoneURL_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEExtAdvertising.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEExtAdvertising.cpp deleted file mode 100644 index b979c9fd0..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEExtAdvertising.cpp +++ /dev/null @@ -1,870 +0,0 @@ -/* - * NimBLEExtAdvertising.cpp - * - * Created: on February 6, 2022 - * Author H2zero - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && \ - defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && \ - CONFIG_BT_NIMBLE_EXT_ADV - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "services/gap/ble_svc_gap.h" -#else -#include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h" -#endif -#include "NimBLEExtAdvertising.h" -#include "NimBLEDevice.h" -#include "NimBLEServer.h" -#include "NimBLEUtils.h" -#include "NimBLELog.h" - -static NimBLEExtAdvertisingCallbacks defaultCallbacks; -static const char* LOG_TAG = "NimBLEExtAdvertising"; - - -/** - * @brief Destructor: deletes callback instances if requested. - */ -NimBLEExtAdvertising::~NimBLEExtAdvertising() { - if(m_deleteCallbacks && m_pCallbacks != &defaultCallbacks) { - delete m_pCallbacks; - } -} - - -/** - * @brief Register the extended advertisement data. - * @param [in] inst_id The extended advertisement instance ID to assign to this data. - * @param [in] adv The extended advertisement instance with the data to set. - * @return True if advertising started successfully. - */ -bool NimBLEExtAdvertising::setInstanceData(uint8_t inst_id, NimBLEExtAdvertisement& adv) { - adv.m_params.sid = inst_id; - - // Legacy advertising as connectable requires the scannable flag also. - if (adv.m_params.legacy_pdu && adv.m_params.connectable) { - adv.m_params.scannable = true; - } - - // If connectable or not scannable disable the callback for scan response requests - if (adv.m_params.connectable || !adv.m_params.scannable) { - adv.m_params.scan_req_notif = false; - } - -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - NimBLEServer* pServer = NimBLEDevice::getServer(); - if (pServer != nullptr) { - if (!pServer->m_gattsStarted) { - pServer->start(); - } - } - - int rc = ble_gap_ext_adv_configure(inst_id, - &adv.m_params, - NULL, - (pServer != nullptr) ? NimBLEServer::handleGapEvent : - NimBLEExtAdvertising::handleGapEvent, - NULL); -#else - int rc = ble_gap_ext_adv_configure(inst_id, - &data.m_params, - NULL, - NimBLEExtAdvertising::handleGapEvent, - NULL); -#endif - - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Advertising config error: rc = %d", rc); - } else { - os_mbuf *buf; - buf = os_msys_get_pkthdr(adv.m_payload.size(), 0); - if (!buf) { - NIMBLE_LOGE(LOG_TAG, "Data buffer allocation failed"); - return false; - } - - rc = os_mbuf_append(buf, &adv.m_payload[0], adv.m_payload.size()); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Unable to copy data: rc = %d", rc); - return false; - } else { - if (adv.m_params.scannable && !adv.m_params.legacy_pdu) { - rc = ble_gap_ext_adv_rsp_set_data(inst_id, buf); - } else { - rc = ble_gap_ext_adv_set_data(inst_id, buf); - } - - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Invalid advertisement data: rc = %d", rc); - } else { - if (adv.m_advAddress != NimBLEAddress("")) { - ble_addr_t addr; - memcpy(&addr.val, adv.m_advAddress.getNative(), 6); - // Custom advertising address must be random. - addr.type = BLE_OWN_ADDR_RANDOM; - rc = ble_gap_ext_adv_set_addr(inst_id, &addr); - } - - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Error setting advertisement address: rc = %d", rc); - return false; - } - } - } - } - - return (rc == 0); -} - - -/** - * @brief Set the scan response data for a legacy advertisement. - * @param [in] inst_id The extended advertisement instance ID to assign to this data. - * @param [in] lsr A reference to a NimBLEExtAdvertisement that contains the data. - */ -bool NimBLEExtAdvertising::setScanResponseData(uint8_t inst_id, NimBLEExtAdvertisement & lsr) { - os_mbuf *buf = os_msys_get_pkthdr(lsr.m_payload.size(), 0); - if (!buf) { - NIMBLE_LOGE(LOG_TAG, "Data buffer allocation failed"); - return false; - } - - int rc = os_mbuf_append(buf, &lsr.m_payload[0], lsr.m_payload.size()); - - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Unable to copy scan data: rc = %d", rc); - return false; - } else { - rc = ble_gap_ext_adv_rsp_set_data(inst_id, buf); - } - return (rc == 0); -} - - -/** - * @brief Start extended advertising. - * @param [in] inst_id The extended advertisement instance ID to start. - * @param [in] duration How long to advertise for in milliseconds, 0 = forever (default). - * @param [in] max_events Maximum number of advertisement events to send, 0 = no limit (default). - * @return True if advertising started successfully. - */ -bool NimBLEExtAdvertising::start(uint8_t inst_id, int duration, int max_events) { - NIMBLE_LOGD(LOG_TAG, ">> Extended Advertising start"); - - // If Host is not synced we cannot start advertising. - if(!NimBLEDevice::m_synced) { - NIMBLE_LOGE(LOG_TAG, "Host reset, wait for sync."); - return false; - } - - int rc = ble_gap_ext_adv_start(inst_id, duration / 10, max_events); - - switch (rc) { - case 0: - m_advStatus[inst_id] = true; - break; - - case BLE_HS_EINVAL: - NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Value Error"); - break; - - case BLE_HS_EALREADY: - NIMBLE_LOGI(LOG_TAG, "Advertisement Already active"); - break; - - case BLE_HS_ETIMEOUT_HCI: - case BLE_HS_EOS: - case BLE_HS_ECONTROLLER: - case BLE_HS_ENOTSYNCED: - NIMBLE_LOGE(LOG_TAG, "Unable to advertise - Host Reset"); - break; - - default: - NIMBLE_LOGE(LOG_TAG, "Error enabling advertising; rc=%d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); - break; - } - - NIMBLE_LOGD(LOG_TAG, "<< Extended Advertising start"); - return (rc == 0 || rc == BLE_HS_EALREADY); -} // start - - -/** - * @brief Stop and remove this instance data from the advertisement set. - * @param [in] inst_id The extended advertisement instance to stop advertising. - * @return True if successful. - */ -bool NimBLEExtAdvertising::removeInstance(uint8_t inst_id) { - if (stop(inst_id)) { - int rc = ble_gap_ext_adv_remove(inst_id); - if (rc != 0 && rc != BLE_HS_EALREADY) { - NIMBLE_LOGE(LOG_TAG, "ble_gap_ext_adv_remove rc = %d %s", - rc, NimBLEUtils::returnCodeToString(rc)); - return false; - } - return true; - } - - return false; -} // removeInstance - - -/** - * @brief Stop and remove all advertising instance data. - * @return True if successful. - */ -bool NimBLEExtAdvertising::removeAll() { - if (stop()) { - int rc = ble_gap_ext_adv_clear(); - if (rc == 0 || rc == BLE_HS_EALREADY) { - return true; - } else { - NIMBLE_LOGE(LOG_TAG, "ble_gap_ext_adv_clear rc = %d %s", - rc, NimBLEUtils::returnCodeToString(rc)); - } - } - - return false; -} // removeAll - - -/** - * @brief Stop advertising this instance data. - * @param [in] inst_id The extended advertisement instance to stop advertising. - * @return True if successful. - */ -bool NimBLEExtAdvertising::stop(uint8_t inst_id) { - int rc = ble_gap_ext_adv_stop(inst_id); - if (rc != 0 && rc != BLE_HS_EALREADY) { - NIMBLE_LOGE(LOG_TAG, "ble_gap_ext_adv_stop rc = %d %s", - rc, NimBLEUtils::returnCodeToString(rc)); - return false; - } - - m_advStatus[inst_id] = false; - return true; -} // stop - - -/** - * @brief Stop all advertisements. - * @return True if successful. - */ -bool NimBLEExtAdvertising::stop() { - int rc = ble_gap_ext_adv_clear(); - if (rc != 0 && rc != BLE_HS_EALREADY) { - NIMBLE_LOGE(LOG_TAG, "ble_gap_ext_adv_stop rc = %d %s", - rc, NimBLEUtils::returnCodeToString(rc)); - return false; - } - - for(auto it : m_advStatus) { - it = false; - } - - return true; -} // stop - - -/** - * @brief Set a callback to call when the advertisement stops. - * @param [in] pCallbacks A pointer to a callback to be invoked when an advertisement stops. - * @param [in] deleteCallbacks if true callback class will be deleted when advertising is destructed. - */ -void NimBLEExtAdvertising::setCallbacks(NimBLEExtAdvertisingCallbacks* pCallbacks, - bool deleteCallbacks) { - if (pCallbacks != nullptr){ - m_pCallbacks = pCallbacks; - m_deleteCallbacks = deleteCallbacks; - } else { - m_pCallbacks = &defaultCallbacks; - } -} // setCallbacks - - -/** - * @brief Check if currently advertising. - * @param [in] inst_id The instance ID of the advertised data to get the status of. - * @return True if advertising is active. - */ -bool NimBLEExtAdvertising::isActive(uint8_t inst_id) { - return m_advStatus[inst_id]; -} // isAdvertising - - -/** - * @brief Check if any instances are currently advertising. - * @return True if any instance is active. - */ -bool NimBLEExtAdvertising::isAdvertising() { - for (auto it : m_advStatus) { - if (it) { - return true; - } - } - return false; -} // isAdvertising - - -/* - * Host reset seems to clear advertising data, - * we need clear the flag so it reloads it. - */ -void NimBLEExtAdvertising::onHostSync() { - NIMBLE_LOGD(LOG_TAG, "Host re-synced"); - for(auto it : m_advStatus) { - it = false; - } -} // onHostSync - - -/** - * @brief Handler for gap events when not using peripheral role. - * @param [in] event the event data. - * @param [in] arg pointer to the advertising instance. - */ -/*STATIC*/ -int NimBLEExtAdvertising::handleGapEvent(struct ble_gap_event *event, void *arg) { - (void)arg; - NimBLEExtAdvertising* pAdv = NimBLEDevice::getAdvertising(); - - switch (event->type) { - case BLE_GAP_EVENT_ADV_COMPLETE: { - switch (event->adv_complete.reason) { - // Don't call the callback if host reset, we want to - // preserve the active flag until re-sync to restart advertising. - case BLE_HS_ETIMEOUT_HCI: - case BLE_HS_EOS: - case BLE_HS_ECONTROLLER: - case BLE_HS_ENOTSYNCED: - NIMBLE_LOGC(LOG_TAG, "host reset, rc = %d", event->adv_complete.reason); - NimBLEDevice::onReset(event->adv_complete.reason); - return 0; - default: - break; - } - pAdv->m_advStatus[event->adv_complete.instance] = false; - pAdv->m_pCallbacks->onStopped(pAdv, event->adv_complete.reason, - event->adv_complete.instance); - break; - } - - case BLE_GAP_EVENT_SCAN_REQ_RCVD: { - pAdv->m_pCallbacks->onScanRequest(pAdv, event->scan_req_rcvd.instance, - NimBLEAddress(event->scan_req_rcvd.scan_addr)); - break; - } - } - - return 0; -} // handleGapEvent - - -/** Default callback handlers */ -void NimBLEExtAdvertisingCallbacks::onStopped(NimBLEExtAdvertising *pAdv, - int reason, uint8_t inst_id) { - NIMBLE_LOGD("NimBLEExtAdvertisingCallbacks", "onStopped: Default"); -} // onStopped - - -void NimBLEExtAdvertisingCallbacks::onScanRequest(NimBLEExtAdvertising *pAdv, - uint8_t inst_id, NimBLEAddress addr) { - NIMBLE_LOGD("NimBLEExtAdvertisingCallbacks", "onScanRequest: Default"); -} // onScanRequest - - -/** - * @brief Construct a BLE extended advertisement. - * @param [in] priPhy The primary Phy to advertise on, can be one of: - * * BLE_HCI_LE_PHY_1M - * * BLE_HCI_LE_PHY_CODED - * @param [in] secPhy The secondary Phy to advertise on, can be one of: - * * BLE_HCI_LE_PHY_1M - * * BLE_HCI_LE_PHY_2M - * * BLE_HCI_LE_PHY_CODED - */ -NimBLEExtAdvertisement::NimBLEExtAdvertisement(uint8_t priPhy, uint8_t secPhy) -: m_advAddress("") -{ - memset (&m_params, 0, sizeof(m_params)); - m_params.own_addr_type = NimBLEDevice::m_own_addr_type; - m_params.primary_phy = priPhy; - m_params.secondary_phy = secPhy; - m_params.tx_power = 127; -} // NimBLEExtAdvertisement - - -/** - * @brief Sets wether the advertisement should use legacy (BLE 4.0, 31 bytes max) advertising. - * @param [in] val true = using legacy advertising. - */ -void NimBLEExtAdvertisement::setLegacyAdvertising(bool val) { - m_params.legacy_pdu = val; -} // setLegacyAdvertising - - -/** - * @brief Sets wether the advertisement has scan response data available. - * @param [in] val true = scan response is available. - */ -void NimBLEExtAdvertisement::setScannable(bool val) { - m_params.scannable = val; -} // setScannable - - - -/** - * @brief Sets the transmission power level for this advertisement. - * @param [in] dbm the transmission power to use in dbm. - * @details The allowable value range depends on device hardware. \n - * The ESP32C3 and ESP32S3 have a range of -27 to +18. - */ -void NimBLEExtAdvertisement::setTxPower(int8_t dbm) { - m_params.tx_power = dbm; -} - - -/** - * @brief Sets wether this advertisement should advertise as a connectable device. - * @param [in] val True = connectable. - */ -void NimBLEExtAdvertisement::setConnectable(bool val) { -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - m_params.connectable = val; -#endif -} // setConnectable - - -/** - * @brief Set the address to use for this advertisement. - * @param [in] addr The address to use. - */ -void NimBLEExtAdvertisement::setAddress(const NimBLEAddress & addr) { - m_advAddress = addr; - // Must use random address type. - m_params.own_addr_type = BLE_OWN_ADDR_RANDOM; -} - - -/** - * @brief Sets The primary channels to advertise on. - * @param [in] ch37 Advertise on channel 37. - * @param [in] ch38 Advertise on channel 38. - * @param [in] ch39 Advertise on channel 39. - * @details This will set a bitmask using the input parameters to allow different \n - * combinations. If all inputs are false then all 3 channels will be used. - */ -void NimBLEExtAdvertisement::setPrimaryChannels(bool ch37, bool ch38, bool ch39) { - m_params.channel_map = (ch37 | (ch38 << 1) | (ch39 << 2)); -} // setPrimaryChannels - - -/** - * @brief Set the filtering for the scan filter. - * @param [in] scanRequestWhitelistOnly If true, only allow scan requests from those on the white list. - * @param [in] connectWhitelistOnly If true, only allow connections from those on the white list. - */ -void NimBLEExtAdvertisement::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) { - if (!scanRequestWhitelistOnly && !connectWhitelistOnly) { - m_params.filter_policy = BLE_HCI_ADV_FILT_NONE; - return; - } - if (scanRequestWhitelistOnly && !connectWhitelistOnly) { - m_params.filter_policy = BLE_HCI_ADV_FILT_SCAN; - return; - } - if (!scanRequestWhitelistOnly && connectWhitelistOnly) { - m_params.filter_policy = BLE_HCI_ADV_FILT_CONN; - return; - } - if (scanRequestWhitelistOnly && connectWhitelistOnly) { - m_params.filter_policy = BLE_HCI_ADV_FILT_BOTH; - return; - } -} // setScanFilter - - -/** - * @brief Sets the peer to directly advertise to. - * @param [in] addr The address of the peer to direct the advertisements. - */ -void NimBLEExtAdvertisement::setDirectedPeer(const NimBLEAddress & addr) { - ble_addr_t peerAddr; - memcpy(&peerAddr.val, addr.getNative(), 6); - peerAddr.type = addr.getType(); - m_params.peer = peerAddr; -} // setDirectedPeer - - -/** - * @brief Enable or disable direct advertisements to the peer set with `NimBLEExtAdvertisement::setDirectedPeer` - * @param [in] val true = send directed advertisements to peer. - * @param [in] high_duty true = use fast advertising rate, default - true. - */ -void NimBLEExtAdvertisement::setDirected(bool val, bool high_duty) { - m_params.directed = val; - m_params.high_duty_directed = high_duty; -} // setDirected - - -/** - * @brief Set the minimum advertising interval. - * @param [in] mininterval Minimum value for advertising interval in 0.625ms units, 0 = use default. - */ -void NimBLEExtAdvertisement::setMinInterval(uint32_t mininterval) { - m_params.itvl_min = mininterval; -} // setMinInterval - - -/** - * @brief Set the maximum advertising interval. - * @param [in] maxinterval Maximum value for advertising interval in 0.625ms units, 0 = use default. - */ -void NimBLEExtAdvertisement::setMaxInterval(uint32_t maxinterval) { - m_params.itvl_max = maxinterval; -} // setMaxInterval - - -/** - * @brief Set the primary advertising PHY to use - * @param [in] phy Can be one of following constants: - * * BLE_HCI_LE_PHY_1M - * * BLE_HCI_LE_PHY_CODED - */ -void NimBLEExtAdvertisement::setPrimaryPhy(uint8_t phy) { - m_params.primary_phy = phy; -} // setPrimaryPhy - - -/** - * @brief Set the secondary advertising PHY to use - * @param [in] phy Can be one of following constants: - * * BLE_HCI_LE_PHY_1M - * * BLE_HCI_LE_PHY_2M - * * BLE_HCI_LE_PHY_CODED - */ -void NimBLEExtAdvertisement::setSecondaryPhy(uint8_t phy) { - m_params.secondary_phy = phy; -} // setSecondaryPhy - - -/** - * @brief Sets whether the advertisement should be anonymous. - * @param [in] val Set to true to enable anonymous advertising. - * - * @details Anonymous advertising omits the device's address from the advertisement. - */ -void NimBLEExtAdvertisement::setAnonymous(bool val) { - m_params.anonymous = val; -} // setAnonymous - - -/** - * @brief Sets whether the scan response request callback should be called. - * @param [in] enable If true the scan response request callback will be called for this advertisement. - */ -void NimBLEExtAdvertisement::enableScanRequestCallback(bool enable) { - m_params.scan_req_notif = enable; -} // enableScanRequestCallback - - -/** - * @brief Clears the data stored in this instance, does not change settings. - * @details This will clear all data but preserves advertising parameter settings. - */ -void NimBLEExtAdvertisement::clearData() { - std::vector swap; - std::swap(m_payload, swap); -} - - -/** - * @brief Get the size of the current data. - */ -size_t NimBLEExtAdvertisement::getDataSize() { - return m_payload.size(); -} // getDataSize - - -/** - * @brief Set the advertisement data. - * @param [in] data The data to be set as the payload. - * @param [in] length The size of data. - * @details This will completely replace any data that was previously set. - */ -void NimBLEExtAdvertisement::setData(const uint8_t * data, size_t length) { - m_payload.assign(data, data + length); -} // setData - - -/** - * @brief Add data to the payload to be advertised. - * @param [in] data The data to be added to the payload. - */ -void NimBLEExtAdvertisement::addData(const std::string &data) { - addData((uint8_t*)data.data(), data.length()); -} // addData - - -/** - * @brief Add data to the payload to be advertised. - * @param [in] data The data to be added to the payload. - * @param [in] length The size of data to be added to the payload. - */ -void NimBLEExtAdvertisement::addData(const uint8_t * data, size_t length) { - m_payload.insert(m_payload.end(), data, data + length); -} // addData - - -/** - * @brief Set the appearance. - * @param [in] appearance The appearance code value. - * - * See also: - * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml - */ -void NimBLEExtAdvertisement::setAppearance(uint16_t appearance) { - char cdata[2]; - cdata[0] = 3; - cdata[1] = BLE_HS_ADV_TYPE_APPEARANCE; // 0x19 - addData(std::string(cdata, 2) + std::string((char*) &appearance, 2)); -} // setAppearance - - -/** - * @brief Set the advertisement flags. - * @param [in] flag The flags to be set in the advertisement. - * * BLE_HS_ADV_F_DISC_LTD - * * BLE_HS_ADV_F_DISC_GEN - * * BLE_HS_ADV_F_BREDR_UNSUP - must always use with NimBLE - */ -void NimBLEExtAdvertisement::setFlags(uint8_t flag) { - char cdata[3]; - cdata[0] = 2; - cdata[1] = BLE_HS_ADV_TYPE_FLAGS; // 0x01 - cdata[2] = flag | BLE_HS_ADV_F_BREDR_UNSUP; - addData(std::string(cdata, 3)); -} // setFlags - - -/** - * @brief Set manufacturer specific data. - * @param [in] data The manufacturer data to advertise. - */ -void NimBLEExtAdvertisement::setManufacturerData(const std::string &data) { - char cdata[2]; - cdata[0] = data.length() + 1; - cdata[1] = BLE_HS_ADV_TYPE_MFG_DATA ; // 0xff - addData(std::string(cdata, 2) + data); -} // setManufacturerData - - -/** - * @brief Set the URI to advertise. - * @param [in] uri The uri to advertise. - */ -void NimBLEExtAdvertisement::setURI(const std::string &uri) { - char cdata[2]; - cdata[0] = uri.length() + 1; - cdata[1] = BLE_HS_ADV_TYPE_URI; - addData(std::string(cdata, 2) + uri); -} // setURI - - -/** - * @brief Set the complete name of this device. - * @param [in] name The name to advertise. - */ -void NimBLEExtAdvertisement::setName(const std::string &name) { - char cdata[2]; - cdata[0] = name.length() + 1; - cdata[1] = BLE_HS_ADV_TYPE_COMP_NAME; // 0x09 - addData(std::string(cdata, 2) + name); -} // setName - - -/** - * @brief Set a single service to advertise as a complete list of services. - * @param [in] uuid The service to advertise. - */ -void NimBLEExtAdvertisement::setCompleteServices(const NimBLEUUID &uuid) { - setServices(true, uuid.bitSize(), {uuid}); -} // setCompleteServices - - -/** - * @brief Set the complete list of 16 bit services to advertise. - * @param [in] v_uuid A vector of 16 bit UUID's to advertise. - */ -void NimBLEExtAdvertisement::setCompleteServices16(const std::vector& v_uuid) { - setServices(true, 16, v_uuid); -} // setCompleteServices16 - - -/** - * @brief Set the complete list of 32 bit services to advertise. - * @param [in] v_uuid A vector of 32 bit UUID's to advertise. - */ -void NimBLEExtAdvertisement::setCompleteServices32(const std::vector& v_uuid) { - setServices(true, 32, v_uuid); -} // setCompleteServices32 - - -/** - * @brief Set a single service to advertise as a partial list of services. - * @param [in] uuid The service to advertise. - */ -void NimBLEExtAdvertisement::setPartialServices(const NimBLEUUID &uuid) { - setServices(false, uuid.bitSize(), {uuid}); -} // setPartialServices - - -/** - * @brief Set the partial list of services to advertise. - * @param [in] v_uuid A vector of 16 bit UUID's to advertise. - */ -void NimBLEExtAdvertisement::setPartialServices16(const std::vector& v_uuid) { - setServices(false, 16, v_uuid); -} // setPartialServices16 - - -/** - * @brief Set the partial list of services to advertise. - * @param [in] v_uuid A vector of 32 bit UUID's to advertise. - */ -void NimBLEExtAdvertisement::setPartialServices32(const std::vector& v_uuid) { - setServices(false, 32, v_uuid); -} // setPartialServices32 - - -/** - * @brief Utility function to create the list of service UUID's from a vector. - * @param [in] complete If true the vector is the complete set of services. - * @param [in] size The bit size of the UUID's in the vector. (16, 32, or 128). - * @param [in] v_uuid The vector of service UUID's to advertise. - */ -void NimBLEExtAdvertisement::setServices(const bool complete, const uint8_t size, - const std::vector &v_uuid) -{ - char cdata[2]; - cdata[0] = (size / 8) * v_uuid.size() + 1; - switch(size) { - case 16: - cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS16 : BLE_HS_ADV_TYPE_INCOMP_UUIDS16; - break; - case 32: - cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS32 : BLE_HS_ADV_TYPE_INCOMP_UUIDS32; - break; - case 128: - cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS128 : BLE_HS_ADV_TYPE_INCOMP_UUIDS128; - break; - default: - return; - } - - std::string uuids; - - for(auto &it : v_uuid){ - if(it.bitSize() != size) { - NIMBLE_LOGE(LOG_TAG, "Service UUID(%d) invalid", size); - return; - } else { - switch(size) { - case 16: - uuids += std::string((char*)&it.getNative()->u16.value, 2); - break; - case 32: - uuids += std::string((char*)&it.getNative()->u32.value, 4); - break; - case 128: - uuids += std::string((char*)&it.getNative()->u128.value, 16); - break; - default: - return; - } - } - } - - addData(std::string(cdata, 2) + uuids); -} // setServices - - -/** - * @brief Set the service data (UUID + data) - * @param [in] uuid The UUID to set with the service data. - * @param [in] data The data to be associated with the service data advertised. - */ -void NimBLEExtAdvertisement::setServiceData(const NimBLEUUID &uuid, const std::string &data) { - char cdata[2]; - switch (uuid.bitSize()) { - case 16: { - // [Len] [0x16] [UUID16] data - cdata[0] = data.length() + 3; - cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID16; // 0x16 - addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u16.value, 2) + data); - break; - } - - case 32: { - // [Len] [0x20] [UUID32] data - cdata[0] = data.length() + 5; - cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID32; // 0x20 - addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u32.value, 4) + data); - break; - } - - case 128: { - // [Len] [0x21] [UUID128] data - cdata[0] = data.length() + 17; - cdata[1] = BLE_HS_ADV_TYPE_SVC_DATA_UUID128; // 0x21 - addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u128.value, 16) + data); - break; - } - - default: - return; - } -} // setServiceData - - -/** - * @brief Set the short name. - * @param [in] name The short name of the device. - */ -void NimBLEExtAdvertisement::setShortName(const std::string &name) { - char cdata[2]; - cdata[0] = name.length() + 1; - cdata[1] = BLE_HS_ADV_TYPE_INCOMP_NAME; // 0x08 - addData(std::string(cdata, 2) + name); -} // setShortName - - -/** - * @brief Adds Tx power level to the advertisement data. - */ -void NimBLEExtAdvertisement::addTxPower() { - m_params.include_tx_power = 1; -} // addTxPower - - -/** - * @brief Set the preferred connection interval parameters. - * @param [in] min The minimum interval desired. - * @param [in] max The maximum interval desired. - */ -void NimBLEExtAdvertisement::setPreferredParams(uint16_t min, uint16_t max) { - uint8_t data[6]; - data[0] = BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1; - data[1] = BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE; - data[2] = min; - data[3] = min >> 8; - data[4] = max; - data[5] = max >> 8; - addData(data, 6); -} // setPreferredParams - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && CONFIG_BT_NIMBLE_EXT_ADV */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEExtAdvertising.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEExtAdvertising.h deleted file mode 100644 index b1f21fc78..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEExtAdvertising.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * NimBLEExtAdvertising.h - * - * Created: on February 6, 2022 - * Author H2zero - */ - -#ifndef MAIN_BLEEXTADVERTISING_H_ -#define MAIN_BLEEXTADVERTISING_H_ -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && \ - defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) && \ - CONFIG_BT_NIMBLE_EXT_ADV - -# if defined(CONFIG_NIMBLE_CPP_IDF) -# include "host/ble_gap.h" -# else -# include "nimble/nimble/host/include/host/ble_gap.h" -# endif - -/**** FIX COMPILATION ****/ -#undef min -#undef max -/**************************/ - -#include "NimBLEAddress.h" -#include "NimBLEUUID.h" - -#include - -class NimBLEExtAdvertisingCallbacks; - - -/** - * @brief Extended advertisement data - */ -class NimBLEExtAdvertisement { -public: - NimBLEExtAdvertisement(uint8_t priPhy = BLE_HCI_LE_PHY_1M, - uint8_t secPhy = BLE_HCI_LE_PHY_1M); - void setAppearance(uint16_t appearance); - void setCompleteServices(const NimBLEUUID &uuid); - void setCompleteServices16(const std::vector &v_uuid); - void setCompleteServices32(const std::vector &v_uuid); - void setFlags(uint8_t flag); - void setManufacturerData(const std::string &data); - void setURI(const std::string &uri); - void setName(const std::string &name); - void setPartialServices(const NimBLEUUID &uuid); - void setPartialServices16(const std::vector &v_uuid); - void setPartialServices32(const std::vector &v_uuid); - void setServiceData(const NimBLEUUID &uuid, const std::string &data); - void setShortName(const std::string &name); - void setData(const uint8_t * data, size_t length); - void addData(const std::string &data); - void addData(const uint8_t * data, size_t length); - void addTxPower(); - void setPreferredParams(uint16_t min, uint16_t max); - void setLegacyAdvertising(bool val); - void setConnectable(bool val); - void setScannable(bool val); - void setMinInterval(uint32_t mininterval); - void setMaxInterval(uint32_t maxinterval); - void setPrimaryPhy(uint8_t phy); - void setSecondaryPhy(uint8_t phy); - void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly); - void setDirectedPeer(const NimBLEAddress & addr); - void setDirected(bool val, bool high_duty = true); - void setAnonymous(bool val); - void setPrimaryChannels(bool ch37, bool ch38, bool ch39); - void setTxPower(int8_t dbm); - void setAddress(const NimBLEAddress & addr); - void enableScanRequestCallback(bool enable); - void clearData(); - size_t getDataSize(); - -private: - friend class NimBLEExtAdvertising; - - void setServices(const bool complete, const uint8_t size, - const std::vector &v_uuid); - - std::vector m_payload; - ble_gap_ext_adv_params m_params; - NimBLEAddress m_advAddress; -}; // NimBLEExtAdvertisement - - -/** - * @brief Extended advertising class. - */ -class NimBLEExtAdvertising { -public: - /** - * @brief Construct an extended advertising object. - */ - NimBLEExtAdvertising() :m_advStatus(CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES + 1, false) {} - ~NimBLEExtAdvertising(); - bool start(uint8_t inst_id, int duration = 0, int max_events = 0); - bool setInstanceData(uint8_t inst_id, NimBLEExtAdvertisement& adv); - bool setScanResponseData(uint8_t inst_id, NimBLEExtAdvertisement & data); - bool removeInstance(uint8_t inst_id); - bool removeAll(); - bool stop(uint8_t inst_id); - bool stop(); - bool isActive(uint8_t inst_id); - bool isAdvertising(); - void setCallbacks(NimBLEExtAdvertisingCallbacks* callbacks, - bool deleteCallbacks = true); - -private: - friend class NimBLEDevice; - friend class NimBLEServer; - - void onHostSync(); - static int handleGapEvent(struct ble_gap_event *event, void *arg); - - bool m_scanResp; - bool m_deleteCallbacks; - NimBLEExtAdvertisingCallbacks* m_pCallbacks; - ble_gap_ext_adv_params m_advParams; - std::vector m_advStatus; -}; - - -/** - * @brief Callbacks associated with NimBLEExtAdvertising class. - */ -class NimBLEExtAdvertisingCallbacks { -public: - virtual ~NimBLEExtAdvertisingCallbacks() {}; - - /** - * @brief Handle an advertising stop event. - * @param [in] pAdv A convenience pointer to the extended advertising interface. - * @param [in] reason The reason code for stopping the advertising. - * @param [in] inst_id The instance ID of the advertisement that was stopped. - */ - virtual void onStopped(NimBLEExtAdvertising *pAdv, int reason, uint8_t inst_id); - - /** - * @brief Handle a scan response request. - * This is called when a scanning device requests a scan response. - * @param [in] pAdv A convenience pointer to the extended advertising interface. - * @param [in] inst_id The instance ID of the advertisement that the scan response request was made. - * @param [in] addr The address of the device making the request. - */ - virtual void onScanRequest(NimBLEExtAdvertising *pAdv, uint8_t inst_id, NimBLEAddress addr); -}; // NimBLEExtAdvertisingCallbacks - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && CONFIG_BT_NIMBLE_EXT_ADV */ -#endif /* MAIN_BLEADVERTISING_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.cpp deleted file mode 100644 index a2310eb9e..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* - * NimBLEHIDDevice.cpp - * - * Created: on Oct 06 2020 - * Author wakwak-koba - * - * Originally: - * - * BLEHIDDevice.cpp - * - * Created on: Jan 03, 2018 - * Author: chegewara - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include "NimBLEHIDDevice.h" -#include "NimBLE2904.h" - -/** - * @brief Construct a default NimBLEHIDDevice object. - * @param [in] server A pointer to the server instance this HID Device will use. - */ -NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer* server) { - /* - * Here we create mandatory services described in bluetooth specification - */ - m_deviceInfoService = server->createService(NimBLEUUID((uint16_t) 0x180a)); - m_hidService = server->createService(NimBLEUUID((uint16_t) 0x1812)); - m_batteryService = server->createService(NimBLEUUID((uint16_t) 0x180f)); - - /* - * Mandatory characteristic for device info service - */ - m_pnpCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a50, NIMBLE_PROPERTY::READ); - - /* - * Mandatory characteristics for HID service - */ - m_hidInfoCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4a, NIMBLE_PROPERTY::READ); - m_reportMapCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4b, NIMBLE_PROPERTY::READ); - m_hidControlCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4c, NIMBLE_PROPERTY::WRITE_NR); - m_protocolModeCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4e, NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ); - - /* - * Mandatory battery level characteristic with notification and presence descriptor - */ - m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t) 0x2a19, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY); - NimBLE2904* batteryLevelDescriptor = (NimBLE2904*)m_batteryLevelCharacteristic->createDescriptor((uint16_t) 0x2904); - batteryLevelDescriptor->setFormat(NimBLE2904::FORMAT_UINT8); - batteryLevelDescriptor->setNamespace(1); - batteryLevelDescriptor->setUnit(0x27ad); - - /* - * This value is setup here because its default value in most usage cases, its very rare to use boot mode - * and we want to simplify library using as much as possible - */ - const uint8_t pMode[] = { 0x01 }; - protocolMode()->setValue((uint8_t*) pMode, 1); -} - -NimBLEHIDDevice::~NimBLEHIDDevice() { -} - -/** - * @brief Set the report map data formatting information. - * @param [in] map A pointer to an array with the values to set. - * @param [in] size The number of values in the array. - */ -void NimBLEHIDDevice::reportMap(uint8_t* map, uint16_t size) { - m_reportMapCharacteristic->setValue(map, size); -} - -/** - * @brief Start the HID device services.\n - * This function called when all the services have been created. - */ -void NimBLEHIDDevice::startServices() { - m_deviceInfoService->start(); - m_hidService->start(); - m_batteryService->start(); -} - -/** - * @brief Create a manufacturer characteristic (this characteristic is optional). - */ -NimBLECharacteristic* NimBLEHIDDevice::manufacturer() { - m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, NIMBLE_PROPERTY::READ); - return m_manufacturerCharacteristic; -} - -/** - * @brief Set manufacturer name - * @param [in] name The manufacturer name of this HID device. - */ -void NimBLEHIDDevice::manufacturer(std::string name) { - m_manufacturerCharacteristic->setValue(name); -} - -/** - * @brief Sets the Plug n Play characteristic value. - * @param [in] sig The vendor ID source number. - * @param [in] vid The vendor ID number. - * @param [in] pid The product ID number. - * @param [in] version The produce version number. - */ -void NimBLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) { - uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version }; - m_pnpCharacteristic->setValue(pnp, sizeof(pnp)); -} - -/** - * @brief Sets the HID Information characteristic value. - * @param [in] country The country code for the device. - * @param [in] flags The HID Class Specification release number to use. - */ -void NimBLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) { - uint8_t info[] = { 0x11, 0x1, country, flags }; - m_hidInfoCharacteristic->setValue(info, sizeof(info)); -} - -/** - * @brief Create input report characteristic - * @param [in] reportID input report ID, the same as in report map for input object related to the characteristic - * @return pointer to new input report characteristic - */ -NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) { - NimBLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ_ENC); - NimBLEDescriptor* inputReportDescriptor = inputReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_ENC); - - uint8_t desc1_val[] = { reportID, 0x01 }; - inputReportDescriptor->setValue((uint8_t*) desc1_val, 2); - - return inputReportCharacteristic; -} - -/** - * @brief Create output report characteristic - * @param [in] reportID Output report ID, the same as in report map for output object related to the characteristic - * @return Pointer to new output report characteristic - */ -NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) { - NimBLECharacteristic* outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC); - NimBLEDescriptor* outputReportDescriptor = outputReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC); - - uint8_t desc1_val[] = { reportID, 0x02 }; - outputReportDescriptor->setValue((uint8_t*) desc1_val, 2); - - return outputReportCharacteristic; -} - -/** - * @brief Create feature report characteristic. - * @param [in] reportID Feature report ID, the same as in report map for feature object related to the characteristic - * @return Pointer to new feature report characteristic - */ -NimBLECharacteristic* NimBLEHIDDevice::featureReport(uint8_t reportID) { - NimBLECharacteristic* featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC); - NimBLEDescriptor* featureReportDescriptor = featureReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC); - - uint8_t desc1_val[] = { reportID, 0x03 }; - featureReportDescriptor->setValue((uint8_t*) desc1_val, 2); - - return featureReportCharacteristic; -} - -/** - * @brief Creates a keyboard boot input report characteristic - */ -NimBLECharacteristic* NimBLEHIDDevice::bootInput() { - return m_hidService->createCharacteristic((uint16_t) 0x2a22, NIMBLE_PROPERTY::NOTIFY); -} - -/** - * @brief Create a keyboard boot output report characteristic - */ -NimBLECharacteristic* NimBLEHIDDevice::bootOutput() { - return m_hidService->createCharacteristic((uint16_t) 0x2a32, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR); -} - -/** - * @brief Returns a pointer to the HID control point characteristic. - */ -NimBLECharacteristic* NimBLEHIDDevice::hidControl() { - return m_hidControlCharacteristic; -} - -/** - * @brief Returns a pointer to the protocol mode characteristic. - */ -NimBLECharacteristic* NimBLEHIDDevice::protocolMode() { - return m_protocolModeCharacteristic; -} - -/** - * @brief Set the battery level characteristic value. - * @param [in] level The battery level value. - */ -void NimBLEHIDDevice::setBatteryLevel(uint8_t level) { - m_batteryLevelCharacteristic->setValue(&level, 1); -} -/* - * @brief Returns battery level characteristic - * @ return battery level characteristic - */ -NimBLECharacteristic* NimBLEHIDDevice::batteryLevel() { - return m_batteryLevelCharacteristic; -} - -/* - -BLECharacteristic* BLEHIDDevice::reportMap() { - return m_reportMapCharacteristic; -} - -BLECharacteristic* BLEHIDDevice::pnp() { - return m_pnpCharacteristic; -} - - -BLECharacteristic* BLEHIDDevice::hidInfo() { - return m_hidInfoCharacteristic; -} -*/ - -/** - * @brief Returns a pointer to the device information service. - */ -NimBLEService* NimBLEHIDDevice::deviceInfo() { - return m_deviceInfoService; -} - -/** - * @brief Returns a pointer to the HID service. - */ -NimBLEService* NimBLEHIDDevice::hidService() { - return m_hidService; -} - -/** - * @brief @brief Returns a pointer to the battery service. - */ -NimBLEService* NimBLEHIDDevice::batteryService() { - return m_batteryService; -} - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.h deleted file mode 100644 index 0e8b2828a..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * NimBLEHIDDevice.h - * - * Created: on Oct 06 2020 - * Author wakwak-koba - * - * Originally: - * - * BLEHIDDevice.h - * - * Created on: Jan 03, 2018 - * Author: chegewara - */ - -#ifndef _BLEHIDDEVICE_H_ -#define _BLEHIDDEVICE_H_ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER) - -#include "NimBLECharacteristic.h" -#include "NimBLEService.h" -#include "NimBLEDescriptor.h" -#include "HIDTypes.h" - -#define GENERIC_HID 0x03C0 -#define HID_KEYBOARD 0x03C1 -#define HID_MOUSE 0x03C2 -#define HID_JOYSTICK 0x03C3 -#define HID_GAMEPAD 0x03C4 -#define HID_TABLET 0x03C5 -#define HID_CARD_READER 0x03C6 -#define HID_DIGITAL_PEN 0x03C7 -#define HID_BARCODE 0x03C8 - - -/** - * @brief A model of a %BLE Human Interface Device. - */ -class NimBLEHIDDevice { -public: - NimBLEHIDDevice(NimBLEServer*); - virtual ~NimBLEHIDDevice(); - - void reportMap(uint8_t* map, uint16_t); - void startServices(); - - NimBLEService* deviceInfo(); - NimBLEService* hidService(); - NimBLEService* batteryService(); - - NimBLECharacteristic* manufacturer(); - void manufacturer(std::string name); - //NimBLECharacteristic* pnp(); - void pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version); - //NimBLECharacteristic* hidInfo(); - void hidInfo(uint8_t country, uint8_t flags); - NimBLECharacteristic* batteryLevel(); - void setBatteryLevel(uint8_t level); - - - //NimBLECharacteristic* reportMap(); - NimBLECharacteristic* hidControl(); - NimBLECharacteristic* inputReport(uint8_t reportID); - NimBLECharacteristic* outputReport(uint8_t reportID); - NimBLECharacteristic* featureReport(uint8_t reportID); - NimBLECharacteristic* protocolMode(); - NimBLECharacteristic* bootInput(); - NimBLECharacteristic* bootOutput(); - -private: - NimBLEService* m_deviceInfoService; //0x180a - NimBLEService* m_hidService; //0x1812 - NimBLEService* m_batteryService = 0; //0x180f - - NimBLECharacteristic* m_manufacturerCharacteristic; //0x2a29 - NimBLECharacteristic* m_pnpCharacteristic; //0x2a50 - NimBLECharacteristic* m_hidInfoCharacteristic; //0x2a4a - NimBLECharacteristic* m_reportMapCharacteristic; //0x2a4b - NimBLECharacteristic* m_hidControlCharacteristic; //0x2a4c - NimBLECharacteristic* m_protocolModeCharacteristic; //0x2a4e - NimBLECharacteristic* m_batteryLevelCharacteristic; //0x2a19 -}; - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER */ -#endif /* _BLEHIDDEVICE_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLELog.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLELog.h deleted file mode 100644 index dda9073f3..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLELog.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * NimBLELog.h - * - * Created: on Feb 24 2020 - * Author H2zero - * - */ -#ifndef MAIN_NIMBLELOG_H_ -#define MAIN_NIMBLELOG_H_ - -#include "nimconfig.h" - -#if defined(CONFIG_BT_ENABLED) - -#if defined(CONFIG_NIMBLE_CPP_IDF) // using esp-idf -# include "esp_log.h" -# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL -# define CONFIG_NIMBLE_CPP_LOG_LEVEL 0 -# endif - -# define NIMBLE_CPP_LOG_PRINT(level, tag, format, ...) do { \ - if (CONFIG_NIMBLE_CPP_LOG_LEVEL >= level) \ - ESP_LOG_LEVEL_LOCAL(level, tag, format, ##__VA_ARGS__); \ - } while(0) - -# define NIMBLE_LOGD(tag, format, ...) \ - NIMBLE_CPP_LOG_PRINT(ESP_LOG_DEBUG, tag, format, ##__VA_ARGS__) - -# define NIMBLE_LOGI(tag, format, ...) \ - NIMBLE_CPP_LOG_PRINT(ESP_LOG_INFO, tag, format, ##__VA_ARGS__) - -# define NIMBLE_LOGW(tag, format, ...) \ - NIMBLE_CPP_LOG_PRINT(ESP_LOG_WARN, tag, format, ##__VA_ARGS__) - -# define NIMBLE_LOGE(tag, format, ...) \ - NIMBLE_CPP_LOG_PRINT(ESP_LOG_ERROR, tag, format, ##__VA_ARGS__) - -# define NIMBLE_LOGC(tag, format, ...) \ - NIMBLE_CPP_LOG_PRINT(ESP_LOG_ERROR, tag, format, ##__VA_ARGS__) - -#else // using Arduino -# include "nimble/porting/nimble/include/syscfg/syscfg.h" -# include "nimble/console/console.h" -# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL -# if defined(ARDUINO_ARCH_ESP32) && defined(CORE_DEBUG_LEVEL) -# define CONFIG_NIMBLE_CPP_LOG_LEVEL CORE_DEBUG_LEVEL -# else -# define CONFIG_NIMBLE_CPP_LOG_LEVEL 0 -# endif -# endif - -# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4 -# define NIMBLE_LOGD( tag, format, ... ) console_printf("D %s: " format "\n", tag, ##__VA_ARGS__) -# else -# define NIMBLE_LOGD( tag, format, ... ) (void)tag -# endif - -# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 3 -# define NIMBLE_LOGI( tag, format, ... ) console_printf("I %s: " format "\n", tag, ##__VA_ARGS__) -# else -# define NIMBLE_LOGI( tag, format, ... ) (void)tag -# endif - -# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 2 -# define NIMBLE_LOGW( tag, format, ... ) console_printf("W %s: " format "\n", tag, ##__VA_ARGS__) -# else -# define NIMBLE_LOGW( tag, format, ... ) (void)tag -# endif - -# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 1 -# define NIMBLE_LOGE( tag, format, ... ) console_printf("E %s: " format "\n", tag, ##__VA_ARGS__) -# define NIMBLE_LOGC( tag, format, ... ) console_printf("CRIT %s: " format "\n", tag, ##__VA_ARGS__) -# else -# define NIMBLE_LOGE( tag, format, ... ) (void)tag -# define NIMBLE_LOGC( tag, format, ... ) (void)tag -# endif - -#endif /* CONFIG_NIMBLE_CPP_IDF */ -#endif /* CONFIG_BT_ENABLED */ -#endif /* MAIN_NIMBLELOG_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.cpp deleted file mode 100644 index 6cca615db..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.cpp +++ /dev/null @@ -1,865 +0,0 @@ -/* - * NimBLERemoteCharacteristic.cpp - * - * Created: on Jan 27 2020 - * Author H2zero - * - * Originally: - * - * BLERemoteCharacteristic.cpp - * - * Created on: Mar 16, 2017 - * Author: kolban - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) - -#include "NimBLERemoteCharacteristic.h" -#include "NimBLEUtils.h" -#include "NimBLELog.h" - -#include - -static const char* LOG_TAG = "NimBLERemoteCharacteristic"; - -/** - * @brief Constructor. - * @param [in] reference to the service this characteristic belongs to. - * @param [in] ble_gatt_chr struct defined as: - * struct ble_gatt_chr { - * uint16_t def_handle; - * uint16_t val_handle; - * uint8_t properties; - * ble_uuid_any_t uuid; - * }; - */ - NimBLERemoteCharacteristic::NimBLERemoteCharacteristic(NimBLERemoteService *pRemoteService, - const struct ble_gatt_chr *chr) -{ - NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteCharacteristic()"); - switch (chr->uuid.u.type) { - case BLE_UUID_TYPE_16: - m_uuid = NimBLEUUID(chr->uuid.u16.value); - break; - case BLE_UUID_TYPE_32: - m_uuid = NimBLEUUID(chr->uuid.u32.value); - break; - case BLE_UUID_TYPE_128: - m_uuid = NimBLEUUID(const_cast(&chr->uuid.u128)); - break; - default: - break; - } - - m_handle = chr->val_handle; - m_defHandle = chr->def_handle; - m_endHandle = 0; - m_charProp = chr->properties; - m_pRemoteService = pRemoteService; - m_notifyCallback = nullptr; - - NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteCharacteristic(): %s", m_uuid.toString().c_str()); - } // NimBLERemoteCharacteristic - - -/** - *@brief Destructor. - */ -NimBLERemoteCharacteristic::~NimBLERemoteCharacteristic() { - deleteDescriptors(); -} // ~NimBLERemoteCharacteristic - -/* -#define BLE_GATT_CHR_PROP_BROADCAST 0x01 -#define BLE_GATT_CHR_PROP_READ 0x02 -#define BLE_GATT_CHR_PROP_WRITE_NO_RSP 0x04 -#define BLE_GATT_CHR_PROP_WRITE 0x08 -#define BLE_GATT_CHR_PROP_NOTIFY 0x10 -#define BLE_GATT_CHR_PROP_INDICATE 0x20 -#define BLE_GATT_CHR_PROP_AUTH_SIGN_WRITE 0x40 -#define BLE_GATT_CHR_PROP_EXTENDED 0x80 -*/ - -/** - * @brief Does the characteristic support broadcasting? - * @return True if the characteristic supports broadcasting. - */ -bool NimBLERemoteCharacteristic::canBroadcast() { - return (m_charProp & BLE_GATT_CHR_PROP_BROADCAST) != 0; -} // canBroadcast - - -/** - * @brief Does the characteristic support indications? - * @return True if the characteristic supports indications. - */ -bool NimBLERemoteCharacteristic::canIndicate() { - return (m_charProp & BLE_GATT_CHR_PROP_INDICATE) != 0; -} // canIndicate - - -/** - * @brief Does the characteristic support notifications? - * @return True if the characteristic supports notifications. - */ -bool NimBLERemoteCharacteristic::canNotify() { - return (m_charProp & BLE_GATT_CHR_PROP_NOTIFY) != 0; -} // canNotify - - -/** - * @brief Does the characteristic support reading? - * @return True if the characteristic supports reading. - */ -bool NimBLERemoteCharacteristic::canRead() { - return (m_charProp & BLE_GATT_CHR_PROP_READ) != 0; -} // canRead - - -/** - * @brief Does the characteristic support writing? - * @return True if the characteristic supports writing. - */ -bool NimBLERemoteCharacteristic::canWrite() { - return (m_charProp & BLE_GATT_CHR_PROP_WRITE) != 0; -} // canWrite - - -/** - * @brief Does the characteristic support writing with no response? - * @return True if the characteristic supports writing with no response. - */ -bool NimBLERemoteCharacteristic::canWriteNoResponse() { - return (m_charProp & BLE_GATT_CHR_PROP_WRITE_NO_RSP) != 0; -} // canWriteNoResponse - - -/** - * @brief Callback used by the API when a descriptor is discovered or search complete. - */ -int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle, - const struct ble_gatt_error *error, - uint16_t chr_val_handle, - const struct ble_gatt_dsc *dsc, - void *arg) -{ - int rc = error->status; - NIMBLE_LOGD(LOG_TAG, "Descriptor Discovered >> status: %d handle: %d", - rc, (rc == 0) ? dsc->handle : -1); - - desc_filter_t *filter = (desc_filter_t*)arg; - const NimBLEUUID *uuid_filter = filter->uuid; - ble_task_data_t *pTaskData = (ble_task_data_t*)filter->task_data; - NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT; - - if (characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){ - return 0; - } - - switch (rc) { - case 0: { - if (uuid_filter != nullptr) { - if (ble_uuid_cmp(&uuid_filter->getNative()->u, &dsc->uuid.u) != 0) { - return 0; - } else { - rc = BLE_HS_EDONE; - } - } - - NimBLERemoteDescriptor* pNewRemoteDescriptor = new NimBLERemoteDescriptor(characteristic, dsc); - characteristic->m_descriptorVector.push_back(pNewRemoteDescriptor); - break; - } - default: - break; - } - - /* If rc == BLE_HS_EDONE, resume the task with a success error code and stop the discovery process. - * Else if rc == 0, just return 0 to continue the discovery until we get BLE_HS_EDONE. - * If we get any other error code tell the application to abort by returning non-zero in the rc. - */ - if (rc == BLE_HS_EDONE) { - pTaskData->rc = 0; - xTaskNotifyGive(pTaskData->task); - } else if(rc != 0) { - // Error; abort discovery. - pTaskData->rc = rc; - xTaskNotifyGive(pTaskData->task); - } - - NIMBLE_LOGD(LOG_TAG,"<< Descriptor Discovered. status: %d", pTaskData->rc); - return rc; -} - - -/** - * @brief callback from NimBLE when the next characteristic of the service is discovered. - */ -int NimBLERemoteCharacteristic::nextCharCB(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_chr *chr, void *arg) -{ - int rc = error->status; - NIMBLE_LOGD(LOG_TAG, "Next Characteristic >> status: %d handle: %d", - rc, (rc == 0) ? chr->val_handle : -1); - - ble_task_data_t *pTaskData = (ble_task_data_t*)arg; - NimBLERemoteCharacteristic *pChar = (NimBLERemoteCharacteristic*)pTaskData->pATT; - - if (pChar->getRemoteService()->getClient()->getConnId() != conn_handle) { - return 0; - } - - if (rc == 0) { - pChar->m_endHandle = chr->def_handle - 1; - rc = BLE_HS_EDONE; - } else if (rc == BLE_HS_EDONE) { - pChar->m_endHandle = pChar->getRemoteService()->getEndHandle(); - } else { - pTaskData->rc = rc; - } - - xTaskNotifyGive(pTaskData->task); - return rc; -} - - -/** - * @brief Populate the descriptors (if any) for this characteristic. - * @param [in] the end handle of the characteristic, or the service, whichever comes first. - */ -bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filter) { - NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str()); - - // If this is the last handle then there are no descriptors - if (m_handle == getRemoteService()->getEndHandle()) { - return true; - } - - int rc = 0; - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {this, cur_task, 0, nullptr}; - - // If we don't know the end handle of this characteristic retrieve the next one in the service - // The end handle is the next characteristic definition handle -1. - if (m_endHandle == 0) { - rc = ble_gattc_disc_all_chrs(getRemoteService()->getClient()->getConnId(), - m_handle, - getRemoteService()->getEndHandle(), - NimBLERemoteCharacteristic::nextCharCB, - &taskData); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Error getting end handle rc=%d", rc); - return false; - } - -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - - if (taskData.rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Could not retrieve end handle rc=%d", taskData.rc); - return false; - } - } - - if (m_handle == m_endHandle) { - return true; - } - - desc_filter_t filter = {uuid_filter, &taskData}; - - rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(), - m_handle, - m_endHandle, - NimBLERemoteCharacteristic::descriptorDiscCB, - &filter); - - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_dscs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); - return false; - } - -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - - if (taskData.rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Failed to retrieve descriptors; startHandle:%d endHandle:%d taskData.rc=%d", - m_handle, m_endHandle, taskData.rc); - } - - NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorVector.size()); - return (taskData.rc == 0); -} // retrieveDescriptors - - -/** - * @brief Get the descriptor instance with the given UUID that belongs to this characteristic. - * @param [in] uuid The UUID of the descriptor to find. - * @return The Remote descriptor (if present) or null if not present. - */ -NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUUID &uuid) { - NIMBLE_LOGD(LOG_TAG, ">> getDescriptor: uuid: %s", uuid.toString().c_str()); - - for(auto &it: m_descriptorVector) { - if(it->getUUID() == uuid) { - NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: found the descriptor with uuid: %s", uuid.toString().c_str()); - return it; - } - } - - size_t prev_size = m_descriptorVector.size(); - if(retrieveDescriptors(&uuid)) { - if(m_descriptorVector.size() > prev_size) { - return m_descriptorVector.back(); - } - - // If the request was successful but 16/32 bit uuid not found - // try again with the 128 bit uuid. - if(uuid.bitSize() == BLE_UUID_TYPE_16 || - uuid.bitSize() == BLE_UUID_TYPE_32) - { - NimBLEUUID uuid128(uuid); - uuid128.to128(); - if(retrieveDescriptors(&uuid128)) { - if(m_descriptorVector.size() > prev_size) { - return m_descriptorVector.back(); - } - } - } else { - // If the request was successful but the 128 bit uuid not found - // try again with the 16 bit uuid. - NimBLEUUID uuid16(uuid); - uuid16.to16(); - // if the uuid was 128 bit but not of the BLE base type this check will fail - if (uuid16.bitSize() == BLE_UUID_TYPE_16) { - if(retrieveDescriptors(&uuid16)) { - if(m_descriptorVector.size() > prev_size) { - return m_descriptorVector.back(); - } - } - } - } - } - - NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: Not found"); - return nullptr; -} // getDescriptor - - -/** - * @brief Get a pointer to the vector of found descriptors. - * @param [in] refresh If true the current descriptor vector will be cleared and\n - * all descriptors for this characteristic retrieved from the peripheral.\n - * If false the vector will be returned with the currently stored descriptors - * of this characteristic. - * @return A pointer to the vector of descriptors for this characteristic. - */ -std::vector* NimBLERemoteCharacteristic::getDescriptors(bool refresh) { - if(refresh) { - deleteDescriptors(); - - if (!retrieveDescriptors()) { - NIMBLE_LOGE(LOG_TAG, "Error: Failed to get descriptors"); - } - else{ - NIMBLE_LOGI(LOG_TAG, "Found %d descriptor(s)", m_descriptorVector.size()); - } - } - return &m_descriptorVector; -} // getDescriptors - - -/** - * @brief Get iterator to the beginning of the vector of remote descriptor pointers. - * @return An iterator to the beginning of the vector of remote descriptor pointers. - */ -std::vector::iterator NimBLERemoteCharacteristic::begin() { - return m_descriptorVector.begin(); -} - - -/** - * @brief Get iterator to the end of the vector of remote descriptor pointers. - * @return An iterator to the end of the vector of remote descriptor pointers. - */ -std::vector::iterator NimBLERemoteCharacteristic::end() { - return m_descriptorVector.end(); -} - - -/** - * @brief Get the handle for this characteristic. - * @return The handle for this characteristic. - */ -uint16_t NimBLERemoteCharacteristic::getHandle() { - return m_handle; -} // getHandle - -/** - * @brief Get the handle for this characteristics definition. - * @return The handle for this characteristic definition. - */ -uint16_t NimBLERemoteCharacteristic::getDefHandle() { - return m_defHandle; -} // getDefHandle - - -/** - * @brief Get the remote service associated with this characteristic. - * @return The remote service associated with this characteristic. - */ -NimBLERemoteService* NimBLERemoteCharacteristic::getRemoteService() { - return m_pRemoteService; -} // getRemoteService - - -/** - * @brief Get the UUID for this characteristic. - * @return The UUID for this characteristic. - */ -NimBLEUUID NimBLERemoteCharacteristic::getUUID() { - return m_uuid; -} // getUUID - - -/** - * @brief Get the value of the remote characteristic. - * @param [in] timestamp A pointer to a time_t struct to store the time the value was read. - * @return The value of the remote characteristic. - */ -NimBLEAttValue NimBLERemoteCharacteristic::getValue(time_t *timestamp) { - if(timestamp != nullptr) { - *timestamp = m_value.getTimeStamp(); - } - - return m_value; -} - - -/** - * @brief Read an unsigned 16 bit value - * @return The unsigned 16 bit value. - * @deprecated Use readValue(). - */ -uint16_t NimBLERemoteCharacteristic::readUInt16() { - return readValue(); -} // readUInt16 - - -/** - * @brief Read an unsigned 32 bit value. - * @return the unsigned 32 bit value. - * @deprecated Use readValue(). - */ -uint32_t NimBLERemoteCharacteristic::readUInt32() { - return readValue(); -} // readUInt32 - - -/** - * @brief Read a byte value - * @return The value as a byte - * @deprecated Use readValue(). - */ -uint8_t NimBLERemoteCharacteristic::readUInt8() { - return readValue(); -} // readUInt8 - - -/** - * @brief Read a float value. - * @return the float value. - */ -float NimBLERemoteCharacteristic::readFloat() { - return readValue(); -} // readFloat - - -/** - * @brief Read the value of the remote characteristic. - * @param [in] timestamp A pointer to a time_t struct to store the time the value was read. - * @return The value of the remote characteristic. - */ -NimBLEAttValue NimBLERemoteCharacteristic::readValue(time_t *timestamp) { - NIMBLE_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x", - getUUID().toString().c_str(), getHandle(), getHandle()); - - NimBLEClient* pClient = getRemoteService()->getClient(); - NimBLEAttValue value; - - if (!pClient->isConnected()) { - NIMBLE_LOGE(LOG_TAG, "Disconnected"); - return value; - } - - int rc = 0; - int retryCount = 1; - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {this, cur_task, 0, &value}; - - do { - rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0, - NimBLERemoteCharacteristic::onReadCB, - &taskData); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Error: Failed to read characteristic; rc=%d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); - return value; - } - -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - rc = taskData.rc; - - switch(rc){ - case 0: - case BLE_HS_EDONE: - rc = 0; - break; - // Characteristic is not long-readable, return with what we have. - case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG): - NIMBLE_LOGI(LOG_TAG, "Attribute not long"); - rc = 0; - break; - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN): - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR): - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC): - if (retryCount && pClient->secureConnection()) - break; - /* Else falls through. */ - default: - NIMBLE_LOGE(LOG_TAG, "<< readValue rc=%d", rc); - return value; - } - } while(rc != 0 && retryCount--); - - value.setTimeStamp(); - m_value = value; - if(timestamp != nullptr) { - *timestamp = value.getTimeStamp(); - } - - NIMBLE_LOGD(LOG_TAG, "<< readValue length: %d rc=%d", value.length(), rc); - return value; -} // readValue - - -/** - * @brief Callback for characteristic read operation. - * @return success == 0 or error code. - */ -int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, void *arg) -{ - ble_task_data_t *pTaskData = (ble_task_data_t*)arg; - NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT; - uint16_t conn_id = characteristic->getRemoteService()->getClient()->getConnId(); - - if(conn_id != conn_handle) { - return 0; - } - - NIMBLE_LOGI(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle); - - NimBLEAttValue *valBuf = (NimBLEAttValue*)pTaskData->buf; - int rc = error->status; - - if(rc == 0) { - if(attr) { - uint16_t data_len = OS_MBUF_PKTLEN(attr->om); - if((valBuf->size() + data_len) > BLE_ATT_ATTR_MAX_LEN) { - rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; - } else { - NIMBLE_LOGD(LOG_TAG, "Got %u bytes", data_len); - valBuf->append(attr->om->om_data, data_len); - return 0; - } - } - } - - pTaskData->rc = rc; - xTaskNotifyGive(pTaskData->task); - - return rc; -} - - -/** - * @brief Subscribe or unsubscribe for notifications or indications. - * @param [in] val 0x00 to unsubscribe, 0x01 for notifications, 0x02 for indications. - * @param [in] notifyCallback A callback to be invoked for a notification. - * @param [in] response If write response required set this to true. - * If NULL is provided then no callback is performed. - * @return false if writing to the descriptor failed. - */ -bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyCallback, bool response) { - NIMBLE_LOGD(LOG_TAG, ">> setNotify(): %s, %02x", toString().c_str(), val); - - m_notifyCallback = notifyCallback; - - NimBLERemoteDescriptor* desc = getDescriptor(NimBLEUUID((uint16_t)0x2902)); - if(desc == nullptr) { - NIMBLE_LOGW(LOG_TAG, "<< setNotify(): Callback set, CCCD not found"); - return true; - } - - NIMBLE_LOGD(LOG_TAG, "<< setNotify()"); - - return desc->writeValue((uint8_t *)&val, 2, response); -} // setNotify - - -/** - * @brief Subscribe for notifications or indications. - * @param [in] notifications If true, subscribe for notifications, false subscribe for indications. - * @param [in] notifyCallback A callback to be invoked for a notification. - * @param [in] response If true, require a write response from the descriptor write operation. - * If NULL is provided then no callback is performed. - * @return false if writing to the descriptor failed. - */ -bool NimBLERemoteCharacteristic::subscribe(bool notifications, notify_callback notifyCallback, bool response) { - if(notifications) { - return setNotify(0x01, notifyCallback, response); - } else { - return setNotify(0x02, notifyCallback, response); - } -} // subscribe - - -/** - * @brief Unsubscribe for notifications or indications. - * @param [in] response bool if true, require a write response from the descriptor write operation. - * @return false if writing to the descriptor failed. - */ -bool NimBLERemoteCharacteristic::unsubscribe(bool response) { - return setNotify(0x00, nullptr, response); -} // unsubscribe - - - /** - * @brief backward-compatibility method for subscribe/unsubscribe notifications/indications - * @param [in] notifyCallback A callback to be invoked for a notification. If NULL is provided then we - * will unregister for notifications. - * @param [in] notifications If true, register for notifications, false register for indications. - * @param [in] response If true, require a write response from the descriptor write operation. - * @return true if successful. - * @deprecated Use subscribe() / unsubscribe() instead. - */ -bool NimBLERemoteCharacteristic::registerForNotify(notify_callback notifyCallback, bool notifications, bool response) { - bool success; - if(notifyCallback != nullptr) { - success = subscribe(notifications, notifyCallback, response); - } else { - success = unsubscribe(response); - } - return success; -} // registerForNotify - - -/** - * @brief Delete the descriptors in the descriptor vector. - * @details We maintain a vector called m_descriptorVector that contains pointers to NimBLERemoteDescriptors - * object references. Since we allocated these in this class, we are also responsible for deleting - * them. This method does just that. - */ -void NimBLERemoteCharacteristic::deleteDescriptors() { - NIMBLE_LOGD(LOG_TAG, ">> deleteDescriptors"); - - for(auto &it: m_descriptorVector) { - delete it; - } - m_descriptorVector.clear(); - NIMBLE_LOGD(LOG_TAG, "<< deleteDescriptors"); -} // deleteDescriptors - - -/** - * @brief Delete descriptor by UUID - * @param [in] uuid The UUID of the descriptor to be deleted. - * @return Number of descriptors left in the vector. - */ -size_t NimBLERemoteCharacteristic::deleteDescriptor(const NimBLEUUID &uuid) { - NIMBLE_LOGD(LOG_TAG, ">> deleteDescriptor"); - - for(auto it = m_descriptorVector.begin(); it != m_descriptorVector.end(); ++it) { - if((*it)->getUUID() == uuid) { - delete *it; - m_descriptorVector.erase(it); - break; - } - } - - NIMBLE_LOGD(LOG_TAG, "<< deleteDescriptor"); - - return m_descriptorVector.size(); -} // deleteDescriptor - - -/** - * @brief Convert a NimBLERemoteCharacteristic to a string representation; - * @return a String representation. - */ -std::string NimBLERemoteCharacteristic::toString() { - std::string res = "Characteristic: uuid: " + m_uuid.toString(); - char val[6]; - res += ", handle: "; - snprintf(val, sizeof(val), "%d", getHandle()); - res += val; - res += " 0x"; - snprintf(val, sizeof(val), "%04x", getHandle()); - res += val; - res += ", props: "; - res += " 0x"; - snprintf(val, sizeof(val), "%02x", m_charProp); - res += val; - - for(auto &it: m_descriptorVector) { - res += "\n" + it->toString(); - } - - return res; -} // toString - - -/** - * @brief Write a new value to the remote characteristic from a std::vector. - * @param [in] vec A std::vector value to write to the remote characteristic. - * @param [in] response Whether we require a response from the write. - * @return false if not connected or otherwise cannot perform write. - */ -bool NimBLERemoteCharacteristic::writeValue(const std::vector& vec, bool response) { - return writeValue((uint8_t*)&vec[0], vec.size(), response); -} // writeValue - - -/** - * @brief Write a new value to the remote characteristic from a const char*. - * @param [in] char_s A character string to write to the remote characteristic. - * @param [in] response Whether we require a response from the write. - * @return false if not connected or otherwise cannot perform write. - */ -bool NimBLERemoteCharacteristic::writeValue(const char* char_s, bool response) { - return writeValue((uint8_t*)char_s, strlen(char_s), response); -} // writeValue - - -/** - * @brief Write a new value to the remote characteristic from a data buffer. - * @param [in] data A pointer to a data buffer. - * @param [in] length The length of the data in the data buffer. - * @param [in] response Whether we require a response from the write. - * @return false if not connected or otherwise cannot perform write. - */ -bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length, bool response) { - - NIMBLE_LOGD(LOG_TAG, ">> writeValue(), length: %d", length); - - NimBLEClient* pClient = getRemoteService()->getClient(); - - if (!pClient->isConnected()) { - NIMBLE_LOGE(LOG_TAG, "Disconnected"); - return false; - } - - int rc = 0; - int retryCount = 1; - uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3; - - // Check if the data length is longer than we can write in one connection event. - // If so we must do a long write which requires a response. - if(length <= mtu && !response) { - rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length); - return (rc==0); - } - - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {this, cur_task, 0, nullptr}; - - do { - if(length > mtu) { - NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length); - os_mbuf *om = ble_hs_mbuf_from_flat(data, length); - rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om, - NimBLERemoteCharacteristic::onWriteCB, - &taskData); - } else { - rc = ble_gattc_write_flat(pClient->getConnId(), m_handle, - data, length, - NimBLERemoteCharacteristic::onWriteCB, - &taskData); - } - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Error: Failed to write characteristic; rc=%d", rc); - return false; - } - -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - rc = taskData.rc; - - switch(rc){ - case 0: - case BLE_HS_EDONE: - rc = 0; - break; - case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG): - NIMBLE_LOGE(LOG_TAG, "Long write not supported by peer; Truncating length to %d", mtu); - retryCount++; - length = mtu; - break; - - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN): - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR): - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC): - if (retryCount && pClient->secureConnection()) - break; - /* Else falls through. */ - default: - NIMBLE_LOGE(LOG_TAG, "<< writeValue, rc: %d", rc); - return false; - } - } while(rc != 0 && retryCount--); - - NIMBLE_LOGD(LOG_TAG, "<< writeValue, rc: %d", rc); - return (rc == 0); -} // writeValue - - -/** - * @brief Callback for characteristic write operation. - * @return success == 0 or error code. - */ -int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, void *arg) -{ - ble_task_data_t *pTaskData = (ble_task_data_t*)arg; - NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT; - - if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){ - return 0; - } - - NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle); - - pTaskData->rc = error->status; - xTaskNotifyGive(pTaskData->task); - - return 0; -} - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.h deleted file mode 100644 index 353d83221..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * NimBLERemoteCharacteristic.h - * - * Created: on Jan 27 2020 - * Author H2zero - * - * Originally: - * - * BLERemoteCharacteristic.h - * - * Created on: Jul 8, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_ -#define COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) - -#include "NimBLERemoteService.h" -#include "NimBLERemoteDescriptor.h" - -#include -#include -#include "NimBLELog.h" - -class NimBLERemoteService; -class NimBLERemoteDescriptor; - - -typedef std::function notify_callback; - -typedef struct { - const NimBLEUUID *uuid; - void *task_data; -} desc_filter_t; - - -/** - * @brief A model of a remote %BLE characteristic. - */ -class NimBLERemoteCharacteristic { -public: - ~NimBLERemoteCharacteristic(); - - // Public member functions - bool canBroadcast(); - bool canIndicate(); - bool canNotify(); - bool canRead(); - bool canWrite(); - bool canWriteNoResponse(); - std::vector::iterator begin(); - std::vector::iterator end(); - NimBLERemoteDescriptor* getDescriptor(const NimBLEUUID &uuid); - std::vector* getDescriptors(bool refresh = false); - void deleteDescriptors(); - size_t deleteDescriptor(const NimBLEUUID &uuid); - uint16_t getHandle(); - uint16_t getDefHandle(); - NimBLEUUID getUUID(); - NimBLEAttValue readValue(time_t *timestamp = nullptr); - std::string toString(); - NimBLERemoteService* getRemoteService(); - - uint8_t readUInt8() __attribute__ ((deprecated("Use template readValue()"))); - uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue()"))); - uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue()"))); - float readFloat() __attribute__ ((deprecated("Use template readValue()"))); - NimBLEAttValue getValue(time_t *timestamp = nullptr); - - bool subscribe(bool notifications = true, - notify_callback notifyCallback = nullptr, - bool response = false); - bool unsubscribe(bool response = false); - bool registerForNotify(notify_callback notifyCallback, - bool notifications = true, - bool response = true) - __attribute__ ((deprecated("Use subscribe()/unsubscribe()"))); - bool writeValue(const uint8_t* data, - size_t length, - bool response = false); - bool writeValue(const std::vector& v, bool response = false); - bool writeValue(const char* s, bool response = false); - - - /*********************** Template Functions ************************/ - - /** - * @brief Template to set the remote characteristic value to val. - * @param [in] s The value to write. - * @param [in] response True == request write response. - * @details Only used for non-arrays and types without a `c_str()` method. - */ - template -#ifdef _DOXYGEN_ - bool -#else - typename std::enable_if::value && !Has_c_str_len::value, bool>::type -#endif - writeValue(const T& s, bool response = false) { - return writeValue((uint8_t*)&s, sizeof(T), response); - } - - /** - * @brief Template to set the remote characteristic value to val. - * @param [in] s The value to write. - * @param [in] response True == request write response. - * @details Only used if the has a `c_str()` method. - */ - template -#ifdef _DOXYGEN_ - bool -#else - typename std::enable_if::value, bool>::type -#endif - writeValue(const T& s, bool response = false) { - return writeValue((uint8_t*)s.c_str(), s.length(), response); - } - - /** - * @brief Template to convert the remote characteristic data to . - * @tparam T The type to convert the data to. - * @param [in] timestamp A pointer to a time_t struct to store the time the value was read. - * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof(). - * @return The data converted to or NULL if skipSizeCheck is false and the data is - * less than sizeof(). - * @details Use: getValue(×tamp, skipSizeCheck); - */ - template - T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) { - if(!skipSizeCheck && m_value.size() < sizeof(T)) return T(); - return *((T *)m_value.getValue(timestamp)); - } - - /** - * @brief Template to convert the remote characteristic data to . - * @tparam T The type to convert the data to. - * @param [in] timestamp A pointer to a time_t struct to store the time the value was read. - * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof(). - * @return The data converted to or NULL if skipSizeCheck is false and the data is - * less than sizeof(). - * @details Use: readValue(×tamp, skipSizeCheck); - */ - template - T readValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) { - NimBLEAttValue value = readValue(); - if(!skipSizeCheck && value.size() < sizeof(T)) return T(); - return *((T *)value.getValue(timestamp)); - } - -private: - - NimBLERemoteCharacteristic(NimBLERemoteService *pRemoteservice, const struct ble_gatt_chr *chr); - - friend class NimBLEClient; - friend class NimBLERemoteService; - friend class NimBLERemoteDescriptor; - - // Private member functions - bool setNotify(uint16_t val, notify_callback notifyCallback = nullptr, bool response = true); - bool retrieveDescriptors(const NimBLEUUID *uuid_filter = nullptr); - static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, void *arg); - static int onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, void *arg); - static int descriptorDiscCB(uint16_t conn_handle, const struct ble_gatt_error *error, - uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc, - void *arg); - static int nextCharCB(uint16_t conn_handle, const struct ble_gatt_error *error, - const struct ble_gatt_chr *chr, void *arg); - - // Private properties - NimBLEUUID m_uuid; - uint8_t m_charProp; - uint16_t m_handle; - uint16_t m_defHandle; - uint16_t m_endHandle; - NimBLERemoteService* m_pRemoteService; - NimBLEAttValue m_value; - notify_callback m_notifyCallback; - - // We maintain a vector of descriptors owned by this characteristic. - std::vector m_descriptorVector; -}; // NimBLERemoteCharacteristic - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ -#endif /* COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteDescriptor.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteDescriptor.cpp deleted file mode 100644 index cae910301..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteDescriptor.cpp +++ /dev/null @@ -1,365 +0,0 @@ -/* - * NimBLERemoteDescriptor.cpp - * - * Created: on Jan 27 2020 - * Author H2zero - * - * Originally: - * - * BLERemoteDescriptor.cpp - * - * Created on: Jul 8, 2017 - * Author: kolban - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) - -#include "NimBLERemoteDescriptor.h" -#include "NimBLEUtils.h" -#include "NimBLELog.h" - -#include - -static const char* LOG_TAG = "NimBLERemoteDescriptor"; - -/** - * @brief Remote descriptor constructor. - * @param [in] pRemoteCharacteristic A pointer to the Characteristic that this belongs to. - * @param [in] dsc A pointer to the struct that contains the descriptor information. - */ -NimBLERemoteDescriptor::NimBLERemoteDescriptor(NimBLERemoteCharacteristic* pRemoteCharacteristic, - const struct ble_gatt_dsc *dsc) -{ - NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteDescriptor()"); - switch (dsc->uuid.u.type) { - case BLE_UUID_TYPE_16: - m_uuid = NimBLEUUID(dsc->uuid.u16.value); - break; - case BLE_UUID_TYPE_32: - m_uuid = NimBLEUUID(dsc->uuid.u32.value); - break; - case BLE_UUID_TYPE_128: - m_uuid = NimBLEUUID(const_cast(&dsc->uuid.u128)); - break; - default: - break; - } - - m_handle = dsc->handle; - m_pRemoteCharacteristic = pRemoteCharacteristic; - - NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteDescriptor(): %s", m_uuid.toString().c_str()); -} - - -/** - * @brief Retrieve the handle associated with this remote descriptor. - * @return The handle associated with this remote descriptor. - */ -uint16_t NimBLERemoteDescriptor::getHandle() { - return m_handle; -} // getHandle - - -/** - * @brief Get the characteristic that owns this descriptor. - * @return The characteristic that owns this descriptor. - */ -NimBLERemoteCharacteristic* NimBLERemoteDescriptor::getRemoteCharacteristic() { - return m_pRemoteCharacteristic; -} // getRemoteCharacteristic - - -/** - * @brief Retrieve the UUID associated this remote descriptor. - * @return The UUID associated this remote descriptor. - */ -NimBLEUUID NimBLERemoteDescriptor::getUUID() { - return m_uuid; -} // getUUID - - -/** - * @brief Read a byte value - * @return The value as a byte - * @deprecated Use readValue(). - */ -uint8_t NimBLERemoteDescriptor::readUInt8() { - return readValue(); -} // readUInt8 - - -/** - * @brief Read an unsigned 16 bit value - * @return The unsigned 16 bit value. - * @deprecated Use readValue(). - */ -uint16_t NimBLERemoteDescriptor::readUInt16() { - return readValue(); -} // readUInt16 - - -/** - * @brief Read an unsigned 32 bit value. - * @return the unsigned 32 bit value. - * @deprecated Use readValue(). - */ -uint32_t NimBLERemoteDescriptor::readUInt32() { - return readValue(); -} // readUInt32 - - -/** - * @brief Read the value of the remote descriptor. - * @return The value of the remote descriptor. - */ -NimBLEAttValue NimBLERemoteDescriptor::readValue() { - NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str()); - - NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient(); - NimBLEAttValue value; - - if (!pClient->isConnected()) { - NIMBLE_LOGE(LOG_TAG, "Disconnected"); - return value; - } - - int rc = 0; - int retryCount = 1; - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {this, cur_task, 0, &value}; - - do { - rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0, - NimBLERemoteDescriptor::onReadCB, - &taskData); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Error: Failed to read descriptor; rc=%d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); - return value; - } - -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - rc = taskData.rc; - - switch(rc){ - case 0: - case BLE_HS_EDONE: - rc = 0; - break; - // Descriptor is not long-readable, return with what we have. - case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG): - NIMBLE_LOGI(LOG_TAG, "Attribute not long"); - rc = 0; - break; - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN): - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR): - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC): - if (retryCount && pClient->secureConnection()) - break; - /* Else falls through. */ - default: - return value; - } - } while(rc != 0 && retryCount--); - - NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %u rc=%d", value.length(), rc); - return value; -} // readValue - - -/** - * @brief Callback for Descriptor read operation. - * @return success == 0 or error code. - */ -int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, void *arg) -{ - (void)attr; - ble_task_data_t *pTaskData = (ble_task_data_t*)arg; - NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)pTaskData->pATT; - uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId(); - - if(conn_id != conn_handle){ - return 0; - } - - NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle); - - NimBLEAttValue *valBuf = (NimBLEAttValue*)pTaskData->buf; - int rc = error->status; - - if(rc == 0) { - if(attr) { - uint16_t data_len = OS_MBUF_PKTLEN(attr->om); - if((valBuf->size() + data_len) > BLE_ATT_ATTR_MAX_LEN) { - rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; - } else { - NIMBLE_LOGD(LOG_TAG, "Got %u bytes", data_len); - valBuf->append(attr->om->om_data, data_len); - return 0; - } - } - } - - pTaskData->rc = rc; - xTaskNotifyGive(pTaskData->task); - - return rc; -} - - -/** - * @brief Return a string representation of this Remote Descriptor. - * @return A string representation of this Remote Descriptor. - */ -std::string NimBLERemoteDescriptor::toString() { - std::string res = "Descriptor: uuid: " + getUUID().toString(); - char val[6]; - res += ", handle: "; - snprintf(val, sizeof(val), "%d", getHandle()); - res += val; - - return res; -} // toString - - -/** - * @brief Callback for descriptor write operation. - * @return success == 0 or error code. - */ -int NimBLERemoteDescriptor::onWriteCB(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, void *arg) -{ - ble_task_data_t *pTaskData = (ble_task_data_t*)arg; - NimBLERemoteDescriptor* descriptor = (NimBLERemoteDescriptor*)pTaskData->pATT; - - if(descriptor->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId() != conn_handle){ - return 0; - } - - NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle); - - pTaskData->rc = error->status; - xTaskNotifyGive(pTaskData->task); - - return 0; -} - - -/** - * @brief Write a new value to a remote descriptor from a std::vector. - * @param [in] vec A std::vector value to write to the remote descriptor. - * @param [in] response Whether we require a response from the write. - * @return false if not connected or otherwise cannot perform write. - */ -bool NimBLERemoteDescriptor::writeValue(const std::vector& vec, bool response) { - return writeValue((uint8_t*)&vec[0], vec.size(), response); -} // writeValue - - -/** - * @brief Write a new value to the remote descriptor from a const char*. - * @param [in] char_s A character string to write to the remote descriptor. - * @param [in] response Whether we require a response from the write. - * @return false if not connected or otherwise cannot perform write. - */ -bool NimBLERemoteDescriptor::writeValue(const char* char_s, bool response) { - return writeValue((uint8_t*)char_s, strlen(char_s), response); -} // writeValue - - -/** - * @brief Write a new value to a remote descriptor. - * @param [in] data The data to send to the remote descriptor. - * @param [in] length The length of the data to send. - * @param [in] response True if we expect a write response. - * @return false if not connected or otherwise cannot perform write. - */ -bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool response) { - - NIMBLE_LOGD(LOG_TAG, ">> Descriptor writeValue: %s", toString().c_str()); - - NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient(); - - // Check to see that we are connected. - if (!pClient->isConnected()) { - NIMBLE_LOGE(LOG_TAG, "Disconnected"); - return false; - } - - int rc = 0; - int retryCount = 1; - uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3; - - // Check if the data length is longer than we can write in 1 connection event. - // If so we must do a long write which requires a response. - if(length <= mtu && !response) { - rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length); - return (rc == 0); - } - - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {this, cur_task, 0, nullptr}; - - do { - if(length > mtu) { - NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length); - os_mbuf *om = ble_hs_mbuf_from_flat(data, length); - rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om, - NimBLERemoteDescriptor::onWriteCB, - &taskData); - } else { - rc = ble_gattc_write_flat(pClient->getConnId(), m_handle, - data, length, - NimBLERemoteDescriptor::onWriteCB, - &taskData); - } - - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Error: Failed to write descriptor; rc=%d", rc); - return false; - } - -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - rc = taskData.rc; - - switch(rc) { - case 0: - case BLE_HS_EDONE: - rc = 0; - break; - case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG): - NIMBLE_LOGE(LOG_TAG, "Long write not supported by peer; Truncating length to %d", mtu); - retryCount++; - length = mtu; - break; - - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN): - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR): - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC): - if (retryCount && pClient->secureConnection()) - break; - /* Else falls through. */ - default: - return false; - } - } while(rc != 0 && retryCount--); - - NIMBLE_LOGD(LOG_TAG, "<< Descriptor writeValue, rc: %d",rc); - return (rc == 0); -} // writeValue - - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteDescriptor.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteDescriptor.h deleted file mode 100644 index 28863df35..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteDescriptor.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * NimBLERemoteDescriptor.h - * - * Created: on Jan 27 2020 - * Author H2zero - * - * Originally: - * - * BLERemoteDescriptor.h - * - * Created on: Jul 8, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_ -#define COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) - -#include "NimBLERemoteCharacteristic.h" - -class NimBLERemoteCharacteristic; -/** - * @brief A model of remote %BLE descriptor. - */ -class NimBLERemoteDescriptor { -public: - uint16_t getHandle(); - NimBLERemoteCharacteristic* getRemoteCharacteristic(); - NimBLEUUID getUUID(); - NimBLEAttValue readValue(); - - uint8_t readUInt8() __attribute__ ((deprecated("Use template readValue()"))); - uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue()"))); - uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue()"))); - std::string toString(void); - bool writeValue(const uint8_t* data, size_t length, bool response = false); - bool writeValue(const std::vector& v, bool response = false); - bool writeValue(const char* s, bool response = false); - - - /*********************** Template Functions ************************/ - - /** - * @brief Template to set the remote descriptor value to val. - * @param [in] s The value to write. - * @param [in] response True == request write response. - * @details Only used for non-arrays and types without a `c_str()` method. - */ - template -#ifdef _DOXYGEN_ - bool -#else - typename std::enable_if::value && !Has_c_str_len::value, bool>::type -#endif - writeValue(const T& s, bool response = false) { - return writeValue((uint8_t*)&s, sizeof(T), response); - } - - /** - * @brief Template to set the remote descriptor value to val. - * @param [in] s The value to write. - * @param [in] response True == request write response. - * @details Only used if the has a `c_str()` method. - */ - template -#ifdef _DOXYGEN_ - bool -#else - typename std::enable_if::value, bool>::type -#endif - writeValue(const T& s, bool response = false) { - return writeValue((uint8_t*)s.c_str(), s.length(), response); - } - - /** - * @brief Template to convert the remote descriptor data to . - * @tparam T The type to convert the data to. - * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof(). - * @return The data converted to or NULL if skipSizeCheck is false and the data is - * less than sizeof(). - * @details Use: readValue(skipSizeCheck); - */ - template - T readValue(bool skipSizeCheck = false) { - NimBLEAttValue value = readValue(); - if(!skipSizeCheck && value.size() < sizeof(T)) return T(); - return *((T *)value.data()); - } - -private: - friend class NimBLERemoteCharacteristic; - - NimBLERemoteDescriptor (NimBLERemoteCharacteristic* pRemoteCharacteristic, - const struct ble_gatt_dsc *dsc); - static int onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, void *arg); - static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, void *arg); - - uint16_t m_handle; - NimBLEUUID m_uuid; - NimBLERemoteCharacteristic* m_pRemoteCharacteristic; -}; - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ -#endif /* COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteService.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteService.cpp deleted file mode 100644 index 5a72fe368..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteService.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* - * NimBLERemoteService.cpp - * - * Created: on Jan 27 2020 - * Author H2zero - * - * Originally: - * - * BLERemoteService.cpp - * - * Created on: Jul 8, 2017 - * Author: kolban - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) - -#include "NimBLERemoteService.h" -#include "NimBLEUtils.h" -#include "NimBLEDevice.h" -#include "NimBLELog.h" - -#include - -static const char* LOG_TAG = "NimBLERemoteService"; - -/** - * @brief Remote Service constructor. - * @param [in] pClient A pointer to the client this belongs to. - * @param [in] service A pointer to the structure with the service information. - */ -NimBLERemoteService::NimBLERemoteService(NimBLEClient* pClient, const struct ble_gatt_svc* service) { - - NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteService()"); - m_pClient = pClient; - switch (service->uuid.u.type) { - case BLE_UUID_TYPE_16: - m_uuid = NimBLEUUID(service->uuid.u16.value); - break; - case BLE_UUID_TYPE_32: - m_uuid = NimBLEUUID(service->uuid.u32.value); - break; - case BLE_UUID_TYPE_128: - m_uuid = NimBLEUUID(const_cast(&service->uuid.u128)); - break; - default: - break; - } - m_startHandle = service->start_handle; - m_endHandle = service->end_handle; - NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteService(): %s", m_uuid.toString().c_str()); -} - - -/** - * @brief When deleting the service make sure we delete all characteristics and descriptors. - */ -NimBLERemoteService::~NimBLERemoteService() { - deleteCharacteristics(); -} - - -/** - * @brief Get iterator to the beginning of the vector of remote characteristic pointers. - * @return An iterator to the beginning of the vector of remote characteristic pointers. - */ -std::vector::iterator NimBLERemoteService::begin() { - return m_characteristicVector.begin(); -} - - -/** - * @brief Get iterator to the end of the vector of remote characteristic pointers. - * @return An iterator to the end of the vector of remote characteristic pointers. - */ -std::vector::iterator NimBLERemoteService::end() { - return m_characteristicVector.end(); -} - - -/** - * @brief Get the remote characteristic object for the characteristic UUID. - * @param [in] uuid Remote characteristic uuid. - * @return A pointer to the remote characteristic object. - */ -NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const char* uuid) { - return getCharacteristic(NimBLEUUID(uuid)); -} // getCharacteristic - - -/** - * @brief Get the characteristic object for the UUID. - * @param [in] uuid Characteristic uuid. - * @return A pointer to the characteristic object, or nullptr if not found. - */ -NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEUUID &uuid) { - NIMBLE_LOGD(LOG_TAG, ">> getCharacteristic: uuid: %s", uuid.toString().c_str()); - - for(auto &it: m_characteristicVector) { - if(it->getUUID() == uuid) { - NIMBLE_LOGD(LOG_TAG, "<< getCharacteristic: found the characteristic with uuid: %s", uuid.toString().c_str()); - return it; - } - } - - size_t prev_size = m_characteristicVector.size(); - if(retrieveCharacteristics(&uuid)) { - if(m_characteristicVector.size() > prev_size) { - return m_characteristicVector.back(); - } - - // If the request was successful but 16/32 bit uuid not found - // try again with the 128 bit uuid. - if(uuid.bitSize() == BLE_UUID_TYPE_16 || - uuid.bitSize() == BLE_UUID_TYPE_32) - { - NimBLEUUID uuid128(uuid); - uuid128.to128(); - if (retrieveCharacteristics(&uuid128)) { - if(m_characteristicVector.size() > prev_size) { - return m_characteristicVector.back(); - } - } - } else { - // If the request was successful but the 128 bit uuid not found - // try again with the 16 bit uuid. - NimBLEUUID uuid16(uuid); - uuid16.to16(); - // if the uuid was 128 bit but not of the BLE base type this check will fail - if (uuid16.bitSize() == BLE_UUID_TYPE_16) { - if(retrieveCharacteristics(&uuid16)) { - if(m_characteristicVector.size() > prev_size) { - return m_characteristicVector.back(); - } - } - } - } - } - - NIMBLE_LOGD(LOG_TAG, "<< getCharacteristic: not found"); - return nullptr; -} // getCharacteristic - - -/** - * @brief Get a pointer to the vector of found characteristics. - * @param [in] refresh If true the current characteristics vector will cleared and - * all characteristics for this service retrieved from the peripheral. - * If false the vector will be returned with the currently stored characteristics of this service. - * @return A pointer to the vector of descriptors for this characteristic. - */ -std::vector* NimBLERemoteService::getCharacteristics(bool refresh) { - if(refresh) { - deleteCharacteristics(); - - if (!retrieveCharacteristics()) { - NIMBLE_LOGE(LOG_TAG, "Error: Failed to get characteristics"); - } - else{ - NIMBLE_LOGI(LOG_TAG, "Found %d characteristics", m_characteristicVector.size()); - } - } - return &m_characteristicVector; -} // getCharacteristics - - -/** - * @brief Callback for Characteristic discovery. - * @return success == 0 or error code. - */ -int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_chr *chr, void *arg) -{ - NIMBLE_LOGD(LOG_TAG,"Characteristic Discovered >> status: %d handle: %d", - error->status, (error->status == 0) ? chr->val_handle : -1); - - ble_task_data_t *pTaskData = (ble_task_data_t*)arg; - NimBLERemoteService *service = (NimBLERemoteService*)pTaskData->pATT; - - // Make sure the discovery is for this device - if(service->getClient()->getConnId() != conn_handle){ - return 0; - } - - if(error->status == 0) { - // Found a service - add it to the vector - NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr); - service->m_characteristicVector.push_back(pRemoteCharacteristic); - return 0; - } - - if(error->status == BLE_HS_EDONE) { - pTaskData->rc = 0; - } else { - NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s", - error->status, - NimBLEUtils::returnCodeToString(error->status)); - pTaskData->rc = error->status; - } - - xTaskNotifyGive(pTaskData->task); - - NIMBLE_LOGD(LOG_TAG,"<< Characteristic Discovered"); - return error->status; -} - - -/** - * @brief Retrieve all the characteristics for this service. - * This function will not return until we have all the characteristics. - * @return True if successful. - */ -bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter) { - NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str()); - - int rc = 0; - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {this, cur_task, 0, nullptr}; - - if(uuid_filter == nullptr) { - rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(), - m_startHandle, - m_endHandle, - NimBLERemoteService::characteristicDiscCB, - &taskData); - } else { - rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnId(), - m_startHandle, - m_endHandle, - &uuid_filter->getNative()->u, - NimBLERemoteService::characteristicDiscCB, - &taskData); - } - - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); - return false; - } - -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - - if(taskData.rc == 0){ - if (uuid_filter == nullptr) { - if (m_characteristicVector.size() > 1) { - for (auto it = m_characteristicVector.begin(); it != m_characteristicVector.end(); ++it ) { - auto nx = std::next(it, 1); - if (nx == m_characteristicVector.end()) { - break; - } - (*it)->m_endHandle = (*nx)->m_defHandle - 1; - } - } - - if (m_characteristicVector.size() > 0) { - m_characteristicVector.back()->m_endHandle = getEndHandle(); - } - } - - NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()"); - return true; - } - - NIMBLE_LOGE(LOG_TAG, "Could not retrieve characteristics"); - return false; - -} // retrieveCharacteristics - - -/** - * @brief Get the client associated with this service. - * @return A reference to the client associated with this service. - */ -NimBLEClient* NimBLERemoteService::getClient() { - return m_pClient; -} // getClient - - -/** - * @brief Get the service end handle. - */ -uint16_t NimBLERemoteService::getEndHandle() { - return m_endHandle; -} // getEndHandle - - -/** - * @brief Get the service start handle. - */ -uint16_t NimBLERemoteService::getStartHandle() { - return m_startHandle; -} // getStartHandle - - -/** - * @brief Get the service UUID. - */ -NimBLEUUID NimBLERemoteService::getUUID() { - return m_uuid; -} - - -/** - * @brief Read the value of a characteristic associated with this service. - * @param [in] characteristicUuid The characteristic to read. - * @returns a string containing the value or an empty string if not found or error. - */ -std::string NimBLERemoteService::getValue(const NimBLEUUID &characteristicUuid) { - NIMBLE_LOGD(LOG_TAG, ">> readValue: uuid: %s", characteristicUuid.toString().c_str()); - - std::string ret = ""; - NimBLERemoteCharacteristic* pChar = getCharacteristic(characteristicUuid); - - if(pChar != nullptr) { - ret = pChar->readValue(); - } - - NIMBLE_LOGD(LOG_TAG, "<< readValue"); - return ret; -} // readValue - - -/** - * @brief Set the value of a characteristic. - * @param [in] characteristicUuid The characteristic to set. - * @param [in] value The value to set. - * @returns true on success, false if not found or error - */ -bool NimBLERemoteService::setValue(const NimBLEUUID &characteristicUuid, const std::string &value) { - NIMBLE_LOGD(LOG_TAG, ">> setValue: uuid: %s", characteristicUuid.toString().c_str()); - - bool ret = false; - NimBLERemoteCharacteristic* pChar = getCharacteristic(characteristicUuid); - - if(pChar != nullptr) { - ret = pChar->writeValue(value); - } - - NIMBLE_LOGD(LOG_TAG, "<< setValue"); - return ret; -} // setValue - - -/** - * @brief Delete the characteristics in the characteristics vector. - * @details We maintain a vector called m_characteristicsVector that contains pointers to BLERemoteCharacteristic - * object references. Since we allocated these in this class, we are also responsible for deleting - * them. This method does just that. - */ -void NimBLERemoteService::deleteCharacteristics() { - NIMBLE_LOGD(LOG_TAG, ">> deleteCharacteristics"); - for(auto &it: m_characteristicVector) { - delete it; - } - m_characteristicVector.clear(); - NIMBLE_LOGD(LOG_TAG, "<< deleteCharacteristics"); -} // deleteCharacteristics - - -/** - * @brief Delete characteristic by UUID - * @param [in] uuid The UUID of the characteristic to be removed from the local database. - * @return Number of characteristics left. - */ -size_t NimBLERemoteService::deleteCharacteristic(const NimBLEUUID &uuid) { - NIMBLE_LOGD(LOG_TAG, ">> deleteCharacteristic"); - - for(auto it = m_characteristicVector.begin(); it != m_characteristicVector.end(); ++it) { - if((*it)->getUUID() == uuid) { - delete *it; - m_characteristicVector.erase(it); - break; - } - } - - NIMBLE_LOGD(LOG_TAG, "<< deleteCharacteristic"); - - return m_characteristicVector.size(); -} // deleteCharacteristic - - -/** - * @brief Create a string representation of this remote service. - * @return A string representation of this remote service. - */ -std::string NimBLERemoteService::toString() { - std::string res = "Service: uuid: " + m_uuid.toString(); - char val[6]; - res += ", start_handle: "; - snprintf(val, sizeof(val), "%d", m_startHandle); - res += val; - snprintf(val, sizeof(val), "%04x", m_startHandle); - res += " 0x"; - res += val; - res += ", end_handle: "; - snprintf(val, sizeof(val), "%d", m_endHandle); - res += val; - snprintf(val, sizeof(val), "%04x", m_endHandle); - res += " 0x"; - res += val; - - for (auto &it: m_characteristicVector) { - res += "\n" + it->toString(); - } - - return res; -} // toString - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteService.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteService.h deleted file mode 100644 index 0443cfd99..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteService.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * NimBLERemoteService.h - * - * Created: on Jan 27 2020 - * Author H2zero - * - * Originally: - * - * BLERemoteService.h - * - * Created on: Jul 8, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_NIMBLEREMOTESERVICE_H_ -#define COMPONENTS_NIMBLEREMOTESERVICE_H_ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) - -#include "NimBLEClient.h" -#include "NimBLEUUID.h" -#include "NimBLERemoteCharacteristic.h" - -#include - -class NimBLEClient; -class NimBLERemoteCharacteristic; - - -/** - * @brief A model of a remote %BLE service. - */ -class NimBLERemoteService { -public: - virtual ~NimBLERemoteService(); - - // Public methods - std::vector::iterator begin(); - std::vector::iterator end(); - NimBLERemoteCharacteristic* getCharacteristic(const char* uuid); - NimBLERemoteCharacteristic* getCharacteristic(const NimBLEUUID &uuid); - void deleteCharacteristics(); - size_t deleteCharacteristic(const NimBLEUUID &uuid); - NimBLEClient* getClient(void); - //uint16_t getHandle(); - NimBLEUUID getUUID(void); - std::string getValue(const NimBLEUUID &characteristicUuid); - bool setValue(const NimBLEUUID &characteristicUuid, - const std::string &value); - std::string toString(void); - std::vector* getCharacteristics(bool refresh = false); - -private: - // Private constructor ... never meant to be created by a user application. - NimBLERemoteService(NimBLEClient* pClient, const struct ble_gatt_svc *service); - - // Friends - friend class NimBLEClient; - friend class NimBLERemoteCharacteristic; - - // Private methods - bool retrieveCharacteristics(const NimBLEUUID *uuid_filter = nullptr); - static int characteristicDiscCB(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_chr *chr, - void *arg); - - uint16_t getStartHandle(); - uint16_t getEndHandle(); - void releaseSemaphores(); - - // Properties - - // We maintain a vector of characteristics owned by this service. - std::vector m_characteristicVector; - - NimBLEClient* m_pClient; - NimBLEUUID m_uuid; - uint16_t m_startHandle; - uint16_t m_endHandle; -}; // NimBLERemoteService - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ -#endif /* COMPONENTS_NIMBLEREMOTESERVICE_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEScan.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEScan.cpp deleted file mode 100644 index d1c4879be..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEScan.cpp +++ /dev/null @@ -1,585 +0,0 @@ -/* - * NimBLEScan.cpp - * - * Created: on Jan 24 2020 - * Author H2zero - * - * Originally: - * - * BLEScan.cpp - * - * Created on: Jul 1, 2017 - * Author: kolban - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) - -#include "NimBLEScan.h" -#include "NimBLEDevice.h" -#include "NimBLELog.h" - -#include -#include - -static const char* LOG_TAG = "NimBLEScan"; - - -/** - * @brief Scan constuctor. - */ -NimBLEScan::NimBLEScan() { - m_scan_params.filter_policy = BLE_HCI_SCAN_FILT_NO_WL; - m_scan_params.passive = 1; // If set, don’t send scan requests to advertisers (i.e., don’t request additional advertising data). - m_scan_params.itvl = 0; // This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan. (units=0.625 msec) - m_scan_params.window = 0; // The duration of the LE scan. LE_Scan_Window shall be less than or equal to LE_Scan_Interval (units=0.625 msec) - m_scan_params.limited = 0; // If set, only discover devices in limited discoverable mode. - m_scan_params.filter_duplicates = 1; // If set, the controller ignores all but the first advertisement from each device. - m_pAdvertisedDeviceCallbacks = nullptr; - m_ignoreResults = false; - m_pTaskData = nullptr; - m_duration = BLE_HS_FOREVER; // make sure this is non-zero in the event of a host reset - m_maxResults = 0xFF; -} - - -/** - * @brief Scan destructor, release any allocated resources. - */ -NimBLEScan::~NimBLEScan() { - clearResults(); -} - -/** - * @brief Handle GAP events related to scans. - * @param [in] event The event type for this event. - * @param [in] param Parameter data for this event. - */ -/*STATIC*/int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) { - (void)arg; - NimBLEScan* pScan = NimBLEDevice::getScan(); - - switch(event->type) { - - case BLE_GAP_EVENT_EXT_DISC: - case BLE_GAP_EVENT_DISC: { - if(pScan->m_ignoreResults) { - NIMBLE_LOGI(LOG_TAG, "Scan op in progress - ignoring results"); - return 0; - } -#if CONFIG_BT_NIMBLE_EXT_ADV - const auto& disc = event->ext_disc; - const bool isLegacyAdv = disc.props & BLE_HCI_ADV_LEGACY_MASK; - const auto event_type = isLegacyAdv ? disc.legacy_event_type : disc.props; -#else - const auto& disc = event->disc; - const bool isLegacyAdv = true; - const auto event_type = disc.event_type; -#endif - NimBLEAddress advertisedAddress(disc.addr); - - // Examine our list of ignored addresses and stop processing if we don't want to see it or are already connected - if(NimBLEDevice::isIgnored(advertisedAddress)) { - NIMBLE_LOGI(LOG_TAG, "Ignoring device: address: %s", advertisedAddress.toString().c_str()); - return 0; - } - - NimBLEAdvertisedDevice* advertisedDevice = nullptr; - - // If we've seen this device before get a pointer to it from the vector - for(auto &it: pScan->m_scanResults.m_advertisedDevicesVector) { -#if CONFIG_BT_NIMBLE_EXT_ADV - // Same address but different set ID should create a new advertised device. - if (it->getAddress() == advertisedAddress && it->getSetId() == disc.sid) { -#else - if (it->getAddress() == advertisedAddress) { -#endif - advertisedDevice = it; - break; - } - } - - // If we haven't seen this device before; create a new instance and insert it in the vector. - // Otherwise just update the relevant parameters of the already known device. - if (advertisedDevice == nullptr && - (!isLegacyAdv || event_type != BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP)) { - // Check if we have reach the scan results limit, ignore this one if so. - // We still need to store each device when maxResults is 0 to be able to append the scan results - if (pScan->m_maxResults > 0 && pScan->m_maxResults < 0xFF && - (pScan->m_scanResults.m_advertisedDevicesVector.size() >= pScan->m_maxResults)) { - return 0; - } - - advertisedDevice = new NimBLEAdvertisedDevice(); - advertisedDevice->setAddress(advertisedAddress); - advertisedDevice->setAdvType(event_type, isLegacyAdv); -#if CONFIG_BT_NIMBLE_EXT_ADV - advertisedDevice->setSetId(disc.sid); - advertisedDevice->setPrimaryPhy(disc.prim_phy); - advertisedDevice->setSecondaryPhy(disc.sec_phy); - advertisedDevice->setPeriodicInterval(disc.periodic_adv_itvl); -#endif - pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice); - NIMBLE_LOGI(LOG_TAG, "New advertiser: %s", advertisedAddress.toString().c_str()); - } else if (advertisedDevice != nullptr) { - NIMBLE_LOGI(LOG_TAG, "Updated advertiser: %s", advertisedAddress.toString().c_str()); - } else { - // Scan response from unknown device - return 0; - } - - advertisedDevice->m_timestamp = time(nullptr); - advertisedDevice->setRSSI(disc.rssi); - advertisedDevice->setPayload(disc.data, disc.length_data, (isLegacyAdv && - event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP)); - - if (pScan->m_pAdvertisedDeviceCallbacks) { - if (pScan->m_scan_params.filter_duplicates && advertisedDevice->m_callbackSent) { - return 0; - } - - // If not active scanning or scan response is not available - // or extended advertisement scanning, report the result to the callback now. - if(pScan->m_scan_params.passive || !isLegacyAdv || - (advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_IND && - advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_SCAN_IND)) - { - advertisedDevice->m_callbackSent = true; - pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); - - // Otherwise, wait for the scan response so we can report the complete data. - } else if (isLegacyAdv && event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) { - advertisedDevice->m_callbackSent = true; - pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); - } - // If not storing results and we have invoked the callback, delete the device. - if(pScan->m_maxResults == 0 && advertisedDevice->m_callbackSent) { - pScan->erase(advertisedAddress); - } - } - - return 0; - } - case BLE_GAP_EVENT_DISC_COMPLETE: { - NIMBLE_LOGD(LOG_TAG, "discovery complete; reason=%d", - event->disc_complete.reason); - - // If a device advertised with scan response available and it was not received - // the callback would not have been invoked, so do it here. - if(pScan->m_pAdvertisedDeviceCallbacks) { - for(auto &it : pScan->m_scanResults.m_advertisedDevicesVector) { - if(!it->m_callbackSent) { - pScan->m_pAdvertisedDeviceCallbacks->onResult(it); - } - } - } - - if(pScan->m_maxResults == 0) { - pScan->clearResults(); - } - - if (pScan->m_scanCompleteCB != nullptr) { - pScan->m_scanCompleteCB(pScan->m_scanResults); - } - - if(pScan->m_pTaskData != nullptr) { - pScan->m_pTaskData->rc = event->disc_complete.reason; - xTaskNotifyGive(pScan->m_pTaskData->task); - } - - return 0; - } - - default: - return 0; - } -} // gapEventHandler - - -/** - * @brief Should we perform an active or passive scan? - * The default is a passive scan. An active scan means that we will request a scan response. - * @param [in] active If true, we perform an active scan otherwise a passive scan. - */ -void NimBLEScan::setActiveScan(bool active) { - m_scan_params.passive = !active; -} // setActiveScan - - -/** - * @brief Set whether or not the BLE controller should only report results - * from devices it has not already seen. - * @param [in] enabled If true, scanned devices will only be reported once. - * @details The controller has a limited buffer and will start reporting - * duplicate devices once the limit is reached. - */ -void NimBLEScan::setDuplicateFilter(bool enabled) { - m_scan_params.filter_duplicates = enabled; -} // setDuplicateFilter - - -/** - * @brief Set whether or not the BLE controller only report scan results - * from devices advertising in limited discovery mode, i.e. directed advertising. - * @param [in] enabled If true, only limited discovery devices will be in scan results. - */ -void NimBLEScan::setLimitedOnly(bool enabled) { - m_scan_params.limited = enabled; -} // setLimited - - -/** - * @brief Sets the scan filter policy. - * @param [in] filter Can be one of: - * * BLE_HCI_SCAN_FILT_NO_WL (0) - * Scanner processes all advertising packets (white list not used) except\n - * directed, connectable advertising packets not sent to the scanner. - * * BLE_HCI_SCAN_FILT_USE_WL (1) - * Scanner processes advertisements from white list only. A connectable,\n - * directed advertisement is ignored unless it contains scanners address. - * * BLE_HCI_SCAN_FILT_NO_WL_INITA (2) - * Scanner process all advertising packets (white list not used). A\n - * connectable, directed advertisement shall not be ignored if the InitA - * is a resolvable private address. - * * BLE_HCI_SCAN_FILT_USE_WL_INITA (3) - * Scanner process advertisements from white list only. A connectable,\n - * directed advertisement shall not be ignored if the InitA is a - * resolvable private address. - */ -void NimBLEScan::setFilterPolicy(uint8_t filter) { - m_scan_params.filter_policy = filter; -} // setFilterPolicy - - -/** - * @brief Sets the max number of results to store. - * @param [in] maxResults The number of results to limit storage to\n - * 0 == none (callbacks only) 0xFF == unlimited, any other value is the limit. - */ -void NimBLEScan::setMaxResults(uint8_t maxResults) { - m_maxResults = maxResults; -} - - -/** - * @brief Set the call backs to be invoked. - * @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked. - * @param [in] wantDuplicates True if we wish to be called back with duplicates. Default is false. - */ -void NimBLEScan::setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, - bool wantDuplicates) { - setDuplicateFilter(!wantDuplicates); - m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks; -} // setAdvertisedDeviceCallbacks - - -/** - * @brief Set the interval to scan. - * @param [in] intervalMSecs The scan interval (how often) in milliseconds. - */ -void NimBLEScan::setInterval(uint16_t intervalMSecs) { - m_scan_params.itvl = intervalMSecs / 0.625; -} // setInterval - - -/** - * @brief Set the window to actively scan. - * @param [in] windowMSecs How long to actively scan. - */ -void NimBLEScan::setWindow(uint16_t windowMSecs) { - m_scan_params.window = windowMSecs / 0.625; -} // setWindow - - -/** - * @brief Get the status of the scanner. - * @return true if scanning or scan starting. - */ -bool NimBLEScan::isScanning() { - return ble_gap_disc_active(); -} - - -/** - * @brief Start scanning. - * @param [in] duration The duration in seconds for which to scan. - * @param [in] scanCompleteCB A function to be called when scanning has completed. - * @param [in] is_continue Set to true to save previous scan results, false to clear them. - * @return True if scan started or false if there was an error. - */ -bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue) { - NIMBLE_LOGD(LOG_TAG, ">> start: duration=%" PRIu32, duration); - - // Save the callback to be invoked when the scan completes. - m_scanCompleteCB = scanCompleteCB; - // Save the duration in the case that the host is reset so we can reuse it. - m_duration = duration; - - // If 0 duration specified then we assume a continuous scan is desired. - if(duration == 0){ - duration = BLE_HS_FOREVER; - } - else{ - // convert duration to milliseconds - duration = duration * 1000; - } - - // Set the flag to ignore the results while we are deleting the vector - if(!is_continue) { - m_ignoreResults = true; - } - -# if CONFIG_BT_NIMBLE_EXT_ADV - ble_gap_ext_disc_params scan_params; - scan_params.passive = m_scan_params.passive; - scan_params.itvl = m_scan_params.itvl; - scan_params.window = m_scan_params.window; - int rc = ble_gap_ext_disc(NimBLEDevice::m_own_addr_type, - duration/10, - 0, - m_scan_params.filter_duplicates, - m_scan_params.filter_policy, - m_scan_params.limited, - &scan_params, - &scan_params, - NimBLEScan::handleGapEvent, - NULL); -#else - int rc = ble_gap_disc(NimBLEDevice::m_own_addr_type, - duration, - &m_scan_params, - NimBLEScan::handleGapEvent, - NULL); -#endif - switch(rc) { - case 0: - if(!is_continue) { - clearResults(); - } - break; - - case BLE_HS_EALREADY: - // Clear the cache if already scanning in case an advertiser was missed. - clearDuplicateCache(); - break; - - case BLE_HS_EBUSY: - NIMBLE_LOGE(LOG_TAG, "Unable to scan - connection in progress."); - break; - - case BLE_HS_ETIMEOUT_HCI: - case BLE_HS_EOS: - case BLE_HS_ECONTROLLER: - case BLE_HS_ENOTSYNCED: - NIMBLE_LOGC(LOG_TAG, "Unable to scan - Host Reset"); - break; - - default: - NIMBLE_LOGE(LOG_TAG, "Error initiating GAP discovery procedure; rc=%d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); - break; - } - - m_ignoreResults = false; - NIMBLE_LOGD(LOG_TAG, "<< start()"); - - if(rc != 0 && rc != BLE_HS_EALREADY) { - return false; - } - return true; -} // start - - -/** - * @brief Start scanning and block until scanning has been completed. - * @param [in] duration The duration in seconds for which to scan. - * @param [in] is_continue Set to true to save previous scan results, false to clear them. - * @return The NimBLEScanResults. - */ -NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) { - if(duration == 0) { - NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever"); - } - - TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); - ble_task_data_t taskData = {nullptr, cur_task, 0, nullptr}; - m_pTaskData = &taskData; - - if(start(duration, nullptr, is_continue)) { -#ifdef ulTaskNotifyValueClear - // Clear the task notification value to ensure we block - ulTaskNotifyValueClear(cur_task, ULONG_MAX); -#endif - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - } - - m_pTaskData = nullptr; - return m_scanResults; -} // start - - -/** - * @brief Stop an in progress scan. - * @return True if successful. - */ -bool NimBLEScan::stop() { - NIMBLE_LOGD(LOG_TAG, ">> stop()"); - - int rc = ble_gap_disc_cancel(); - if (rc != 0 && rc != BLE_HS_EALREADY) { - NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d", rc); - return false; - } - - if(m_maxResults == 0) { - clearResults(); - } - - if (rc != BLE_HS_EALREADY && m_scanCompleteCB != nullptr) { - m_scanCompleteCB(m_scanResults); - } - - if(m_pTaskData != nullptr) { - xTaskNotifyGive(m_pTaskData->task); - } - - NIMBLE_LOGD(LOG_TAG, "<< stop()"); - return true; -} // stop - - -/** - * @brief Clears the duplicate scan filter cache. - */ -void NimBLEScan::clearDuplicateCache() { -#ifdef CONFIG_IDF_TARGET_ESP32 // Not available for ESP32C3 - esp_ble_scan_dupilcate_list_flush(); -#endif -} - - -/** - * @brief Delete peer device from the scan results vector. - * @param [in] address The address of the device to delete from the results. - * @details After disconnecting, it may be required in the case we were connected to a device without a public address. - */ -void NimBLEScan::erase(const NimBLEAddress &address) { - NIMBLE_LOGD(LOG_TAG, "erase device: %s", address.toString().c_str()); - - for(auto it = m_scanResults.m_advertisedDevicesVector.begin(); it != m_scanResults.m_advertisedDevicesVector.end(); ++it) { - if((*it)->getAddress() == address) { - delete *it; - m_scanResults.m_advertisedDevicesVector.erase(it); - break; - } - } -} - - -/** - * @brief Called when host reset, we set a flag to stop scanning until synced. - */ -void NimBLEScan::onHostReset() { - m_ignoreResults = true; -} - - -/** - * @brief If the host reset and re-synced this is called. - * If the application was scanning indefinitely with a callback, restart it. - */ -void NimBLEScan::onHostSync() { - m_ignoreResults = false; - - if(m_duration == 0 && m_pAdvertisedDeviceCallbacks != nullptr) { - start(m_duration, m_scanCompleteCB); - } -} - -/** - * @brief Get the results of the scan. - * @return NimBLEScanResults object. - */ -NimBLEScanResults NimBLEScan::getResults() { - return m_scanResults; -} - - -/** - * @brief Clear the results of the scan. - */ -void NimBLEScan::clearResults() { - for(auto &it: m_scanResults.m_advertisedDevicesVector) { - delete it; - } - m_scanResults.m_advertisedDevicesVector.clear(); - clearDuplicateCache(); -} - - -/** - * @brief Dump the scan results to the log. - */ -void NimBLEScanResults::dump() { - NIMBLE_LOGD(LOG_TAG, ">> Dump scan results:"); - for (int i=0; i::iterator NimBLEScanResults::begin() { - return m_advertisedDevicesVector.begin(); -} - - -/** - * @brief Get iterator to the end of the vector of advertised device pointers. - * @return An iterator to the end of the vector of advertised device pointers. - */ -std::vector::iterator NimBLEScanResults::end() { - return m_advertisedDevicesVector.end(); -} - - -/** - * @brief Get a pointer to the specified device at the given address. - * If the address is not found a nullptr is returned. - * @param [in] address The address of the device. - * @return A pointer to the device at the specified address. - */ -NimBLEAdvertisedDevice *NimBLEScanResults::getDevice(const NimBLEAddress &address) { - for(size_t index = 0; index < m_advertisedDevicesVector.size(); index++) { - if(m_advertisedDevicesVector[index]->getAddress() == address) { - return m_advertisedDevicesVector[index]; - } - } - - return nullptr; -} - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEScan.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEScan.h deleted file mode 100644 index 76a114276..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEScan.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * NimBLEScan.h - * - * Created: on Jan 24 2020 - * Author H2zero - * - * Originally: - * - * BLEScan.h - * - * Created on: Jul 1, 2017 - * Author: kolban - */ -#ifndef COMPONENTS_NIMBLE_SCAN_H_ -#define COMPONENTS_NIMBLE_SCAN_H_ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) - -#include "NimBLEAdvertisedDevice.h" -#include "NimBLEUtils.h" - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "host/ble_gap.h" -#else -#include "nimble/nimble/host/include/host/ble_gap.h" -#endif - -#include - -class NimBLEDevice; -class NimBLEScan; -class NimBLEAdvertisedDevice; -class NimBLEAdvertisedDeviceCallbacks; -class NimBLEAddress; - -/** - * @brief A class that contains and operates on the results of a BLE scan. - * @details When a scan completes, we have a set of found devices. Each device is described - * by a NimBLEAdvertisedDevice object. The number of items in the set is given by - * getCount(). We can retrieve a device by calling getDevice() passing in the - * index (starting at 0) of the desired device. - */ -class NimBLEScanResults { -public: - void dump(); - int getCount(); - NimBLEAdvertisedDevice getDevice(uint32_t i); - std::vector::iterator begin(); - std::vector::iterator end(); - NimBLEAdvertisedDevice *getDevice(const NimBLEAddress &address); - -private: - friend NimBLEScan; - std::vector m_advertisedDevicesVector; -}; - -/** - * @brief Perform and manage %BLE scans. - * - * Scanning is associated with a %BLE client that is attempting to locate BLE servers. - */ -class NimBLEScan { -public: - bool start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue = false); - NimBLEScanResults start(uint32_t duration, bool is_continue = false); - bool isScanning(); - void setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates = false); - void setActiveScan(bool active); - void setInterval(uint16_t intervalMSecs); - void setWindow(uint16_t windowMSecs); - void setDuplicateFilter(bool enabled); - void setLimitedOnly(bool enabled); - void setFilterPolicy(uint8_t filter); - void clearDuplicateCache(); - bool stop(); - void clearResults(); - NimBLEScanResults getResults(); - void setMaxResults(uint8_t maxResults); - void erase(const NimBLEAddress &address); - - -private: - friend class NimBLEDevice; - - NimBLEScan(); - ~NimBLEScan(); - static int handleGapEvent(ble_gap_event* event, void* arg); - void onHostReset(); - void onHostSync(); - - NimBLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks = nullptr; - void (*m_scanCompleteCB)(NimBLEScanResults scanResults); - ble_gap_disc_params m_scan_params; - bool m_ignoreResults; - NimBLEScanResults m_scanResults; - uint32_t m_duration; - ble_task_data_t *m_pTaskData; - uint8_t m_maxResults; -}; - -#endif /* CONFIG_BT_ENABLED CONFIG_BT_NIMBLE_ROLE_OBSERVER */ -#endif /* COMPONENTS_NIMBLE_SCAN_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLESecurity.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLESecurity.cpp deleted file mode 100644 index 0a0b72ba3..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLESecurity.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * NimBLESecurity.cpp - * - * Created: on Feb 22 2020 - * Author H2zero - * - * Originally: - * - * BLESecurity.cpp - * - * Created on: Dec 17, 2017 - * Author: chegewara - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "NimBLESecurity.h" -#include "NimBLEDevice.h" - -NimBLESecurity::NimBLESecurity() { -} - -NimBLESecurity::~NimBLESecurity() { -} - - -/** - * @brief Set requested authentication mode - * @param [in] auth_req A bitmask containing one or more of: - * * ESP_LE_AUTH_NO_BOND 0x00 - * * ESP_LE_AUTH_BOND 0x01 - * * ESP_LE_AUTH_REQ_MITM (1 << 2) - * * ESP_LE_AUTH_REQ_BOND_MITM (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_MITM) - * * ESP_LE_AUTH_REQ_SC_ONLY (1 << 3) - * * ESP_LE_AUTH_REQ_SC_BOND (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_SC_ONLY) - * * ESP_LE_AUTH_REQ_SC_MITM (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY) - * * ESP_LE_AUTH_REQ_SC_MITM_BOND (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY | ESP_LE_AUTH_BOND) - */ -void NimBLESecurity::setAuthenticationMode(esp_ble_auth_req_t auth_req) { - NimBLEDevice::setSecurityAuth((auth_req & BLE_SM_PAIR_AUTHREQ_BOND)>0, - (auth_req & BLE_SM_PAIR_AUTHREQ_MITM)>0, - (auth_req & BLE_SM_PAIR_AUTHREQ_SC)>0); -} - - -/** - * @brief Set our device IO capability to let end user perform authorization - * either by displaying or entering generated 6-digit pin code or use \"just works\". - * @param [in] iocap The IO capabilites our device has.\n - * Can be set to one of: - * * ESP_IO_CAP_OUT 0 - * * ESP_IO_CAP_IO 1 - * * ESP_IO_CAP_IN 2 - * * ESP_IO_CAP_NONE 3 - * * ESP_IO_CAP_KBDISP 4 - */ -void NimBLESecurity::setCapability(esp_ble_io_cap_t iocap) { - NimBLEDevice::setSecurityIOCap(iocap); -} // setCapability - - -/** - * @brief Sets the keys we will distribute during encryption. - * @param [in] init_key A bitmask of the keys we will distribute.\n - * Can be one or more of: - * * ESP_BLE_ENC_KEY_MASK (1 << 0) - * * ESP_BLE_ID_KEY_MASK (1 << 1) - * * ESP_BLE_CSR_KEY_MASK (1 << 2) - * * ESP_BLE_LINK_KEY_MASK (1 << 3) - */ -void NimBLESecurity::setInitEncryptionKey(uint8_t init_key) { - NimBLEDevice::setSecurityInitKey(init_key); -} // setInitEncryptionKey - - -/** - * @brief Sets the keys we will accept during encryption. - * @param [in] resp_key A bitmask of the keys we will accept.\n - * Can be one or more of: - * * ESP_BLE_ENC_KEY_MASK (1 << 0) - * * ESP_BLE_ID_KEY_MASK (1 << 1) - * * ESP_BLE_CSR_KEY_MASK (1 << 2) - * * ESP_BLE_LINK_KEY_MASK (1 << 3) - */ -void NimBLESecurity::setRespEncryptionKey(uint8_t resp_key) { - NimBLEDevice::setSecurityRespKey(resp_key); -} // setRespEncryptionKey - - -/** - *@todo Requires implementation - */ -void NimBLESecurity::setKeySize(uint8_t key_size) { - - //m_keySize = key_size; - //esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &m_keySize, sizeof(uint8_t)); -} //setKeySize - - -/** - * @brief Sets a static PIN used to authenticate/encrypt the connection. - * @param [in] pin The 6 digit pin code to accept. - */ -void NimBLESecurity::setStaticPIN(uint32_t pin){ - //uint32_t passkey = pin; - //esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t)); - NimBLEDevice::setSecurityPasskey(pin); - setCapability(ESP_IO_CAP_OUT); - setKeySize(); - setAuthenticationMode(ESP_LE_AUTH_REQ_SC_ONLY); - setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); -} - - -/** - * @brief Debug function to display what keys are exchanged by peers - */ - /* -char* BLESecurity::esp_key_type_to_str(esp_ble_key_type_t key_type) { - char* key_str = nullptr; - switch (key_type) { - case ESP_LE_KEY_NONE: - key_str = (char*) "ESP_LE_KEY_NONE"; - break; - case ESP_LE_KEY_PENC: - key_str = (char*) "ESP_LE_KEY_PENC"; - break; - case ESP_LE_KEY_PID: - key_str = (char*) "ESP_LE_KEY_PID"; - break; - case ESP_LE_KEY_PCSRK: - key_str = (char*) "ESP_LE_KEY_PCSRK"; - break; - case ESP_LE_KEY_PLK: - key_str = (char*) "ESP_LE_KEY_PLK"; - break; - case ESP_LE_KEY_LLK: - key_str = (char*) "ESP_LE_KEY_LLK"; - break; - case ESP_LE_KEY_LENC: - key_str = (char*) "ESP_LE_KEY_LENC"; - break; - case ESP_LE_KEY_LID: - key_str = (char*) "ESP_LE_KEY_LID"; - break; - case ESP_LE_KEY_LCSRK: - key_str = (char*) "ESP_LE_KEY_LCSRK"; - break; - default: - key_str = (char*) "INVALID BLE KEY TYPE"; - break; - } - return key_str; - -} // esp_key_type_to_str -*/ -#endif // CONFIG_BT_ENABLED diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLESecurity.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLESecurity.h deleted file mode 100644 index 157577d7b..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLESecurity.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * NimBLESecurity.h - * - * Created: on Feb 22 2020 - * Author H2zero - * - * Originally: - * - * BLESecurity.h - * - * Created on: Dec 17, 2017 - * Author: chegewara - */ - -#ifndef COMPONENTS_NIMBLESECURITY_H_ -#define COMPONENTS_NIMBLESECURITY_H_ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "host/ble_gap.h" -#else -#include "nimble/nimble/host/include/host/ble_gap.h" -#endif - -/**** FIX COMPILATION ****/ -#undef min -#undef max -/**************************/ - -#include - -#define ESP_LE_AUTH_NO_BOND 0x00 /*!< 0*/ /* relate to BTM_LE_AUTH_NO_BOND in stack/btm_api.h */ -#define ESP_LE_AUTH_BOND 0x01 /*!< 1 << 0 */ /* relate to BTM_LE_AUTH_BOND in stack/btm_api.h */ -#define ESP_LE_AUTH_REQ_MITM (1 << 2) /*!< 1 << 2 */ /* relate to BTM_LE_AUTH_REQ_MITM in stack/btm_api.h */ -#define ESP_LE_AUTH_REQ_BOND_MITM (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_MITM)/*!< 0101*/ -#define ESP_LE_AUTH_REQ_SC_ONLY (1 << 3) /*!< 1 << 3 */ /* relate to BTM_LE_AUTH_REQ_SC_ONLY in stack/btm_api.h */ -#define ESP_LE_AUTH_REQ_SC_BOND (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_SC_ONLY) /*!< 1001 */ /* relate to BTM_LE_AUTH_REQ_SC_BOND in stack/btm_api.h */ -#define ESP_LE_AUTH_REQ_SC_MITM (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY) /*!< 1100 */ /* relate to BTM_LE_AUTH_REQ_SC_MITM in stack/btm_api.h */ -#define ESP_LE_AUTH_REQ_SC_MITM_BOND (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY | ESP_LE_AUTH_BOND) /*!< 1101 */ /* relate to BTM_LE_AUTH_REQ_SC_MITM_BOND in stack/btm_api.h */ - -#define ESP_IO_CAP_OUT 0 /*!< DisplayOnly */ /* relate to BTM_IO_CAP_OUT in stack/btm_api.h */ -#define ESP_IO_CAP_IO 1 /*!< DisplayYesNo */ /* relate to BTM_IO_CAP_IO in stack/btm_api.h */ -#define ESP_IO_CAP_IN 2 /*!< KeyboardOnly */ /* relate to BTM_IO_CAP_IN in stack/btm_api.h */ -#define ESP_IO_CAP_NONE 3 /*!< NoInputNoOutput */ /* relate to BTM_IO_CAP_NONE in stack/btm_api.h */ -#define ESP_IO_CAP_KBDISP 4 /*!< Keyboard display */ /* relate to BTM_IO_CAP_KBDISP in stack/btm_api.h */ - -/// Used to exchange the encryption key in the init key & response key -#define ESP_BLE_ENC_KEY_MASK (1 << 0) /* relate to BTM_BLE_ENC_KEY_MASK in stack/btm_api.h */ -/// Used to exchange the IRK key in the init key & response key -#define ESP_BLE_ID_KEY_MASK (1 << 1) /* relate to BTM_BLE_ID_KEY_MASK in stack/btm_api.h */ -/// Used to exchange the CSRK key in the init key & response key -#define ESP_BLE_CSR_KEY_MASK (1 << 2) /* relate to BTM_BLE_CSR_KEY_MASK in stack/btm_api.h */ -/// Used to exchange the link key(this key just used in the BLE & BR/EDR coexist mode) in the init key & response key -#define ESP_BLE_LINK_KEY_MASK (1 << 3) /* relate to BTM_BLE_LINK_KEY_MASK in stack/btm_api.h */ - -typedef uint8_t esp_ble_auth_req_t; /*!< combination of the above bit pattern */ -typedef uint8_t esp_ble_io_cap_t; /*!< combination of the io capability */ - - -/** - * @brief A class to handle BLE security operations. - * Deprecated - provided for backward compatibility only. - * @deprecated Use the security methods provided in NimBLEDevice instead. - */ -class NimBLESecurity { -public: - NimBLESecurity(); - virtual ~NimBLESecurity(); - void setAuthenticationMode(esp_ble_auth_req_t auth_req); - void setCapability(esp_ble_io_cap_t iocap); - void setInitEncryptionKey(uint8_t init_key); - void setRespEncryptionKey(uint8_t resp_key); - void setKeySize(uint8_t key_size = 16); - void setStaticPIN(uint32_t pin); - //static char* esp_key_type_to_str(esp_ble_key_type_t key_type); -/* -private: - esp_ble_auth_req_t m_authReq; - esp_ble_io_cap_t m_iocap; - uint8_t m_initKey; - uint8_t m_respKey; - uint8_t m_keySize; -*/ -}; // BLESecurity - - -/** - * @brief Callbacks to handle GAP events related to authorization. - * Deprecated - provided for backward compatibility only. - * @deprecated Use the callbacks provided in NimBLEClientCallbacks and NimBLEServerCallbacks instead. - */ -class NimBLESecurityCallbacks { -public: - virtual ~NimBLESecurityCallbacks() {}; - - /** - * @brief Its request from peer device to input authentication pin code displayed on peer device. - * It requires that our device is capable to input 6-digits code by end user - * @return Return 6-digits integer value from input device - */ - virtual uint32_t onPassKeyRequest() = 0; - - /** - * @brief Provide us 6-digits code to perform authentication. - * It requires that our device is capable to display this code to end user - * @param [in] pass_key The PIN provided by the peer. - */ - virtual void onPassKeyNotify(uint32_t pass_key) = 0; - - /** - * @brief Here we can make decision if we want to let negotiate authorization with peer device or not - * @return Return true if we accept this peer device request - */ - virtual bool onSecurityRequest() = 0 ; - /** - * @brief Provides us information when authentication process is completed - */ - virtual void onAuthenticationComplete(ble_gap_conn_desc*) = 0; - - /** - * @brief Called when using numeric comparison for authentication. - * @param [in] pin The PIN to compare. - * @return True to accept and pair. - */ - virtual bool onConfirmPIN(uint32_t pin) = 0; -}; // BLESecurityCallbacks - -#endif // CONFIG_BT_ENABLED -#endif // COMPONENTS_NIMBLESECURITY_H_ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.cpp deleted file mode 100644 index 82fbc7a01..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.cpp +++ /dev/null @@ -1,921 +0,0 @@ -/* - * NimBLEServer.cpp - * - * Created: on March 2, 2020 - * Author H2zero - * - * Originally: - * - * BLEServer.cpp - * - * Created on: Apr 16, 2017 - * Author: kolban - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include "NimBLEServer.h" -#include "NimBLEDevice.h" -#include "NimBLELog.h" - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "services/gap/ble_svc_gap.h" -#include "services/gatt/ble_svc_gatt.h" -#else -#include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h" -#include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h" -#endif - -static const char* LOG_TAG = "NimBLEServer"; -static NimBLEServerCallbacks defaultCallbacks; - - -/** - * @brief Construct a %BLE Server - * - * This class is not designed to be individually instantiated. Instead one should create a server by asking - * the NimBLEDevice class. - */ -NimBLEServer::NimBLEServer() { - memset(m_indWait, BLE_HS_CONN_HANDLE_NONE, sizeof(m_indWait)); -// m_svcChgChrHdl = 0xffff; // Future Use - m_pServerCallbacks = &defaultCallbacks; - m_gattsStarted = false; -#if !CONFIG_BT_NIMBLE_EXT_ADV - m_advertiseOnDisconnect = true; -#endif - m_svcChanged = false; - m_deleteCallbacks = true; -} // NimBLEServer - - -/** - * @brief Destructor: frees all resources / attributes created. - */ -NimBLEServer::~NimBLEServer() { - for(auto &it : m_svcVec) { - delete it; - } - - if(m_deleteCallbacks && m_pServerCallbacks != &defaultCallbacks) { - delete m_pServerCallbacks; - } -} - - -/** - * @brief Create a %BLE Service. - * @param [in] uuid The UUID of the new service. - * @return A reference to the new service object. - */ -NimBLEService* NimBLEServer::createService(const char* uuid) { - return createService(NimBLEUUID(uuid)); -} // createService - - -/** - * @brief Create a %BLE Service. - * @param [in] uuid The UUID of the new service. - * @return A reference to the new service object. - */ -NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid) { - NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str()); - - // Check that a service with the supplied UUID does not already exist. - if(getServiceByUUID(uuid) != nullptr) { - NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s", - std::string(uuid).c_str()); - } - - NimBLEService* pService = new NimBLEService(uuid); - m_svcVec.push_back(pService); - serviceChanged(); - - NIMBLE_LOGD(LOG_TAG, "<< createService"); - return pService; -} // createService - - -/** - * @brief Get a %BLE Service by its UUID - * @param [in] uuid The UUID of the service. - * @param instanceId The index of the service to return (used when multiple services have the same UUID). - * @return A pointer to the service object or nullptr if not found. - */ -NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid, uint16_t instanceId) { - return getServiceByUUID(NimBLEUUID(uuid), instanceId); -} // getServiceByUUID - - -/** - * @brief Get a %BLE Service by its UUID - * @param [in] uuid The UUID of the service. - * @param instanceId The index of the service to return (used when multiple services have the same UUID). - * @return A pointer to the service object or nullptr if not found. - */ -NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId) { - uint16_t position = 0; - for (auto &it : m_svcVec) { - if (it->getUUID() == uuid) { - if (position == instanceId){ - return it; - } - position++; - } - } - return nullptr; -} // getServiceByUUID - -/** - * @brief Get a %BLE Service by its handle - * @param handle The handle of the service. - * @return A pointer to the service object or nullptr if not found. - */ -NimBLEService *NimBLEServer::getServiceByHandle(uint16_t handle) { - for (auto &it : m_svcVec) { - if (it->getHandle() == handle) { - return it; - } - } - return nullptr; -} - - -#if CONFIG_BT_NIMBLE_EXT_ADV -/** - * @brief Retrieve the advertising object that can be used to advertise the existence of the server. - * @return An advertising object. - */ -NimBLEExtAdvertising* NimBLEServer::getAdvertising() { - return NimBLEDevice::getAdvertising(); -} // getAdvertising -#endif - -#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) -/** - * @brief Retrieve the advertising object that can be used to advertise the existence of the server. - * @return An advertising object. - */ -NimBLEAdvertising* NimBLEServer::getAdvertising() { - return NimBLEDevice::getAdvertising(); -} // getAdvertising -#endif - -/** - * @brief Sends a service changed notification and resets the GATT server. - */ -void NimBLEServer::serviceChanged() { - if(m_gattsStarted) { - m_svcChanged = true; - ble_svc_gatt_changed(0x0001, 0xffff); - resetGATT(); - } -} - - -/** - * @brief Start the GATT server. Required to be called after setup of all - * services and characteristics / descriptors for the NimBLE host to register them. - */ -void NimBLEServer::start() { - if(m_gattsStarted) { - NIMBLE_LOGW(LOG_TAG, "Gatt server already started"); - return; - } - - int rc = ble_gatts_start(); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "ble_gatts_start; rc=%d, %s", rc, - NimBLEUtils::returnCodeToString(rc)); - abort(); - } - -#if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4 - ble_gatts_show_local(); -#endif -/*** Future use *** - * TODO: implement service changed handling - - ble_uuid16_t svc = {BLE_UUID_TYPE_16, 0x1801}; - ble_uuid16_t chr = {BLE_UUID_TYPE_16, 0x2a05}; - - rc = ble_gatts_find_chr(&svc.u, &chr.u, NULL, &m_svcChgChrHdl); - if(rc != 0) { - NIMBLE_LOGE(LOG_TAG, "ble_gatts_find_chr: rc=%d, %s", rc, - NimBLEUtils::returnCodeToString(rc)); - abort(); - } - - NIMBLE_LOGI(LOG_TAG, "Service changed characterisic handle: %d", m_svcChgChrHdl); -*/ - // Get the assigned service handles and build a vector of characteristics - // with Notify / Indicate capabilities for event handling - for(auto &svc : m_svcVec) { - if(svc->m_removed == 0) { - rc = ble_gatts_find_svc(&svc->getUUID().getNative()->u, &svc->m_handle); - if(rc != 0) { - abort(); - } - } - - for(auto &chr : svc->m_chrVec) { - // if Notify / Indicate is enabled but we didn't create the descriptor - // we do it now. - if((chr->m_properties & BLE_GATT_CHR_F_INDICATE) || - (chr->m_properties & BLE_GATT_CHR_F_NOTIFY)) { - m_notifyChrVec.push_back(chr); - } - } - } - - m_gattsStarted = true; -} // start - - -/** - * @brief Disconnect the specified client with optional reason. - * @param [in] connId Connection Id of the client to disconnect. - * @param [in] reason code for disconnecting. - * @return NimBLE host return code. - */ -int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) { - NIMBLE_LOGD(LOG_TAG, ">> disconnect()"); - - int rc = ble_gap_terminate(connId, reason); - if(rc != 0){ - NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s", rc, - NimBLEUtils::returnCodeToString(rc)); - } - - NIMBLE_LOGD(LOG_TAG, "<< disconnect()"); - return rc; -} // disconnect - - -#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) -/** - * @brief Set the server to automatically start advertising when a client disconnects. - * @param [in] aod true == advertise, false == don't advertise. - */ -void NimBLEServer::advertiseOnDisconnect(bool aod) { - m_advertiseOnDisconnect = aod; -} // advertiseOnDisconnect -#endif - -/** - * @brief Return the number of connected clients. - * @return The number of connected clients. - */ -size_t NimBLEServer::getConnectedCount() { - return m_connectedPeersVec.size(); -} // getConnectedCount - - -/** - * @brief Get the vector of the connected client ID's. - */ -std::vector NimBLEServer::getPeerDevices() { - return m_connectedPeersVec; -} // getPeerDevices - - -/** - * @brief Get the connection information of a connected peer by vector index. - * @param [in] index The vector index of the peer. - */ -NimBLEConnInfo NimBLEServer::getPeerInfo(size_t index) { - if (index >= m_connectedPeersVec.size()) { - NIMBLE_LOGE(LOG_TAG, "No peer at index %u", index); - return NimBLEConnInfo(); - } - - return getPeerIDInfo(m_connectedPeersVec[index]); -} // getPeerInfo - - -/** - * @brief Get the connection information of a connected peer by address. - * @param [in] address The address of the peer. - */ -NimBLEConnInfo NimBLEServer::getPeerInfo(const NimBLEAddress& address) { - ble_addr_t peerAddr; - memcpy(&peerAddr.val, address.getNative(),6); - peerAddr.type = address.getType(); - - NimBLEConnInfo peerInfo; - int rc = ble_gap_conn_find_by_addr(&peerAddr, &peerInfo.m_desc); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Peer info not found"); - } - - return peerInfo; -} // getPeerInfo - - -/** - * @brief Get the connection information of a connected peer by connection ID. - * @param [in] id The connection id of the peer. - */ -NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) { - NimBLEConnInfo peerInfo; - - int rc = ble_gap_conn_find(id, &peerInfo.m_desc); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Peer info not found"); - } - - return peerInfo; -} // getPeerIDInfo - - -/** - * @brief Handle a GATT Server Event. - * - * @param [in] event - * @param [in] gatts_if - * @param [in] param - * - */ -/*STATIC*/ -int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) { - NimBLEServer* server = NimBLEDevice::getServer(); - NIMBLE_LOGD(LOG_TAG, ">> handleGapEvent: %s", - NimBLEUtils::gapEventToString(event->type)); - int rc = 0; - struct ble_gap_conn_desc desc; - - switch(event->type) { - - case BLE_GAP_EVENT_CONNECT: { - if (event->connect.status != 0) { - /* Connection failed; resume advertising */ - NIMBLE_LOGE(LOG_TAG, "Connection failed"); -#if !CONFIG_BT_NIMBLE_EXT_ADV - NimBLEDevice::startAdvertising(); -#endif - } - else { - server->m_connectedPeersVec.push_back(event->connect.conn_handle); - - rc = ble_gap_conn_find(event->connect.conn_handle, &desc); - if (rc != 0) { - return 0; - } - - server->m_pServerCallbacks->onConnect(server); - server->m_pServerCallbacks->onConnect(server, &desc); - } - - return 0; - } // BLE_GAP_EVENT_CONNECT - - - case BLE_GAP_EVENT_DISCONNECT: { - // If Host reset tell the device now before returning to prevent - // any errors caused by calling host functions before resync. - switch(event->disconnect.reason) { - case BLE_HS_ETIMEOUT_HCI: - case BLE_HS_EOS: - case BLE_HS_ECONTROLLER: - case BLE_HS_ENOTSYNCED: - NIMBLE_LOGC(LOG_TAG, "Disconnect - host reset, rc=%d", event->disconnect.reason); - NimBLEDevice::onReset(event->disconnect.reason); - break; - default: - break; - } - - server->m_connectedPeersVec.erase(std::remove(server->m_connectedPeersVec.begin(), - server->m_connectedPeersVec.end(), - event->disconnect.conn.conn_handle), - server->m_connectedPeersVec.end()); - - if(server->m_svcChanged) { - server->resetGATT(); - } - - server->m_pServerCallbacks->onDisconnect(server); - server->m_pServerCallbacks->onDisconnect(server, &event->disconnect.conn); - -#if !CONFIG_BT_NIMBLE_EXT_ADV - if(server->m_advertiseOnDisconnect) { - server->startAdvertising(); - } -#endif - return 0; - } // BLE_GAP_EVENT_DISCONNECT - - case BLE_GAP_EVENT_SUBSCRIBE: { - NIMBLE_LOGI(LOG_TAG, "subscribe event; attr_handle=%d, subscribed: %s", - event->subscribe.attr_handle, - (event->subscribe.cur_notify ? "true":"false")); - - for(auto &it : server->m_notifyChrVec) { - if(it->getHandle() == event->subscribe.attr_handle) { - if((it->getProperties() & BLE_GATT_CHR_F_READ_AUTHEN) || - (it->getProperties() & BLE_GATT_CHR_F_READ_AUTHOR) || - (it->getProperties() & BLE_GATT_CHR_F_READ_ENC)) - { - rc = ble_gap_conn_find(event->subscribe.conn_handle, &desc); - if (rc != 0) { - break; - } - - if(!desc.sec_state.encrypted) { - NimBLEDevice::startSecurity(event->subscribe.conn_handle); - } - } - - it->setSubscribe(event); - break; - } - } - - return 0; - } // BLE_GAP_EVENT_SUBSCRIBE - - case BLE_GAP_EVENT_MTU: { - NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d", - event->mtu.conn_handle, - event->mtu.value); - rc = ble_gap_conn_find(event->mtu.conn_handle, &desc); - if (rc != 0) { - return 0; - } - - server->m_pServerCallbacks->onMTUChange(event->mtu.value, &desc); - return 0; - } // BLE_GAP_EVENT_MTU - - case BLE_GAP_EVENT_NOTIFY_TX: { - NimBLECharacteristic *pChar = nullptr; - - for(auto &it : server->m_notifyChrVec) { - if(it->getHandle() == event->notify_tx.attr_handle) { - pChar = it; - } - } - - if(pChar == nullptr) { - return 0; - } - - NimBLECharacteristicCallbacks::Status statusRC; - - if(event->notify_tx.indication) { - if(event->notify_tx.status != 0) { - if(event->notify_tx.status == BLE_HS_EDONE) { - statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE; - } else if(rc == BLE_HS_ETIMEOUT) { - statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT; - } else { - statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE; - } - } else { - return 0; - } - - server->clearIndicateWait(event->notify_tx.conn_handle); - } else { - if(event->notify_tx.status == 0) { - statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY; - } else { - statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT; - } - } - - pChar->m_pCallbacks->onStatus(pChar, statusRC, event->notify_tx.status); - - return 0; - } // BLE_GAP_EVENT_NOTIFY_TX - - - case BLE_GAP_EVENT_ADV_COMPLETE: -#if CONFIG_BT_NIMBLE_EXT_ADV - case BLE_GAP_EVENT_SCAN_REQ_RCVD: - return NimBLEExtAdvertising::handleGapEvent(event, arg); -#else - return NimBLEAdvertising::handleGapEvent(event, arg); -#endif - // BLE_GAP_EVENT_ADV_COMPLETE | BLE_GAP_EVENT_SCAN_REQ_RCVD - - case BLE_GAP_EVENT_CONN_UPDATE: { - NIMBLE_LOGD(LOG_TAG, "Connection parameters updated."); - return 0; - } // BLE_GAP_EVENT_CONN_UPDATE - - case BLE_GAP_EVENT_REPEAT_PAIRING: { - /* We already have a bond with the peer, but it is attempting to - * establish a new secure link. This app sacrifices security for - * convenience: just throw away the old bond and accept the new link. - */ - - /* Delete the old bond. */ - rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc); - if (rc != 0){ - return BLE_GAP_REPEAT_PAIRING_IGNORE; - } - - ble_store_util_delete_peer(&desc.peer_id_addr); - - /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should - * continue with the pairing operation. - */ - return BLE_GAP_REPEAT_PAIRING_RETRY; - } // BLE_GAP_EVENT_REPEAT_PAIRING - - case BLE_GAP_EVENT_ENC_CHANGE: { - rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc); - if(rc != 0) { - return BLE_ATT_ERR_INVALID_HANDLE; - } - // Compatibility only - Do not use, should be removed the in future - if(NimBLEDevice::m_securityCallbacks != nullptr) { - NimBLEDevice::m_securityCallbacks->onAuthenticationComplete(&desc); - ///////////////////////////////////////////// - } else { - server->m_pServerCallbacks->onAuthenticationComplete(&desc); - } - - return 0; - } // BLE_GAP_EVENT_ENC_CHANGE - - case BLE_GAP_EVENT_PASSKEY_ACTION: { - struct ble_sm_io pkey = {0,0}; - - if (event->passkey.params.action == BLE_SM_IOACT_DISP) { - pkey.action = event->passkey.params.action; - // backward compatibility - pkey.passkey = NimBLEDevice::getSecurityPasskey(); // This is the passkey to be entered on peer - // if the (static)passkey is the default, check the callback for custom value - // both values default to the same. - if(pkey.passkey == 123456) { - pkey.passkey = server->m_pServerCallbacks->onPassKeyRequest(); - } - rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); - NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_DISP; ble_sm_inject_io result: %d", rc); - - } else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) { - NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp); - pkey.action = event->passkey.params.action; - // Compatibility only - Do not use, should be removed the in future - if(NimBLEDevice::m_securityCallbacks != nullptr) { - pkey.numcmp_accept = NimBLEDevice::m_securityCallbacks->onConfirmPIN(event->passkey.params.numcmp); - ///////////////////////////////////////////// - } else { - pkey.numcmp_accept = server->m_pServerCallbacks->onConfirmPIN(event->passkey.params.numcmp); - } - - rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); - NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_NUMCMP; ble_sm_inject_io result: %d", rc); - - //TODO: Handle out of band pairing - } else if (event->passkey.params.action == BLE_SM_IOACT_OOB) { - static uint8_t tem_oob[16] = {0}; - pkey.action = event->passkey.params.action; - for (int i = 0; i < 16; i++) { - pkey.oob[i] = tem_oob[i]; - } - rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); - NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_OOB; ble_sm_inject_io result: %d", rc); - ////////////////////////////////// - } else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) { - NIMBLE_LOGD(LOG_TAG, "Enter the passkey"); - pkey.action = event->passkey.params.action; - - // Compatibility only - Do not use, should be removed the in future - if(NimBLEDevice::m_securityCallbacks != nullptr) { - pkey.passkey = NimBLEDevice::m_securityCallbacks->onPassKeyRequest(); - ///////////////////////////////////////////// - } else { - pkey.passkey = server->m_pServerCallbacks->onPassKeyRequest(); - } - - rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey); - NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_INPUT; ble_sm_inject_io result: %d", rc); - - } else if (event->passkey.params.action == BLE_SM_IOACT_NONE) { - NIMBLE_LOGD(LOG_TAG, "No passkey action required"); - } - - NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent"); - return 0; - } // BLE_GAP_EVENT_PASSKEY_ACTION - - default: - break; - } - - NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent"); - return 0; -} // handleGapEvent - - -/** - * @brief Set the server callbacks. - * - * As a %BLE server operates, it will generate server level events such as a new client connecting or a previous client - * disconnecting. This function can be called to register a callback handler that will be invoked when these - * events are detected. - * - * @param [in] pCallbacks The callbacks to be invoked. - * @param [in] deleteCallbacks if true callback class will be deleted when server is destructed. - */ -void NimBLEServer::setCallbacks(NimBLEServerCallbacks* pCallbacks, bool deleteCallbacks) { - if (pCallbacks != nullptr){ - m_pServerCallbacks = pCallbacks; - m_deleteCallbacks = deleteCallbacks; - } else { - m_pServerCallbacks = &defaultCallbacks; - } -} // setCallbacks - - -/** - * @brief Remove a service from the server. - * - * @details Immediately removes access to the service by clients, sends a service changed indication, - * and removes the service (if applicable) from the advertisements. - * The service is not deleted unless the deleteSvc parameter is true, otherwise the service remains - * available and can be re-added in the future. If desired a removed but not deleted service can - * be deleted later by calling this method with deleteSvc set to true. - * - * @note The service will not be removed from the database until all open connections are closed - * as it requires resetting the GATT server. In the interim the service will have it's visibility disabled. - * - * @note Advertising will need to be restarted by the user after calling this as we must stop - * advertising in order to remove the service. - * - * @param [in] service The service object to remove. - * @param [in] deleteSvc true if the service should be deleted. - */ -void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) { - // Check if the service was already removed and if so check if this - // is being called to delete the object and do so if requested. - // Otherwise, ignore the call and return. - if(service->m_removed > 0) { - if(deleteSvc) { - for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ++it) { - if ((*it) == service) { - delete *it; - m_svcVec.erase(it); - break; - } - } - } - - return; - } - - int rc = ble_gatts_svc_set_visibility(service->getHandle(), 0); - if(rc !=0) { - return; - } - - service->m_removed = deleteSvc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE; - serviceChanged(); -#if !CONFIG_BT_NIMBLE_EXT_ADV - NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID()); -#endif -} - - -/** - * @brief Adds a service which was either already created but removed from availability,\n - * or created and later added to services list. - * @param [in] service The service object to add. - * @note If it is desired to advertise the service it must be added by - * calling NimBLEAdvertising::addServiceUUID. - */ -void NimBLEServer::addService(NimBLEService* service) { - // Check that a service with the supplied UUID does not already exist. - if(getServiceByUUID(service->getUUID()) != nullptr) { - NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s", - std::string(service->getUUID()).c_str()); - } - - // If adding a service that was not removed add it and return. - // Else reset GATT and send service changed notification. - if(service->m_removed == 0) { - m_svcVec.push_back(service); - return; - } - - service->m_removed = 0; - serviceChanged(); -} - - -/** - * @brief Resets the GATT server, used when services are added/removed after initialization. - */ -void NimBLEServer::resetGATT() { - if(getConnectedCount() > 0) { - return; - } - - NimBLEDevice::stopAdvertising(); - ble_gatts_reset(); - ble_svc_gap_init(); - ble_svc_gatt_init(); - - for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ) { - if ((*it)->m_removed > 0) { - if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) { - delete *it; - it = m_svcVec.erase(it); - } else { - ++it; - } - continue; - } - - (*it)->start(); - ++it; - } - - m_svcChanged = false; - m_gattsStarted = false; -} - - -#if CONFIG_BT_NIMBLE_EXT_ADV -/** - * @brief Start advertising. - * @param [in] inst_id The extended advertisement instance ID to start. - * @param [in] duration How long to advertise for in milliseconds, 0 = forever (default). - * @param [in] max_events Maximum number of advertisement events to send, 0 = no limit (default). - * @return True if advertising started successfully. - * @details Start the server advertising its existence. This is a convenience function and is equivalent to - * retrieving the advertising object and invoking start upon it. - */ -bool NimBLEServer::startAdvertising(uint8_t inst_id, - int duration, - int max_events) { - return getAdvertising()->start(inst_id, duration, max_events); -} // startAdvertising - - -/** - * @brief Convenience function to stop advertising a data set. - * @param [in] inst_id The extended advertisement instance ID to stop advertising. - * @return True if advertising stopped successfully. - */ -bool NimBLEServer::stopAdvertising(uint8_t inst_id) { - return getAdvertising()->stop(inst_id); -} // stopAdvertising -#endif - -#if !CONFIG_BT_NIMBLE_EXT_ADV|| defined(_DOXYGEN_) -/** - * @brief Start advertising. - * @return True if advertising started successfully. - * @details Start the server advertising its existence. This is a convenience function and is equivalent to - * retrieving the advertising object and invoking start upon it. - */ -bool NimBLEServer::startAdvertising() { - return getAdvertising()->start(); -} // startAdvertising -#endif - - -/** - * @brief Stop advertising. - * @return True if advertising stopped successfully. - */ -bool NimBLEServer::stopAdvertising() { - return getAdvertising()->stop(); -} // stopAdvertising - - -/** - * @brief Get the MTU of the client. - * @returns The client MTU or 0 if not found/connected. - */ -uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) { - return ble_att_mtu(conn_id); -} //getPeerMTU - - -/** - * @brief Request an Update the connection parameters: - * * Can only be used after a connection has been established. - * @param [in] conn_handle The connection handle of the peer to send the request to. - * @param [in] minInterval The minimum connection interval in 1.25ms units. - * @param [in] maxInterval The maximum connection interval in 1.25ms units. - * @param [in] latency The number of packets allowed to skip (extends max interval). - * @param [in] timeout The timeout time in 10ms units before disconnecting. - */ -void NimBLEServer::updateConnParams(uint16_t conn_handle, - uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout) -{ - ble_gap_upd_params params; - - params.latency = latency; - params.itvl_max = maxInterval; // max_int = 0x20*1.25ms = 40ms - params.itvl_min = minInterval; // min_int = 0x10*1.25ms = 20ms - params.supervision_timeout = timeout; // timeout = 400*10ms = 4000ms - params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units - params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units - - int rc = ble_gap_update_params(conn_handle, ¶ms); - if(rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); - } -} // updateConnParams - - -/** - * @brief Request an update of the data packet length. - * * Can only be used after a connection has been established. - * @details Sends a data length update request to the peer. - * The Data Length Extension (DLE) allows to increase the Data Channel Payload from 27 bytes to up to 251 bytes. - * The peer needs to support the Bluetooth 4.2 specifications, to be capable of DLE. - * @param [in] conn_handle The connection handle of the peer to send the request to. - * @param [in] tx_octets The preferred number of payload octets to use (Range 0x001B-0x00FB). - */ -void NimBLEServer::setDataLen(uint16_t conn_handle, uint16_t tx_octets) { -#if defined(CONFIG_NIMBLE_CPP_IDF) && !defined(ESP_IDF_VERSION) || \ - (ESP_IDF_VERSION_MAJOR * 100 + ESP_IDF_VERSION_MINOR * 10 + ESP_IDF_VERSION_PATCH) < 432 - return; -#else - uint16_t tx_time = (tx_octets + 14) * 8; - - int rc = ble_gap_set_data_len(conn_handle, tx_octets, tx_time); - if(rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Set data length error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); - } -#endif -} // setDataLen - - -bool NimBLEServer::setIndicateWait(uint16_t conn_handle) { - for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) { - if(m_indWait[i] == conn_handle) { - return false; - } - } - - return true; -} - - -void NimBLEServer::clearIndicateWait(uint16_t conn_handle) { - for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) { - if(m_indWait[i] == conn_handle) { - m_indWait[i] = BLE_HS_CONN_HANDLE_NONE; - return; - } - } -} - - -/** Default callback handlers */ - -void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer) { - NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default"); -} // onConnect - - -void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) { - NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default"); -} // onConnect - - -void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer) { - NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default"); -} // onDisconnect - -void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) { - NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default"); -} // onDisconnect - -void NimBLEServerCallbacks::onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) { - NIMBLE_LOGD("NimBLEServerCallbacks", "onMTUChange(): Default"); -} // onMTUChange - -uint32_t NimBLEServerCallbacks::onPassKeyRequest(){ - NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyRequest: default: 123456"); - return 123456; -} -/* -void NimBLEServerCallbacks::onPassKeyNotify(uint32_t pass_key){ - NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyNotify: default: %d", pass_key); -} - -bool NimBLEServerCallbacks::onSecurityRequest(){ - NIMBLE_LOGD("NimBLEServerCallbacks", "onSecurityRequest: default: true"); - return true; -} -*/ -void NimBLEServerCallbacks::onAuthenticationComplete(ble_gap_conn_desc*){ - NIMBLE_LOGD("NimBLEServerCallbacks", "onAuthenticationComplete: default"); -} -bool NimBLEServerCallbacks::onConfirmPIN(uint32_t pin){ - NIMBLE_LOGD("NimBLEServerCallbacks", "onConfirmPIN: default: true"); - return true; -} - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.h deleted file mode 100644 index 54bbb9ab1..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * NimBLEServer.h - * - * Created: on March 2, 2020 - * Author H2zero - * - * Originally: - * - * BLEServer.h - * - * Created on: Apr 16, 2017 - * Author: kolban - */ - -#ifndef MAIN_NIMBLESERVER_H_ -#define MAIN_NIMBLESERVER_H_ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#define NIMBLE_ATT_REMOVE_HIDE 1 -#define NIMBLE_ATT_REMOVE_DELETE 2 - -#define onMtuChanged onMTUChange - -#include "NimBLEUtils.h" -#include "NimBLEAddress.h" -#if CONFIG_BT_NIMBLE_EXT_ADV -#include "NimBLEExtAdvertising.h" -#else -#include "NimBLEAdvertising.h" -#endif -#include "NimBLEService.h" -#include "NimBLESecurity.h" -#include "NimBLEConnInfo.h" - - -class NimBLEService; -class NimBLECharacteristic; -class NimBLEServerCallbacks; - - -/** - * @brief The model of a %BLE server. - */ -class NimBLEServer { -public: - size_t getConnectedCount(); - NimBLEService* createService(const char* uuid); - NimBLEService* createService(const NimBLEUUID &uuid); - void removeService(NimBLEService* service, bool deleteSvc = false); - void addService(NimBLEService* service); - void setCallbacks(NimBLEServerCallbacks* pCallbacks, - bool deleteCallbacks = true); -#if CONFIG_BT_NIMBLE_EXT_ADV - NimBLEExtAdvertising* getAdvertising(); - bool startAdvertising(uint8_t inst_id, - int duration = 0, - int max_events = 0); - bool stopAdvertising(uint8_t inst_id); -#endif -#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) - NimBLEAdvertising* getAdvertising(); - bool startAdvertising(); -#endif - bool stopAdvertising(); - void start(); - NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0); - NimBLEService* getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId = 0); - NimBLEService* getServiceByHandle(uint16_t handle); - int disconnect(uint16_t connID, - uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); - void updateConnParams(uint16_t conn_handle, - uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout); - void setDataLen(uint16_t conn_handle, uint16_t tx_octets); - uint16_t getPeerMTU(uint16_t conn_id); - std::vector getPeerDevices(); - NimBLEConnInfo getPeerInfo(size_t index); - NimBLEConnInfo getPeerInfo(const NimBLEAddress& address); - NimBLEConnInfo getPeerIDInfo(uint16_t id); -#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) - void advertiseOnDisconnect(bool); -#endif - -private: - NimBLEServer(); - ~NimBLEServer(); - friend class NimBLECharacteristic; - friend class NimBLEService; - friend class NimBLEDevice; - friend class NimBLEAdvertising; -#if CONFIG_BT_NIMBLE_EXT_ADV - friend class NimBLEExtAdvertising; - friend class NimBLEExtAdvertisementData; -#endif - - bool m_gattsStarted; -#if !CONFIG_BT_NIMBLE_EXT_ADV - bool m_advertiseOnDisconnect; -#endif - bool m_svcChanged; - NimBLEServerCallbacks* m_pServerCallbacks; - bool m_deleteCallbacks; - uint16_t m_indWait[CONFIG_BT_NIMBLE_MAX_CONNECTIONS]; - std::vector m_connectedPeersVec; - -// uint16_t m_svcChgChrHdl; // Future use - - std::vector m_svcVec; - std::vector m_notifyChrVec; - - static int handleGapEvent(struct ble_gap_event *event, void *arg); - void serviceChanged(); - void resetGATT(); - bool setIndicateWait(uint16_t conn_handle); - void clearIndicateWait(uint16_t conn_handle); -}; // NimBLEServer - - -/** - * @brief Callbacks associated with the operation of a %BLE server. - */ -class NimBLEServerCallbacks { -public: - virtual ~NimBLEServerCallbacks() {}; - - /** - * @brief Handle a client connection. - * This is called when a client connects. - * @param [in] pServer A pointer to the %BLE server that received the client connection. - */ - virtual void onConnect(NimBLEServer* pServer); - - /** - * @brief Handle a client connection. - * This is called when a client connects. - * @param [in] pServer A pointer to the %BLE server that received the client connection. - * @param [in] desc A pointer to the connection description structure containig information - * about the connection parameters. - */ - virtual void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc); - - /** - * @brief Handle a client disconnection. - * This is called when a client disconnects. - * @param [in] pServer A reference to the %BLE server that received the existing client disconnection. - */ - virtual void onDisconnect(NimBLEServer* pServer); - - /** - * @brief Handle a client disconnection. - * This is called when a client discconnects. - * @param [in] pServer A pointer to the %BLE server that received the client disconnection. - * @param [in] desc A pointer to the connection description structure containing information - * about the connection. - */ - virtual void onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc* desc); - - /** - * @brief Called when the connection MTU changes. - * @param [in] MTU The new MTU value. - * @param [in] desc A pointer to the connection description structure containing information - * about the connection. - */ - virtual void onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc); - - /** - * @brief Called when a client requests a passkey for pairing. - * @return The passkey to be sent to the client. - */ - virtual uint32_t onPassKeyRequest(); - - //virtual void onPassKeyNotify(uint32_t pass_key); - //virtual bool onSecurityRequest(); - - /** - * @brief Called when the pairing procedure is complete. - * @param [in] desc A pointer to the struct containing the connection information.\n - * This can be used to check the status of the connection encryption/pairing. - */ - virtual void onAuthenticationComplete(ble_gap_conn_desc* desc); - - /** - * @brief Called when using numeric comparision for pairing. - * @param [in] pin The pin to compare with the client. - * @return True to accept the pin. - */ - virtual bool onConfirmPIN(uint32_t pin); -}; // NimBLEServerCallbacks - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */ -#endif /* MAIN_NIMBLESERVER_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEService.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEService.cpp deleted file mode 100644 index b124fcb9c..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEService.cpp +++ /dev/null @@ -1,435 +0,0 @@ -/* - * NimBLEService.cpp - * - * Created: on March 2, 2020 - * Author H2zero - * - * Originally: - * - * BLEService.cpp - * - * Created on: Mar 25, 2017 - * Author: kolban - */ - -// A service is identified by a UUID. A service is also the container for one or more characteristics. - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include "NimBLEDevice.h" -#include "NimBLEService.h" -#include "NimBLEUtils.h" -#include "NimBLELog.h" - -#include - -static const char* LOG_TAG = "NimBLEService"; // Tag for logging. - -#define NULL_HANDLE (0xffff) - - -/** - * @brief Construct an instance of the NimBLEService - * @param [in] uuid The UUID of the service. - */ -NimBLEService::NimBLEService(const char* uuid) -: NimBLEService(NimBLEUUID(uuid)) { -} - - -/** - * @brief Construct an instance of the BLEService - * @param [in] uuid The UUID of the service. - */ -NimBLEService::NimBLEService(const NimBLEUUID &uuid) { - m_uuid = uuid; - m_handle = NULL_HANDLE; - m_pSvcDef = nullptr; - m_removed = 0; - -} // NimBLEService - - -NimBLEService::~NimBLEService() { - if(m_pSvcDef != nullptr) { - if(m_pSvcDef->characteristics != nullptr) { - for(int i=0; m_pSvcDef->characteristics[i].uuid != NULL; ++i) { - if(m_pSvcDef->characteristics[i].descriptors) { - delete(m_pSvcDef->characteristics[i].descriptors); - } - } - delete(m_pSvcDef->characteristics); - } - - delete(m_pSvcDef); - } - - for(auto &it : m_chrVec) { - delete it; - } -} - -/** - * @brief Dump details of this BLE GATT service. - * @return N/A. - */ -void NimBLEService::dump() { - NIMBLE_LOGD(LOG_TAG, "Service: uuid:%s, handle: 0x%2x", - m_uuid.toString().c_str(), - m_handle); - - std::string res; - int count = 0; - char hex[5]; - for (auto &it: m_chrVec) { - if (count > 0) {res += "\n";} - snprintf(hex, sizeof(hex), "%04x", it->getHandle()); - count++; - res += "handle: 0x"; - res += hex; - res += ", uuid: " + std::string(it->getUUID()); - } - NIMBLE_LOGD(LOG_TAG, "Characteristics:\n%s", res.c_str()); -} // dump - - -/** - * @brief Get the UUID of the service. - * @return the UUID of the service. - */ -NimBLEUUID NimBLEService::getUUID() { - return m_uuid; -} // getUUID - - -/** - * @brief Builds the database of characteristics/descriptors for the service - * and registers it with the NimBLE stack. - * @return bool success/failure . - */ -bool NimBLEService::start() { - NIMBLE_LOGD(LOG_TAG, ">> start(): Starting service: %s", toString().c_str()); - - // Rebuild the service definition if the server attributes have changed. - if(getServer()->m_svcChanged && m_pSvcDef != nullptr) { - if(m_pSvcDef[0].characteristics) { - if(m_pSvcDef[0].characteristics[0].descriptors) { - delete(m_pSvcDef[0].characteristics[0].descriptors); - } - delete(m_pSvcDef[0].characteristics); - } - delete(m_pSvcDef); - m_pSvcDef = nullptr; - } - - if(m_pSvcDef == nullptr) { - // Nimble requires an array of services to be sent to the api - // Since we are adding 1 at a time we create an array of 2 and set the type - // of the second service to 0 to indicate the end of the array. - ble_gatt_svc_def* svc = new ble_gatt_svc_def[2]; - ble_gatt_chr_def* pChr_a = nullptr; - ble_gatt_dsc_def* pDsc_a = nullptr; - - svc[0].type = BLE_GATT_SVC_TYPE_PRIMARY; - svc[0].uuid = &m_uuid.getNative()->u; - svc[0].includes = NULL; - - int removedCount = 0; - for(auto it = m_chrVec.begin(); it != m_chrVec.end(); ) { - if ((*it)->m_removed > 0) { - if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) { - delete *it; - it = m_chrVec.erase(it); - } else { - ++removedCount; - ++it; - } - continue; - } - - ++it; - } - - size_t numChrs = m_chrVec.size() - removedCount; - NIMBLE_LOGD(LOG_TAG,"Adding %d characteristics for service %s", numChrs, toString().c_str()); - - if(!numChrs){ - svc[0].characteristics = NULL; - }else{ - // Nimble requires the last characteristic to have it's uuid = 0 to indicate the end - // of the characteristics for the service. We create 1 extra and set it to null - // for this purpose. - pChr_a = new ble_gatt_chr_def[numChrs + 1]; - uint8_t i = 0; - for(auto chr_it = m_chrVec.begin(); chr_it != m_chrVec.end(); ++chr_it) { - if((*chr_it)->m_removed > 0) { - continue; - } - - removedCount = 0; - for(auto it = (*chr_it)->m_dscVec.begin(); it != (*chr_it)->m_dscVec.end(); ) { - if ((*it)->m_removed > 0) { - if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) { - delete *it; - it = (*chr_it)->m_dscVec.erase(it); - } else { - ++removedCount; - ++it; - } - continue; - } - - ++it; - } - - size_t numDscs = (*chr_it)->m_dscVec.size() - removedCount; - - if(!numDscs){ - pChr_a[i].descriptors = NULL; - } else { - // Must have last descriptor uuid = 0 so we have to create 1 extra - pDsc_a = new ble_gatt_dsc_def[numDscs+1]; - uint8_t d = 0; - for(auto dsc_it = (*chr_it)->m_dscVec.begin(); dsc_it != (*chr_it)->m_dscVec.end(); ++dsc_it ) { - if((*dsc_it)->m_removed > 0) { - continue; - } - pDsc_a[d].uuid = &(*dsc_it)->m_uuid.getNative()->u; - pDsc_a[d].att_flags = (*dsc_it)->m_properties; - pDsc_a[d].min_key_size = 0; - pDsc_a[d].access_cb = NimBLEDescriptor::handleGapEvent; - pDsc_a[d].arg = (*dsc_it); - ++d; - } - - pDsc_a[numDscs].uuid = NULL; - pChr_a[i].descriptors = pDsc_a; - } - - pChr_a[i].uuid = &(*chr_it)->m_uuid.getNative()->u; - pChr_a[i].access_cb = NimBLECharacteristic::handleGapEvent; - pChr_a[i].arg = (*chr_it); - pChr_a[i].flags = (*chr_it)->m_properties; - pChr_a[i].min_key_size = 0; - pChr_a[i].val_handle = &(*chr_it)->m_handle; - ++i; - } - - pChr_a[numChrs].uuid = NULL; - svc[0].characteristics = pChr_a; - } - - // end of services must indicate to api with type = 0 - svc[1].type = 0; - m_pSvcDef = svc; - } - - int rc = ble_gatts_count_cfg((const ble_gatt_svc_def*)m_pSvcDef); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "ble_gatts_count_cfg failed, rc= %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); - return false; - } - - rc = ble_gatts_add_svcs((const ble_gatt_svc_def*)m_pSvcDef); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "ble_gatts_add_svcs, rc= %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); - return false; - - } - - NIMBLE_LOGD(LOG_TAG, "<< start()"); - return true; -} // start - - -/** - * @brief Get the handle associated with this service. - * @return The handle associated with this service. - */ -uint16_t NimBLEService::getHandle() { - return m_handle; -} // getHandle - - -/** - * @brief Create a new BLE Characteristic associated with this service. - * @param [in] uuid - The UUID of the characteristic. - * @param [in] properties - The properties of the characteristic. - * @param [in] max_len - The maximum length in bytes that the characteristic value can hold. - * @return The new BLE characteristic. - */ -NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint32_t properties, uint16_t max_len) { - return createCharacteristic(NimBLEUUID(uuid), properties, max_len); -} - - -/** - * @brief Create a new BLE Characteristic associated with this service. - * @param [in] uuid - The UUID of the characteristic. - * @param [in] properties - The properties of the characteristic. - * @param [in] max_len - The maximum length in bytes that the characteristic value can hold. - * @return The new BLE characteristic. - */ -NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) { - NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, max_len, this); - - if (getCharacteristic(uuid) != nullptr) { - NIMBLE_LOGD(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s", - std::string(uuid).c_str()); - } - - addCharacteristic(pCharacteristic); - return pCharacteristic; -} // createCharacteristic - - -/** - * @brief Add a characteristic to the service. - * @param[in] pCharacteristic A pointer to the characteristic instance to add to the service. - */ -void NimBLEService::addCharacteristic(NimBLECharacteristic* pCharacteristic) { - bool foundRemoved = false; - - if(pCharacteristic->m_removed > 0) { - for(auto& it : m_chrVec) { - if(it == pCharacteristic) { - foundRemoved = true; - pCharacteristic->m_removed = 0; - } - } - } - - if(!foundRemoved) { - m_chrVec.push_back(pCharacteristic); - } - - pCharacteristic->setService(this); - getServer()->serviceChanged(); -} // addCharacteristic - - -/** - * @brief Remove a characteristic from the service. - * @param[in] pCharacteristic A pointer to the characteristic instance to remove from the service. - * @param[in] deleteChr If true it will delete the characteristic instance and free it's resources. - */ -void NimBLEService::removeCharacteristic(NimBLECharacteristic* pCharacteristic, bool deleteChr) { - // Check if the characteristic was already removed and if so, check if this - // is being called to delete the object and do so if requested. - // Otherwise, ignore the call and return. - if(pCharacteristic->m_removed > 0) { - if(deleteChr) { - for(auto it = m_chrVec.begin(); it != m_chrVec.end(); ++it) { - if ((*it) == pCharacteristic) { - m_chrVec.erase(it); - delete *it; - break; - } - } - } - - return; - } - - pCharacteristic->m_removed = deleteChr ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE; - getServer()->serviceChanged(); -} // removeCharacteristic - - -/** - * @brief Get a pointer to the characteristic object with the specified UUID. - * @param [in] uuid The UUID of the characteristic. - * @param instanceId The index of the characteristic to return (used when multiple characteristics have the same UUID). - * @return A pointer to the characteristic object or nullptr if not found. - */ -NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid, uint16_t instanceId) { - return getCharacteristic(NimBLEUUID(uuid), instanceId); -} - -/** - * @brief Get a pointer to the characteristic object with the specified UUID. - * @param [in] uuid The UUID of the characteristic. - * @param instanceId The index of the characteristic to return (used when multiple characteristics have the same UUID). - * @return A pointer to the characteristic object or nullptr if not found. - */ -NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId) { - uint16_t position = 0; - for (auto &it : m_chrVec) { - if (it->getUUID() == uuid) { - if (position == instanceId) { - return it; - } - position++; - } - } - return nullptr; -} - -/** - * @brief Get a pointer to the characteristic object with the specified handle. - * @param handle The handle of the characteristic. - * @return A pointer to the characteristic object or nullptr if not found. - */ -NimBLECharacteristic *NimBLEService::getCharacteristicByHandle(uint16_t handle) { - for (auto &it : m_chrVec) { - if (it->getHandle() == handle) { - return it; - } - } - return nullptr; -} - -/** - * @return A vector containing pointers to each characteristic associated with this service. - */ -std::vector NimBLEService::getCharacteristics() { - return m_chrVec; -} - -/** - * @return A vector containing pointers to each characteristic with the provided UUID associated with this service. - */ -std::vector NimBLEService::getCharacteristics(const char *uuid) { - return getCharacteristics(NimBLEUUID(uuid)); -} - -/** - * @return A vector containing pointers to each characteristic with the provided UUID associated with this service. - */ -std::vector NimBLEService::getCharacteristics(const NimBLEUUID &uuid) { - std::vector result; - for (auto &it : m_chrVec) { - if (it->getUUID() == uuid) { - result.push_back(it); - } - } - return result; -} - -/** - * @brief Return a string representation of this service. - * A service is defined by: - * * Its UUID - * * Its handle - * @return A string representation of this service. - */ -std::string NimBLEService::toString() { - std::string res = "UUID: " + getUUID().toString(); - char hex[5]; - snprintf(hex, sizeof(hex), "%04x", getHandle()); - res += ", handle: 0x"; - res += hex; - return res; -} // toString - - -/** - * @brief Get the BLE server associated with this service. - * @return The BLEServer associated with this service. - */ -NimBLEServer* NimBLEService::getServer() { - return NimBLEDevice::getServer(); -}// getServer - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEService.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEService.h deleted file mode 100644 index 21ec1af70..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEService.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * NimBLEService.h - * - * Created: on March 2, 2020 - * Author H2zero - * - * Originally: - * - * BLEService.h - * - * Created on: Mar 25, 2017 - * Author: kolban - */ - -#ifndef MAIN_NIMBLESERVICE_H_ -#define MAIN_NIMBLESERVICE_H_ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include "NimBLEServer.h" -#include "NimBLECharacteristic.h" -#include "NimBLEUUID.h" - - -class NimBLEServer; -class NimBLECharacteristic; - - -/** - * @brief The model of a %BLE service. - * - */ -class NimBLEService { -public: - - NimBLEService(const char* uuid); - NimBLEService(const NimBLEUUID &uuid); - ~NimBLEService(); - - NimBLEServer* getServer(); - - NimBLEUUID getUUID(); - uint16_t getHandle(); - std::string toString(); - void dump(); - - bool start(); - - NimBLECharacteristic* createCharacteristic(const char* uuid, - uint32_t properties = - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE, - uint16_t max_len = BLE_ATT_ATTR_MAX_LEN); - - NimBLECharacteristic* createCharacteristic(const NimBLEUUID &uuid, - uint32_t properties = - NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE, - uint16_t max_len = BLE_ATT_ATTR_MAX_LEN); - - void addCharacteristic(NimBLECharacteristic* pCharacteristic); - void removeCharacteristic(NimBLECharacteristic* pCharacteristic, bool deleteChr = false); - NimBLECharacteristic* getCharacteristic(const char* uuid, uint16_t instanceId = 0); - NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId = 0); - NimBLECharacteristic* getCharacteristicByHandle(uint16_t handle); - - std::vector getCharacteristics(); - std::vector getCharacteristics(const char* uuid); - std::vector getCharacteristics(const NimBLEUUID &uuid); - - -private: - - friend class NimBLEServer; - friend class NimBLEDevice; - - uint16_t m_handle; - NimBLEUUID m_uuid; - ble_gatt_svc_def* m_pSvcDef; - uint8_t m_removed; - std::vector m_chrVec; - -}; // NimBLEService - -#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */ -#endif /* MAIN_NIMBLESERVICE_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEUUID.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEUUID.cpp deleted file mode 100644 index b14eae160..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEUUID.cpp +++ /dev/null @@ -1,360 +0,0 @@ -/* - * NimBLEUUID.cpp - * - * Created: on Jan 24 2020 - * Author H2zero - * - * Originally: - * - * BLEUUID.cpp - * - * Created on: Jun 21, 2017 - * Author: kolban - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "NimBLEUtils.h" -#include "NimBLEUUID.h" -#include "NimBLELog.h" - -#include - -static const char* LOG_TAG = "NimBLEUUID"; - - -/** - * @brief Create a UUID from a string. - * - * Create a UUID from a string. There will be two possible stories here. Either the string represents - * a binary data field or the string represents a hex encoding of a UUID. - * For the hex encoding, here is an example: - * - * ``` - * "beb5483e-36e1-4688-b7f5-ea07361b26a8" - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * 12345678-90ab-cdef-1234-567890abcdef - * ``` - * - * This has a length of 36 characters. We need to parse this into 16 bytes. - * - * @param [in] value The string to build a UUID from. - */ - NimBLEUUID::NimBLEUUID(const std::string &value) { - m_valueSet = true; - if (value.length() == 4) { - m_uuid.u.type = BLE_UUID_TYPE_16; - m_uuid.u16.value = strtoul(value.c_str(), NULL, 16); - } - else if (value.length() == 8) { - m_uuid.u.type = BLE_UUID_TYPE_32; - m_uuid.u32.value = strtoul(value.c_str(), NULL, 16); - } - else if (value.length() == 16) { - *this = NimBLEUUID((uint8_t*)value.data(), 16, true); - } - else if (value.length() == 36) { - // If the length of the string is 36 bytes then we will assume it is a long hex string in - // UUID format. - char * position = const_cast(value.c_str()); - uint32_t first = strtoul(position, &position, 16); - uint16_t second = strtoul(position + 1, &position, 16); - uint16_t third = strtoul(position + 1, &position, 16); - uint16_t fourth = strtoul(position + 1, &position, 16); - uint64_t fifth = strtoull(position + 1, NULL, 16); - *this = NimBLEUUID(first, second, third, (uint64_t(fourth) << 48) + fifth); - } - else { - m_valueSet = false; - } -} // NimBLEUUID(std::string) - - -/** - * @brief Create a UUID from 2, 4, 16 bytes of memory. - * @param [in] pData The pointer to the start of the UUID. - * @param [in] size The size of the data. - * @param [in] msbFirst Is the MSB first in pData memory? - */ -NimBLEUUID::NimBLEUUID(const uint8_t* pData, size_t size, bool msbFirst) { - uint8_t *uuidValue = nullptr; - - switch(size) { - case 2: - uuidValue = (uint8_t*)&m_uuid.u16.value; - m_uuid.u.type = BLE_UUID_TYPE_16; - break; - case 4: - uuidValue = (uint8_t*)&m_uuid.u32.value; - m_uuid.u.type = BLE_UUID_TYPE_32; - break; - case 16: - uuidValue = m_uuid.u128.value; - m_uuid.u.type = BLE_UUID_TYPE_128; - break; - default: - m_valueSet = false; - NIMBLE_LOGE(LOG_TAG, "Invalid UUID size"); - return; - } - if (msbFirst) { - std::reverse_copy(pData, pData + size, uuidValue); - } else { - memcpy(uuidValue, pData, size); - } - m_valueSet = true; -} // NimBLEUUID - - -/** - * @brief Create a UUID from the 16bit value. - * @param [in] uuid The 16bit short form UUID. - */ -NimBLEUUID::NimBLEUUID(uint16_t uuid) { - m_uuid.u.type = BLE_UUID_TYPE_16; - m_uuid.u16.value = uuid; - m_valueSet = true; -} // NimBLEUUID - - -/** - * @brief Create a UUID from the 32bit value. - * @param [in] uuid The 32bit short form UUID. - */ -NimBLEUUID::NimBLEUUID(uint32_t uuid) { - m_uuid.u.type = BLE_UUID_TYPE_32; - m_uuid.u32.value = uuid; - m_valueSet = true; -} // NimBLEUUID - - -/** - * @brief Create a UUID from the native UUID. - * @param [in] uuid The native UUID. - */ -NimBLEUUID::NimBLEUUID(const ble_uuid128_t* uuid) { - m_uuid.u.type = BLE_UUID_TYPE_128; - memcpy(m_uuid.u128.value, uuid->value, 16); - m_valueSet = true; -} // NimBLEUUID - - -/** - * @brief Create a UUID from the 128bit value using hex parts instead of string, - * instead of NimBLEUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6"), it becomes - * NimBLEUUID(0xebe0ccb0, 0x7a0a, 0x4b0c, 0x8a1a6ff2997da3a6) - * - * @param [in] first The first 32bit of the UUID. - * @param [in] second The next 16bit of the UUID. - * @param [in] third The next 16bit of the UUID. - * @param [in] fourth The last 64bit of the UUID, combining the last 2 parts of the string equivalent - */ -NimBLEUUID::NimBLEUUID(uint32_t first, uint16_t second, uint16_t third, uint64_t fourth) { - m_uuid.u.type = BLE_UUID_TYPE_128; - memcpy(m_uuid.u128.value + 12, &first, 4); - memcpy(m_uuid.u128.value + 10, &second, 2); - memcpy(m_uuid.u128.value + 8, &third, 2); - memcpy(m_uuid.u128.value, &fourth, 8); - m_valueSet = true; -} - - -/** - * @brief Creates an empty UUID. - */ -NimBLEUUID::NimBLEUUID() { - m_valueSet = false; -} // NimBLEUUID - - -/** - * @brief Get the number of bits in this uuid. - * @return The number of bits in the UUID. One of 16, 32 or 128. - */ -uint8_t NimBLEUUID::bitSize() const { - if (!m_valueSet) return 0; - return m_uuid.u.type; -} // bitSize - - -/** - * @brief Compare a UUID against this UUID. - * - * @param [in] uuid The UUID to compare against. - * @return True if the UUIDs are equal and false otherwise. - */ -bool NimBLEUUID::equals(const NimBLEUUID &uuid) const { - return *this == uuid; -} - - -/** - * Create a NimBLEUUID from a string of the form: - * 0xNNNN - * 0xNNNNNNNN - * 0x - * NNNN - * NNNNNNNN - * - * - * @param [in] uuid The string to create the UUID from. - */ -NimBLEUUID NimBLEUUID::fromString(const std::string &uuid) { - uint8_t start = 0; - if (strstr(uuid.c_str(), "0x") != nullptr) { // If the string starts with 0x, skip those characters. - start = 2; - } - uint8_t len = uuid.length() - start; // Calculate the length of the string we are going to use. - - if(len == 4) { - uint16_t x = strtoul(uuid.substr(start, len).c_str(), NULL, 16); - return NimBLEUUID(x); - } else if (len == 8) { - uint32_t x = strtoul(uuid.substr(start, len).c_str(), NULL, 16); - return NimBLEUUID(x); - } else if (len == 36) { - return NimBLEUUID(uuid); - } - return NimBLEUUID(); -} // fromString - - -/** - * @brief Get the native UUID value. - * @return The native UUID value or nullptr if not set. - */ -const ble_uuid_any_t* NimBLEUUID::getNative() const { - if (m_valueSet == false) { - NIMBLE_LOGD(LOG_TAG,"<< Return of un-initialized UUID!"); - return nullptr; - } - return &m_uuid; -} // getNative - - -/** - * @brief Convert a UUID to its 128 bit representation. - * @details A UUID can be internally represented as 16bit, 32bit or the full 128bit. - * This method will convert 16 or 32bit representations to the full 128bit. - * @return The NimBLEUUID converted to 128bit. - */ -const NimBLEUUID &NimBLEUUID::to128() { - // If we either don't have a value or are already a 128 bit UUID, nothing further to do. - if (!m_valueSet || m_uuid.u.type == BLE_UUID_TYPE_128) { - return *this; - } - - // If we are 16 bit or 32 bit, then set the other bytes of the UUID. - if (m_uuid.u.type == BLE_UUID_TYPE_16) { - *this = NimBLEUUID(m_uuid.u16.value, 0x0000, 0x1000, 0x800000805f9b34fb); - } - else if (m_uuid.u.type == BLE_UUID_TYPE_32) { - *this = NimBLEUUID(m_uuid.u32.value, 0x0000, 0x1000, 0x800000805f9b34fb); - } - - return *this; -} // to128 - - -/** - * @brief Convert 128 bit UUID to its 16 bit representation. - * @details A UUID can be internally represented as 16bit, 32bit or the full 128bit. - * This method will convert a 128bit uuid to 16bit if it contains the ble base uuid. - * @return The NimBLEUUID converted to 16bit if successful, otherwise the original uuid. - */ -const NimBLEUUID& NimBLEUUID::to16() { - if (!m_valueSet || m_uuid.u.type == BLE_UUID_TYPE_16) { - return *this; - } - - if (m_uuid.u.type == BLE_UUID_TYPE_128) { - uint8_t base128[] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, - 0x00, 0x80, 0x00, 0x10, 0x00, 0x00}; - if (memcmp(m_uuid.u128.value, base128, sizeof(base128)) == 0 ) { - *this = NimBLEUUID(*(uint16_t*)(m_uuid.u128.value + 12)); - } - } - - return *this; -} - - -/** - * @brief Get a string representation of the UUID. - * @details - * The format of a string is: - * 01234567 8901 2345 6789 012345678901 - * 0000180d-0000-1000-8000-00805f9b34fb - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * - * @return A string representation of the UUID. - * @deprecated Use std::string() operator instead. - */ -std::string NimBLEUUID::toString() const { - return std::string(*this); -} // toString - - -/** - * @brief Convenience operator to check if this UUID is equal to another. - */ -bool NimBLEUUID::operator ==(const NimBLEUUID & rhs) const { - if(m_valueSet && rhs.m_valueSet) { - if(m_uuid.u.type != rhs.m_uuid.u.type) { - uint8_t uuidBase[16] = { - 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - if(m_uuid.u.type == BLE_UUID_TYPE_128){ - if(rhs.m_uuid.u.type == BLE_UUID_TYPE_16){ - memcpy(uuidBase+12, &rhs.m_uuid.u16.value, 2); - } else if (rhs.m_uuid.u.type == BLE_UUID_TYPE_32){ - memcpy(uuidBase+12, &rhs.m_uuid.u32.value, 4); - } - return memcmp(m_uuid.u128.value,uuidBase,16) == 0; - - } else if(rhs.m_uuid.u.type == BLE_UUID_TYPE_128) { - if(m_uuid.u.type == BLE_UUID_TYPE_16){ - memcpy(uuidBase+12, &m_uuid.u16.value, 2); - } else if (m_uuid.u.type == BLE_UUID_TYPE_32){ - memcpy(uuidBase+12, &m_uuid.u32.value, 4); - } - return memcmp(rhs.m_uuid.u128.value,uuidBase,16) == 0; - - } else { - return false; - } - } - - return ble_uuid_cmp(&m_uuid.u, &rhs.m_uuid.u) == 0; - } - - return m_valueSet == rhs.m_valueSet; -} - - -/** - * @brief Convenience operator to check if this UUID is not equal to another. - */ -bool NimBLEUUID::operator !=(const NimBLEUUID & rhs) const { - return !this->operator==(rhs); -} - - -/** - * @brief Convenience operator to convert this UUID to string representation. - * @details This allows passing NimBLEUUID to functions - * that accept std::string and/or or it's methods as a parameter. - */ -NimBLEUUID::operator std::string() const { - if (!m_valueSet) return std::string(); // If we have no value, nothing to format. - - char buf[BLE_UUID_STR_LEN]; - - return ble_uuid_to_str(&m_uuid.u, buf); -} - - -#endif /* CONFIG_BT_ENABLED */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEUUID.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEUUID.h deleted file mode 100644 index 2c24971f0..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEUUID.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * NimBLEUUID.h - * - * Created: on Jan 24 2020 - * Author H2zero - * - * Originally: - * - * BLEUUID.h - * - * Created on: Jun 21, 2017 - * Author: kolban - */ - -#ifndef COMPONENTS_NIMBLEUUID_H_ -#define COMPONENTS_NIMBLEUUID_H_ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "host/ble_uuid.h" -#else -#include "nimble/nimble/host/include/host/ble_uuid.h" -#endif - -/**** FIX COMPILATION ****/ -#undef min -#undef max -/**************************/ - -#include - -/** - * @brief A model of a %BLE UUID. - */ -class NimBLEUUID { -public: - NimBLEUUID(const std::string &uuid); - NimBLEUUID(uint16_t uuid); - NimBLEUUID(uint32_t uuid); - NimBLEUUID(const ble_uuid128_t* uuid); - NimBLEUUID(const uint8_t* pData, size_t size, bool msbFirst); - NimBLEUUID(uint32_t first, uint16_t second, uint16_t third, uint64_t fourth); - NimBLEUUID(); - - uint8_t bitSize() const; - bool equals(const NimBLEUUID &uuid) const; - const ble_uuid_any_t* getNative() const; - const NimBLEUUID & to128(); - const NimBLEUUID& to16(); - std::string toString() const; - static NimBLEUUID fromString(const std::string &uuid); - - bool operator ==(const NimBLEUUID & rhs) const; - bool operator !=(const NimBLEUUID & rhs) const; - operator std::string() const; - -private: - ble_uuid_any_t m_uuid; - bool m_valueSet = false; -}; // NimBLEUUID -#endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_NIMBLEUUID_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEUtils.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEUtils.cpp deleted file mode 100644 index 60ea541f2..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEUtils.cpp +++ /dev/null @@ -1,518 +0,0 @@ -/* - * NimBLEUtils.cpp - * - * Created: on Jan 25 2020 - * Author H2zero - * - */ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "NimBLEUtils.h" -#include "NimBLELog.h" - -#include - -static const char* LOG_TAG = "NimBLEUtils"; - - -/** - * @brief A function for checking validity of connection parameters. - * @param [in] params A pointer to the structure containing the parameters to check. - * @return valid == 0 or error code. - */ -int NimBLEUtils::checkConnParams(ble_gap_conn_params* params) { - /* Check connection interval min */ - if ((params->itvl_min < BLE_HCI_CONN_ITVL_MIN) || - (params->itvl_min > BLE_HCI_CONN_ITVL_MAX)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - /* Check connection interval max */ - if ((params->itvl_max < BLE_HCI_CONN_ITVL_MIN) || - (params->itvl_max > BLE_HCI_CONN_ITVL_MAX) || - (params->itvl_max < params->itvl_min)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check connection latency */ - if (params->latency > BLE_HCI_CONN_LATENCY_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check supervision timeout */ - if ((params->supervision_timeout < BLE_HCI_CONN_SPVN_TIMEOUT_MIN) || - (params->supervision_timeout > BLE_HCI_CONN_SPVN_TIMEOUT_MAX)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check connection event length */ - if (params->min_ce_len > params->max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return 0; -} - - -/** - * @brief Converts a return code from the NimBLE stack to a text string. - * @param [in] rc The return code to convert. - * @return A string representation of the return code. - */ -const char* NimBLEUtils::returnCodeToString(int rc) { -#if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT) - switch(rc) { - case 0: - return "SUCCESS"; - case BLE_HS_EAGAIN: - return "Temporary failure; try again."; - case BLE_HS_EALREADY: - return "Operation already in progress or completed."; - case BLE_HS_EINVAL: - return "One or more arguments are invalid."; - case BLE_HS_EMSGSIZE: - return "The provided buffer is too small."; - case BLE_HS_ENOENT: - return "No entry matching the specified criteria."; - case BLE_HS_ENOMEM: - return "Operation failed due to resource exhaustion."; - case BLE_HS_ENOTCONN: - return "No open connection with the specified handle."; - case BLE_HS_ENOTSUP: - return "Operation disabled at compile time."; - case BLE_HS_EAPP: - return "Application callback behaved unexpectedly."; - case BLE_HS_EBADDATA: - return "Command from peer is invalid."; - case BLE_HS_EOS: - return "Mynewt OS error."; - case BLE_HS_ECONTROLLER: - return "Event from controller is invalid."; - case BLE_HS_ETIMEOUT: - return "Operation timed out."; - case BLE_HS_EDONE: - return "Operation completed successfully."; - case BLE_HS_EBUSY: - return "Operation cannot be performed until procedure completes."; - case BLE_HS_EREJECT: - return "Peer rejected a connection parameter update request."; - case BLE_HS_EUNKNOWN: - return "Unexpected failure; catch all."; - case BLE_HS_EROLE: - return "Operation requires different role (e.g., central vs. peripheral)."; - case BLE_HS_ETIMEOUT_HCI: - return "HCI request timed out; controller unresponsive."; - case BLE_HS_ENOMEM_EVT: - return "Controller failed to send event due to memory exhaustion (combined host-controller only)."; - case BLE_HS_ENOADDR: - return "Operation requires an identity address but none configured."; - case BLE_HS_ENOTSYNCED: - return "Attempt to use the host before it is synced with controller."; - case BLE_HS_EAUTHEN: - return "Insufficient authentication."; - case BLE_HS_EAUTHOR: - return "Insufficient authorization."; - case BLE_HS_EENCRYPT: - return "Insufficient encryption level."; - case BLE_HS_EENCRYPT_KEY_SZ: - return "Insufficient key size."; - case BLE_HS_ESTORE_CAP: - return "Storage at capacity."; - case BLE_HS_ESTORE_FAIL: - return "Storage IO error."; - case (0x0100+BLE_ATT_ERR_INVALID_HANDLE ): - return "The attribute handle given was not valid on this server."; - case (0x0100+BLE_ATT_ERR_READ_NOT_PERMITTED ): - return "The attribute cannot be read."; - case (0x0100+BLE_ATT_ERR_WRITE_NOT_PERMITTED ): - return "The attribute cannot be written."; - case (0x0100+BLE_ATT_ERR_INVALID_PDU ): - return "The attribute PDU was invalid."; - case (0x0100+BLE_ATT_ERR_INSUFFICIENT_AUTHEN ): - return "The attribute requires authentication before it can be read or written."; - case (0x0100+BLE_ATT_ERR_REQ_NOT_SUPPORTED ): - return "Attribute server does not support the request received from the client."; - case (0x0100+BLE_ATT_ERR_INVALID_OFFSET ): - return "Offset specified was past the end of the attribute."; - case (0x0100+BLE_ATT_ERR_INSUFFICIENT_AUTHOR ): - return "The attribute requires authorization before it can be read or written."; - case (0x0100+BLE_ATT_ERR_PREPARE_QUEUE_FULL ): - return "Too many prepare writes have been queued."; - case (0x0100+BLE_ATT_ERR_ATTR_NOT_FOUND ): - return "No attribute found within the given attribute handle range."; - case (0x0100+BLE_ATT_ERR_ATTR_NOT_LONG ): - return "The attribute cannot be read or written using the Read Blob Request."; - case (0x0100+BLE_ATT_ERR_INSUFFICIENT_KEY_SZ ): - return "The Encryption Key Size used for encrypting this link is insufficient."; - case (0x0100+BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN ): - return "The attribute value length is invalid for the operation."; - case (0x0100+BLE_ATT_ERR_UNLIKELY ): - return "The attribute request has encountered an error that was unlikely, could not be completed as requested."; - case (0x0100+BLE_ATT_ERR_INSUFFICIENT_ENC ): - return "The attribute requires encryption before it can be read or written."; - case (0x0100+BLE_ATT_ERR_UNSUPPORTED_GROUP ): - return "The attribute type is not a supported grouping attribute as defined by a higher layer specification."; - case (0x0100+BLE_ATT_ERR_INSUFFICIENT_RES ): - return "Insufficient Resources to complete the request."; - case (0x0200+BLE_ERR_UNKNOWN_HCI_CMD ): - return "Unknown HCI Command"; - case (0x0200+BLE_ERR_UNK_CONN_ID ): - return "Unknown Connection Identifier"; - case (0x0200+BLE_ERR_HW_FAIL ): - return "Hardware Failure"; - case (0x0200+BLE_ERR_PAGE_TMO ): - return "Page Timeout"; - case (0x0200+BLE_ERR_AUTH_FAIL ): - return "Authentication Failure"; - case (0x0200+BLE_ERR_PINKEY_MISSING ): - return "PIN or Key Missing"; - case (0x0200+BLE_ERR_MEM_CAPACITY ): - return "Memory Capacity Exceeded"; - case (0x0200+BLE_ERR_CONN_SPVN_TMO ): - return "Connection Timeout"; - case (0x0200+BLE_ERR_CONN_LIMIT ): - return "Connection Limit Exceeded"; - case (0x0200+BLE_ERR_SYNCH_CONN_LIMIT ): - return "Synchronous Connection Limit To A Device Exceeded"; - case (0x0200+BLE_ERR_ACL_CONN_EXISTS ): - return "ACL Connection Already Exists"; - case (0x0200+BLE_ERR_CMD_DISALLOWED ): - return "Command Disallowed"; - case (0x0200+BLE_ERR_CONN_REJ_RESOURCES ): - return "Connection Rejected due to Limited Resources"; - case (0x0200+BLE_ERR_CONN_REJ_SECURITY ): - return "Connection Rejected Due To Security Reasons"; - case (0x0200+BLE_ERR_CONN_REJ_BD_ADDR ): - return "Connection Rejected due to Unacceptable BD_ADDR"; - case (0x0200+BLE_ERR_CONN_ACCEPT_TMO ): - return "Connection Accept Timeout Exceeded"; - case (0x0200+BLE_ERR_UNSUPPORTED ): - return "Unsupported Feature or Parameter Value"; - case (0x0200+BLE_ERR_INV_HCI_CMD_PARMS ): - return "Invalid HCI Command Parameters"; - case (0x0200+BLE_ERR_REM_USER_CONN_TERM ): - return "Remote User Terminated Connection"; - case (0x0200+BLE_ERR_RD_CONN_TERM_RESRCS ): - return "Remote Device Terminated Connection due to Low Resources"; - case (0x0200+BLE_ERR_RD_CONN_TERM_PWROFF ): - return "Remote Device Terminated Connection due to Power Off"; - case (0x0200+BLE_ERR_CONN_TERM_LOCAL ): - return "Connection Terminated By Local Host"; - case (0x0200+BLE_ERR_REPEATED_ATTEMPTS ): - return "Repeated Attempts"; - case (0x0200+BLE_ERR_NO_PAIRING ): - return "Pairing Not Allowed"; - case (0x0200+BLE_ERR_UNK_LMP ): - return "Unknown LMP PDU"; - case (0x0200+BLE_ERR_UNSUPP_REM_FEATURE ): - return "Unsupported Remote Feature / Unsupported LMP Feature"; - case (0x0200+BLE_ERR_SCO_OFFSET ): - return "SCO Offset Rejected"; - case (0x0200+BLE_ERR_SCO_ITVL ): - return "SCO Interval Rejected"; - case (0x0200+BLE_ERR_SCO_AIR_MODE ): - return "SCO Air Mode Rejected"; - case (0x0200+BLE_ERR_INV_LMP_LL_PARM ): - return "Invalid LMP Parameters / Invalid LL Parameters"; - case (0x0200+BLE_ERR_UNSPECIFIED ): - return "Unspecified Error"; - case (0x0200+BLE_ERR_UNSUPP_LMP_LL_PARM ): - return "Unsupported LMP Parameter Value / Unsupported LL Parameter Value"; - case (0x0200+BLE_ERR_NO_ROLE_CHANGE ): - return "Role Change Not Allowed"; - case (0x0200+BLE_ERR_LMP_LL_RSP_TMO ): - return "LMP Response Timeout / LL Response Timeout"; - case (0x0200+BLE_ERR_LMP_COLLISION ): - return "LMP Error Transaction Collision"; - case (0x0200+BLE_ERR_LMP_PDU ): - return "LMP PDU Not Allowed"; - case (0x0200+BLE_ERR_ENCRYPTION_MODE ): - return "Encryption Mode Not Acceptable"; - case (0x0200+BLE_ERR_LINK_KEY_CHANGE ): - return "Link Key cannot be Changed"; - case (0x0200+BLE_ERR_UNSUPP_QOS ): - return "Requested QoS Not Supported"; - case (0x0200+BLE_ERR_INSTANT_PASSED ): - return "Instant Passed"; - case (0x0200+BLE_ERR_UNIT_KEY_PAIRING ): - return "Pairing With Unit Key Not Supported"; - case (0x0200+BLE_ERR_DIFF_TRANS_COLL ): - return "Different Transaction Collision"; - case (0x0200+BLE_ERR_QOS_PARM ): - return "QoS Unacceptable Parameter"; - case (0x0200+BLE_ERR_QOS_REJECTED ): - return "QoS Rejected"; - case (0x0200+BLE_ERR_CHAN_CLASS ): - return "Channel Classification Not Supported"; - case (0x0200+BLE_ERR_INSUFFICIENT_SEC ): - return "Insufficient Security"; - case (0x0200+BLE_ERR_PARM_OUT_OF_RANGE ): - return "Parameter Out Of Mandatory Range"; - case (0x0200+BLE_ERR_PENDING_ROLE_SW ): - return "Role Switch Pending"; - case (0x0200+BLE_ERR_RESERVED_SLOT ): - return "Reserved Slot Violation"; - case (0x0200+BLE_ERR_ROLE_SW_FAIL ): - return "Role Switch Failed"; - case (0x0200+BLE_ERR_INQ_RSP_TOO_BIG ): - return "Extended Inquiry Response Too Large"; - case (0x0200+BLE_ERR_SEC_SIMPLE_PAIR ): - return "Secure Simple Pairing Not Supported By Host"; - case (0x0200+BLE_ERR_HOST_BUSY_PAIR ): - return "Host Busy - Pairing"; - case (0x0200+BLE_ERR_CONN_REJ_CHANNEL ): - return "Connection Rejected, No Suitable Channel Found"; - case (0x0200+BLE_ERR_CTLR_BUSY ): - return "Controller Busy"; - case (0x0200+BLE_ERR_CONN_PARMS ): - return "Unacceptable Connection Parameters"; - case (0x0200+BLE_ERR_DIR_ADV_TMO ): - return "Directed Advertising Timeout"; - case (0x0200+BLE_ERR_CONN_TERM_MIC ): - return "Connection Terminated due to MIC Failure"; - case (0x0200+BLE_ERR_CONN_ESTABLISHMENT ): - return "Connection Failed to be Established"; - case (0x0200+BLE_ERR_MAC_CONN_FAIL ): - return "MAC Connection Failed"; - case (0x0200+BLE_ERR_COARSE_CLK_ADJ ): - return "Coarse Clock Adjustment Rejected"; - case (0x0300+BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD ): - return "Invalid or unsupported incoming L2CAP sig command."; - case (0x0300+BLE_L2CAP_SIG_ERR_MTU_EXCEEDED ): - return "Incoming packet too large."; - case (0x0300+BLE_L2CAP_SIG_ERR_INVALID_CID ): - return "No channel with specified ID."; - case (0x0400+BLE_SM_ERR_PASSKEY ): - return "The user input of passkey failed, for example, the user cancelled the operation."; - case (0x0400+BLE_SM_ERR_OOB ): - return "The OOB data is not available."; - case (0x0400+BLE_SM_ERR_AUTHREQ ): - return "The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices."; - case (0x0400+BLE_SM_ERR_CONFIRM_MISMATCH ): - return "The confirm value does not match the calculated compare value."; - case (0x0400+BLE_SM_ERR_PAIR_NOT_SUPP ): - return "Pairing is not supported by the device."; - case (0x0400+BLE_SM_ERR_ENC_KEY_SZ ): - return "The resultant encryption key size is insufficient for the security requirements of this device."; - case (0x0400+BLE_SM_ERR_CMD_NOT_SUPP ): - return "The SMP command received is not supported on this device."; - case (0x0400+BLE_SM_ERR_UNSPECIFIED ): - return "Pairing failed due to an unspecified reason."; - case (0x0400+BLE_SM_ERR_REPEATED ): - return "Pairing or authentication procedure disallowed, too little time has elapsed since last pairing request or security request."; - case (0x0400+BLE_SM_ERR_INVAL ): - return "Command length is invalid or that a parameter is outside of the specified range."; - case (0x0400+BLE_SM_ERR_DHKEY ): - return "DHKey Check value received doesn't match the one calculated by the local device."; - case (0x0400+BLE_SM_ERR_NUMCMP ): - return "Confirm values in the numeric comparison protocol do not match."; - case (0x0400+BLE_SM_ERR_ALREADY ): - return "Pairing over the LE transport failed - Pairing Request sent over the BR/EDR transport in process."; - case (0x0400+BLE_SM_ERR_CROSS_TRANS ): - return "BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport."; - case (0x0500+BLE_SM_ERR_PASSKEY ): - return "The user input of passkey failed or the user cancelled the operation."; - case (0x0500+BLE_SM_ERR_OOB ): - return "The OOB data is not available."; - case (0x0500+BLE_SM_ERR_AUTHREQ ): - return "The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices."; - case (0x0500+BLE_SM_ERR_CONFIRM_MISMATCH ): - return "The confirm value does not match the calculated compare value."; - case (0x0500+BLE_SM_ERR_PAIR_NOT_SUPP ): - return "Pairing is not supported by the device."; - case (0x0500+BLE_SM_ERR_ENC_KEY_SZ ): - return "The resultant encryption key size is insufficient for the security requirements of this device."; - case (0x0500+BLE_SM_ERR_CMD_NOT_SUPP ): - return "The SMP command received is not supported on this device."; - case (0x0500+BLE_SM_ERR_UNSPECIFIED ): - return "Pairing failed due to an unspecified reason."; - case (0x0500+BLE_SM_ERR_REPEATED ): - return "Pairing or authentication procedure is disallowed because too little time has elapsed since last pairing request or security request."; - case (0x0500+BLE_SM_ERR_INVAL ): - return "Command length is invalid or a parameter is outside of the specified range."; - case (0x0500+BLE_SM_ERR_DHKEY ): - return "Indicates to the remote device that the DHKey Check value received doesn’t match the one calculated by the local device."; - case (0x0500+BLE_SM_ERR_NUMCMP ): - return "Confirm values in the numeric comparison protocol do not match."; - case (0x0500+BLE_SM_ERR_ALREADY ): - return "Pairing over the LE transport failed - Pairing Request sent over the BR/EDR transport in process."; - case (0x0500+BLE_SM_ERR_CROSS_TRANS ): - return "BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport."; - default: - return "Unknown"; - } -#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT) - (void)rc; - return ""; -#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT) -} - - -/** - * @brief Convert the advertising type flag to a string. - * @param advType The type to convert. - * @return A string representation of the advertising flags. - */ -const char* NimBLEUtils::advTypeToString(uint8_t advType) { -#if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT) - switch(advType) { - case BLE_HCI_ADV_TYPE_ADV_IND : //0 - return "Undirected - Connectable / Scannable"; - case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD: //1 - return "Directed High Duty - Connectable"; - case BLE_HCI_ADV_TYPE_ADV_SCAN_IND: //2 - return "Non-Connectable - Scan Response Available"; - case BLE_HCI_ADV_TYPE_ADV_NONCONN_IND: //3 - return "Non-Connectable - No Scan Response"; - case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD: //4 - return "Directed Low Duty - Connectable"; - default: - return "Unknown flag"; - } -#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT) - (void)advType; - return ""; -#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT) -} // adFlagsToString - - -/** - * @brief Create a hex representation of data. - * - * @param [in] target Where to write the hex string. If this is null, we malloc storage. - * @param [in] source The start of the binary data. - * @param [in] length The length of the data to convert. - * @return A pointer to the formatted buffer. - */ -char* NimBLEUtils::buildHexData(uint8_t* target, const uint8_t* source, uint8_t length) { - // Guard against too much data. - if (length > 100) length = 100; - - if (target == nullptr) { - target = (uint8_t*) malloc(length * 2 + 1); - if (target == nullptr) { - NIMBLE_LOGE(LOG_TAG, "buildHexData: malloc failed"); - return nullptr; - } - } - char* startOfData = (char*) target; - - for (int i = 0; i < length; i++) { - sprintf((char*) target, "%.2x", (char) *source); - source++; - target += 2; - } - - // Handle the special case where there was no data. - if (length == 0) { - *startOfData = 0; - } - - return startOfData; -} // buildHexData - - -/** - * @brief Utility function to log the gap event info. - * @param [in] event A pointer to the gap event structure. - * @param [in] arg Unused. - */ -void NimBLEUtils::dumpGapEvent(ble_gap_event *event, void *arg){ - (void)arg; -#if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT) - NIMBLE_LOGD(LOG_TAG, "Received a GAP event: %s", gapEventToString(event->type)); -#else - (void)event; -#endif -} - - -/** - * @brief Convert a GAP event type to a string representation. - * @param [in] eventType The type of event. - * @return A string representation of the event type. - */ -const char* NimBLEUtils::gapEventToString(uint8_t eventType) { -#if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT) - switch (eventType) { - case BLE_GAP_EVENT_CONNECT : //0 - return "BLE_GAP_EVENT_CONNECT "; - - case BLE_GAP_EVENT_DISCONNECT: //1 - return "BLE_GAP_EVENT_DISCONNECT"; - - case BLE_GAP_EVENT_CONN_UPDATE: //3 - return "BLE_GAP_EVENT_CONN_UPDATE"; - - case BLE_GAP_EVENT_CONN_UPDATE_REQ: //4 - return "BLE_GAP_EVENT_CONN_UPDATE_REQ"; - - case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: //5 - return "BLE_GAP_EVENT_L2CAP_UPDATE_REQ"; - - case BLE_GAP_EVENT_TERM_FAILURE: //6 - return "BLE_GAP_EVENT_TERM_FAILURE"; - - case BLE_GAP_EVENT_DISC: //7 - return "BLE_GAP_EVENT_DISC"; - - case BLE_GAP_EVENT_DISC_COMPLETE: //8 - return "BLE_GAP_EVENT_DISC_COMPLETE"; - - case BLE_GAP_EVENT_ADV_COMPLETE: //9 - return "BLE_GAP_EVENT_ADV_COMPLETE"; - - case BLE_GAP_EVENT_ENC_CHANGE: //10 - return "BLE_GAP_EVENT_ENC_CHANGE"; - - case BLE_GAP_EVENT_PASSKEY_ACTION : //11 - return "BLE_GAP_EVENT_PASSKEY_ACTION"; - - case BLE_GAP_EVENT_NOTIFY_RX: //12 - return "BLE_GAP_EVENT_NOTIFY_RX"; - - case BLE_GAP_EVENT_NOTIFY_TX : //13 - return "BLE_GAP_EVENT_NOTIFY_TX"; - - case BLE_GAP_EVENT_SUBSCRIBE : //14 - return "BLE_GAP_EVENT_SUBSCRIBE"; - - case BLE_GAP_EVENT_MTU: //15 - return "BLE_GAP_EVENT_MTU"; - - case BLE_GAP_EVENT_IDENTITY_RESOLVED: //16 - return "BLE_GAP_EVENT_IDENTITY_RESOLVED"; - - case BLE_GAP_EVENT_REPEAT_PAIRING: //17 - return "BLE_GAP_EVENT_REPEAT_PAIRING"; - - case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: //18 - return "BLE_GAP_EVENT_PHY_UPDATE_COMPLETE"; - - case BLE_GAP_EVENT_EXT_DISC: //19 - return "BLE_GAP_EVENT_EXT_DISC"; -#ifdef BLE_GAP_EVENT_PERIODIC_SYNC // IDF 4.0 does not support these - case BLE_GAP_EVENT_PERIODIC_SYNC: //20 - return "BLE_GAP_EVENT_PERIODIC_SYNC"; - - case BLE_GAP_EVENT_PERIODIC_REPORT: //21 - return "BLE_GAP_EVENT_PERIODIC_REPORT"; - - case BLE_GAP_EVENT_PERIODIC_SYNC_LOST: //22 - return "BLE_GAP_EVENT_PERIODIC_SYNC_LOST"; - - case BLE_GAP_EVENT_SCAN_REQ_RCVD: //23 - return "BLE_GAP_EVENT_SCAN_REQ_RCVD"; -#endif - default: - NIMBLE_LOGD(LOG_TAG, "gapEventToString: Unknown event type %d 0x%.2x", eventType, eventType); - return "Unknown event type"; - } -#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT) - (void)eventType; - return ""; -#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT) -} // gapEventToString - -#endif //CONFIG_BT_ENABLED diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEUtils.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEUtils.h deleted file mode 100644 index 006d9352f..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEUtils.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * NimBLEUtils.h - * - * Created: on Jan 25 2020 - * Author H2zero - * - */ - -#ifndef COMPONENTS_NIMBLEUTILS_H_ -#define COMPONENTS_NIMBLEUTILS_H_ - -#include "nimconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#if defined(CONFIG_NIMBLE_CPP_IDF) -#include "host/ble_gap.h" -#else -#include "nimble/nimble/host/include/host/ble_gap.h" -#endif - -/**** FIX COMPILATION ****/ -#undef min -#undef max -/**************************/ - -#include - -typedef struct { - void *pATT; - TaskHandle_t task; - int rc; - void *buf; -} ble_task_data_t; - - -/** - * @brief A BLE Utility class with methods for debugging and general purpose use. - */ -class NimBLEUtils { -public: - static void dumpGapEvent(ble_gap_event *event, void *arg); - static const char* gapEventToString(uint8_t eventType); - static char* buildHexData(uint8_t* target, const uint8_t* source, uint8_t length); - static const char* advTypeToString(uint8_t advType); - static const char* returnCodeToString(int rc); - static int checkConnParams(ble_gap_conn_params* params); -}; - - -#endif // CONFIG_BT_ENABLED -#endif // COMPONENTS_NIMBLEUTILS_H_ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/CODING_STANDARDS.md b/lib/libesp32_div/NimBLE-Arduino/src/nimble/CODING_STANDARDS.md deleted file mode 100644 index d14b9fdb1..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/CODING_STANDARDS.md +++ /dev/null @@ -1,267 +0,0 @@ -# Coding Style for Apache NimBLE - -Apache NimBLE project is part of Apache Mynewt projct and follows its coding -style. - -# Coding Style for Apache Mynewt Core - -This document is meant to define the coding style for Apache Mynewt, and -all subprojects of Apache Mynewt. This covers C and Assembly coding -conventions, *only*. Other languages (such as Go), have their own -coding conventions. - -## Headers - -* All files that are newly written, should have the Apache License clause -at the top of them. - -* For files that are copied from another source, but contain an Apache -compatible license, the original license header shall be maintained. - -* For more information on applying the Apache license, the definitive -source is here: http://www.apache.org/dev/apply-license.html - -* The Apache License clause for the top of files is as follows: - -```no-highlight -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -``` - -## Whitespace and Braces - -* Code must be indented to 4 spaces, tabs should not be used. - -* Do not add whitespace at the end of a line. - -* Put space after keywords (for, if, return, switch, while). - -* for, else, if, while statements must have braces around their -code blocks, i.e., do: - -``` - if (x) { - assert(0); - } else { - assert(0); - } -``` - -Not: - -``` - if (x) - assert(0); - else - assert(0); -``` - -* Braces for statements must be on the same line as the statement. Good: - -``` - for (i = 0; i < 10; i++) { - if (i == 5) { - break; - } else { - continue; - } - } -``` - -Not: - -``` - for (i = 0; i < 10; i++) - { <-- brace must be on same line as for - if (i == 5) { - break; - } <-- no new line between else - else { - continue; - } - } -``` - -* After a function declaration, the braces should be on a newline, i.e. do: - -``` - static void * - function(int var1, int var2) - { -``` - -not: - -``` - static void * - function(int var1, int var2) { -``` - -## Line Length and Wrap - -* Line length should never exceed 79 columns. - -* When you have to wrap a long statement, put the operator at the end of the - line. i.e.: - -``` - if (x && - y == 10 && - b) -``` - -Not: - -``` - if (x - && y == 10 - && b) -``` - -## Comments - -* No C++ style comments allowed. - -* When using a single line comment, put it above the line of code that you -intend to comment, i.e., do: - -``` - /* check variable */ - if (a) { -``` - -Not: - -``` - if (a) { /* check variable */ -``` - - -* All public APIs should be commented with Doxygen style comments describing -purpose, parameters and return values. Private APIs need not be documented. - - -## Header files - -* Header files must contain the following structure: - * Apache License (see above) - * ```#ifdef``` aliasing, to prevent multiple includes - * ```#include``` directives for other required header files - * ```#ifdef __cplusplus``` wrappers to maintain C++ friendly APIs - * Contents of the header file - -* ```#ifdef``` aliasing, shall be in the following format, where -the package name is "os" and the file name is "callout.h": - -```no-highlight -#ifndef _OS_CALLOUT_H -#define _OS_CALLOUT_H -``` - -* ```#include``` directives must happen prior to the cplusplus -wrapper. - -* The cplusplus wrapper must have the following format, and precedes -any contents of the header file: - -```no-highlight -#ifdef __cplusplus -#extern "C" { -##endif -``` - -## Naming - -* Names of functions, structures and variables must be in all lowercase. - -* Names should be as short as possible, but no shorter. - -* Globally visible names must be prefixed with the name of the module, -followed by the '_' character, i.e.: - -``` - os_callout_init(&c) -``` - -Not: - -``` - callout_init(c) -``` - -## Functions - -* No spaces after function names when calling a function, i.e, do: - -``` - rc = function(a) -``` - -Not: - -``` - rc = function (a) -``` - - -* Arguments to function calls should have spaces between the comma, i.e. do: - -``` - rc = function(a, b) -``` - -Not: - -``` - rc = function(a,b) -``` - -* The function type must be on a line by itself preceding the function, i.e. do: - -``` - static void * - function(int var1, int var2) - { -``` - -Not: - -``` - static void *function(int var1, int var2) - { -``` - -* In general, for functions that return values that denote success or error, 0 -shall be success, and non-zero shall be the failure code. - -## Variables and Macros - -* Do not use typedefs for structures. This makes it impossible for -applications to use pointers to those structures opaquely. - -* typedef may be used for non-structure types, where it is beneficial to -hide or alias the underlying type used (e.g. ```os_time_t```.) Indicate -typedefs by applying the ```_t``` marker to them. - -* Place all function-local variable definitions at the top of the function body, before any statements. - -## Compiler Directives - -* Code must compile cleanly with -Wall enabled. - diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/LICENSE b/lib/libesp32_div/NimBLE-Arduino/src/nimble/LICENSE deleted file mode 100644 index 08b9b218a..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/LICENSE +++ /dev/null @@ -1,217 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -This product bundles queue.h 8.5, which is available under the "3-clause BSD" -license. For details, see porting/nimble/include/os/queue.h - -This product partly derives from FreeBSD, which is available under the -"3-clause BSD" license. For details, see: - * porting/nimble/src/os_mbuf.c - -This product bundles Gary S. Brown's CRC32 implementation, which is available -under the following license: - COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or - code or tables extracted from it, as desired without restriction. - -This product bundles tinycrypt, which is available under the "3-clause BSD" -license. For details, and bundled files see: - * ext/tinycrypt/LICENSE diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/NOTICE b/lib/libesp32_div/NimBLE-Arduino/src/nimble/NOTICE deleted file mode 100644 index 02fe5929d..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/NOTICE +++ /dev/null @@ -1,9 +0,0 @@ -Apache Mynewt NimBLE -Copyright 2015-2020 The Apache Software Foundation -Modifications Copyright 2017-2020 Espressif Systems (Shanghai) CO., LTD. - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -Portions of this software were developed at -Runtime Inc, copyright 2015. diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/README.md b/lib/libesp32_div/NimBLE-Arduino/src/nimble/README.md deleted file mode 100644 index 96c636634..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/README.md +++ /dev/null @@ -1,170 +0,0 @@ - - -Apache Mynewt - -## Overview - -Apache NimBLE is an open-source Bluetooth 5.1 stack (both Host & Controller) -that completely replaces the proprietary SoftDevice on Nordic chipsets. It is -part of [Apache Mynewt project](https://github.com/apache/mynewt-core). - -Features highlight: - - Support for 251 byte packet size - - Support for all 4 roles concurrently - Broadcaster, Observer, Peripheral and Central - - Support for up to 32 simultaneous connections. - - Legacy and SC (secure connections) SMP support (pairing and bonding). - - Advertising Extensions. - - Periodic Advertising. - - Coded (aka Long Range) and 2M PHYs. - - Bluetooth Mesh. - -## Supported hardware - -Controller supports Nordic nRF51 and nRF52 chipsets. Host runs on any board -and architecture [supported](https://github.com/apache/mynewt-core#overview) -by Apache Mynewt OS. - - -## Browsing - -If you are browsing around the source tree, and want to see some of the -major functional chunks, here are a few pointers: - -- nimble/controller: Contains code for controller including Link Layer and HCI implementation -([controller](https://github.com/apache/mynewt-nimble/tree/master/nimble/controller)) - -- nimble/drivers: Contains drivers for supported radio transceivers (Nordic nRF51 and nRF52) -([drivers](https://github.com/apache/mynewt-nimble/tree/master/nimble/drivers)) - -- nimble/host: Contains code for host subsystem. This includes protocols like -L2CAP and ATT, support for HCI commands and events, Generic Access Profile (GAP), -Generic Attribute Profile (GATT) and Security Manager (SM). -([host](https://github.com/apache/mynewt-nimble/tree/master/nimble/host)) - -- nimble/host/mesh: Contains code for Bluetooth Mesh subsystem. -([mesh](https://github.com/apache/mynewt-nimble/tree/master/nimble/host/mesh)) - -- nimble/transport: Contains code for supported transport protocols between host -and controller. This includes UART, emSPI and RAM (used in combined build when -host and controller run on same CPU) -([transport](https://github.com/apache/mynewt-nimble/tree/master/nimble/transport)) - -- porting: Contains implementation of NimBLE Porting Layer (NPL) for supported -operating systems -([porting](https://github.com/apache/mynewt-nimble/tree/master/porting)) - -- ext: Contains external libraries used by NimBLE. Those are used if not -provided by OS -([ext](https://github.com/apache/mynewt-nimble/tree/master/ext)) - -- kernel: Contains the core of the RTOS ([kernel/os](https://github.com/apache/mynewt-core/tree/master/kernel/os)) - -## Sample Applications - -There are also some sample applications that show how to Apache Mynewt NimBLE -stack. These sample applications are located in the `apps/` directory of -Apache Mynewt [repo](https://github.com/apache/mynewt-core). Some examples: - -* [blecent](https://github.com/apache/mynewt-nimble/tree/master/apps/blecent): -A basic central device with no user interface. This application scans for -a peripheral that supports the alert notification service (ANS). Upon -discovering such a peripheral, blecent connects and performs a characteristic -read, characteristic write, and notification subscription. -* [blehci](https://github.com/apache/mynewt-nimble/tree/master/apps/blehci): -Implements a BLE controller-only application. A separate host-only -implementation, such as Linux's BlueZ, can interface with this application via -HCI over UART. -* [bleprph](https://github.com/apache/mynewt-nimble/tree/master/apps/bleprph): An - implementation of a minimal BLE peripheral. -* [btshell](https://github.com/apache/mynewt-nimble/tree/master/apps/btshell): A - shell-like application allowing to configure and use most of NimBLE - functionality from command line. -* [bleuart](https://github.com/apache/mynewt-core/tree/master/apps/bleuart): -Implements a simple BLE peripheral that supports the Nordic -UART / Serial Port Emulation service -(https://developer.nordicsemi.com/nRF5_SDK/nRF51_SDK_v8.x.x/doc/8.0.0/s110/html/a00072.html). - -# Getting Help - -If you are having trouble using or contributing to Apache Mynewt NimBLE, or just -want to talk to a human about what you're working on, you can contact us via the -[developers mailing list](mailto:dev@mynewt.apache.org). - -Although not a formal channel, you can also find a number of core developers -on the #mynewt channel on Freenode IRC or #general channel on [Mynewt Slack](https://mynewt.slack.com/join/shared_invite/enQtNjA1MTg0NzgyNzg3LTcyMmZiOGQzOGMxM2U4ODFmMTIwNjNmYTE5Y2UwYjQwZWIxNTE0MTUzY2JmMTEzOWFjYWZkNGM0YmM4MzAxNWQ) - -Also, be sure to checkout the [Frequently Asked Questions](https://mynewt.apache.org/faq/answers) -for some help troubleshooting first. - -# Contributing - -Anybody who works with Apache Mynewt can be a contributing member of the -community that develops and deploys it. The process of releasing an operating -system for microcontrollers is never done: and we welcome your contributions -to that effort. - -More information can be found at the Community section of the Apache Mynewt -website, located [here](https://mynewt.apache.org/community). - -## Pull Requests - -Apache Mynewt welcomes pull request via Github. Discussions are done on Github, -but depending on the topic, can also be relayed to the official Apache Mynewt -developer mailing list dev@mynewt.apache.org. - -If you are suggesting a new feature, please email the developer list directly, -with a description of the feature you are planning to work on. - -## Filing Bugs - -Bugs can be filed on the -[Apache Mynewt NimBLE Issues](https://github.com/apache/mynewt-nimble/issues). -Please label the issue as a "Bug". - -Where possible, please include a self-contained reproduction case! - -## Feature Requests - -Feature requests should also be filed on the -[Apache Mynewt NimBLE Bug Tracker](https://github.com/apache/mynewt-nimble/issues). -Please label the issue as a "Feature" or "Enhancement" depending on the scope. - -## Writing Tests - -We love getting newt tests! Apache Mynewt is a huge undertaking, and improving -code coverage is a win for every Apache Mynewt user. - - - -# License - -The code in this repository is all under either the Apache 2 license, or a -license compatible with the Apache 2 license. See the LICENSE file for more -information. diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/RELEASE_NOTES.md b/lib/libesp32_div/NimBLE-Arduino/src/nimble/RELEASE_NOTES.md deleted file mode 100644 index 99810a718..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/RELEASE_NOTES.md +++ /dev/null @@ -1,22 +0,0 @@ -# RELEASE NOTES - -24 March 2021 - Apache NimBLE v1.4.0 - -For full release notes, please visit the -[Apache Mynewt Wiki](https://cwiki.apache.org/confluence/display/MYNEWT/Release+Notes). - -Apache NimBLE is an open-source Bluetooth 5.1 stack (both Host & Controller) that completely -replaces the proprietary SoftDevice on Nordic chipsets. - -New features in this version of NimBLE include: - -* Support for PHY on Dialog Configurable MAC (CMAC) -* Support for PHY on Nordic nRF5340 -* Support for Apache NuttX port of NimBLE -* Controller-to-host flow control support -* Support for USB transport -* Various bugfixes - -If working on next-generation RTOS and Bluetooth protocol stack -sounds exciting to you, get in touch, by sending a mail to the Apache Mynewt -Developer's list, dev@mynewt.apache.org. diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/console/console.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/console/console.h deleted file mode 100644 index 4b32c8b15..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/console/console.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __CONSOLE_H__ -#define __CONSOLE_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define console_printf(_fmt, ...) printf(_fmt, ##__VA_ARGS__) - -#ifdef __cplusplus -} -#endif - -#endif /* __CONSOLE_H__ */ \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/esp-hci/include/esp_compiler.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/esp-hci/include/esp_compiler.h deleted file mode 100644 index 917c66025..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/esp-hci/include/esp_compiler.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2016-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef __ESP_COMPILER_H -#define __ESP_COMPILER_H - -/* - * The likely and unlikely macro pairs: - * These macros are useful to place when application - * knows the majority ocurrence of a decision paths, - * placing one of these macros can hint the compiler - * to reorder instructions producing more optimized - * code. - */ -#if (CONFIG_COMPILER_OPTIMIZATION_PERF) -#ifndef likely -#define likely(x) __builtin_expect(!!(x), 1) -#endif -#ifndef unlikely -#define unlikely(x) __builtin_expect(!!(x), 0) -#endif -#else -#ifndef likely -#define likely(x) (x) -#endif -#ifndef unlikely -#define unlikely(x) (x) -#endif -#endif - -/* - * Utility macros used for designated initializers, which work differently - * in C99 and C++ standards mainly for aggregate types. - * The member separator, comma, is already part of the macro, please omit the trailing comma. - * Usage example: - * struct config_t { char* pchr; char arr[SIZE]; } config = { - * ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(pchr) - * ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(arr, "Value") - * }; - */ -#ifdef __cplusplus -#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(member, value) { .member = value }, -#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(member) .member = { }, -#else -#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(member, value) .member = value, -#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(member) -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/esp-hci/include/esp_nimble_hci.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/esp-hci/include/esp_nimble_hci.h deleted file mode 100644 index 5d98edf57..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/esp-hci/include/esp_nimble_hci.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifdef ESP_PLATFORM -#ifndef __ESP_NIMBLE_HCI_H__ -#define __ESP_NIMBLE_HCI_H__ - -#include "nimble/nimble/include/nimble/ble_hci_trans.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define BLE_HCI_UART_H4_NONE 0x00 -#define BLE_HCI_UART_H4_CMD 0x01 -#define BLE_HCI_UART_H4_ACL 0x02 -#define BLE_HCI_UART_H4_SCO 0x03 -#define BLE_HCI_UART_H4_EVT 0x04 - -/** - * @brief Initialize VHCI transport layer between NimBLE Host and - * ESP Bluetooth controller - * - * This function initializes the transport buffers to be exchanged - * between NimBLE host and ESP controller. It also registers required - * host callbacks with the controller. - * - * @return - * - ESP_OK if the initialization is successful - * - Appropriate error code from esp_err_t in case of an error - */ -esp_err_t esp_nimble_hci_init(void); - -/** - * @brief Initialize ESP Bluetooth controller(link layer) and VHCI transport - * layer between NimBLE Host and ESP Bluetooth controller - * - * This function initializes ESP controller in BLE only mode and the - * transport buffers to be exchanged between NimBLE host and ESP controller. - * It also registers required host callbacks with the controller. - * - * Below is the sequence of APIs to be called to init/enable NimBLE host and ESP controller: - * - * @code{c} - * void ble_host_task(void *param) - * { - * nimble_port_run(); //This function will return only when nimble_port_stop() is executed. - * nimble_port_freertos_deinit(); - * } - * - * int ret = esp_nimble_hci_and_controller_init(); - * if (ret != ESP_OK) { - ESP_LOGE(TAG, "esp_nimble_hci_and_controller_init() failed with error: %d", ret); - * return; - * } - * - * nimble_port_init(); - * - * //Initialize the NimBLE Host configuration - * - * nimble_port_freertos_init(ble_host_task); - * @endcode - * - * nimble_port_freertos_init() is an optional call that creates a new task in which the NimBLE - * host will run. The task function should have a call to nimble_port_run(). If a separate task - * is not required, calling nimble_port_run() will run the NimBLE host in the current task. - * - * @return - * - ESP_OK if the initialization is successful - * - Appropriate error code from esp_err_t in case of an error - */ -esp_err_t esp_nimble_hci_and_controller_init(void); - -/** - * @brief Deinitialize VHCI transport layer between NimBLE Host and - * ESP Bluetooth controller - * - * @note This function should be called after the NimBLE host is deinitialized. - * - * @return - * - ESP_OK if the deinitialization is successful - * - Appropriate error codes from esp_err_t in case of an error - */ -esp_err_t esp_nimble_hci_deinit(void); - -/** - * @brief Deinitialize VHCI transport layer between NimBLE Host and - * ESP Bluetooth controller and disable and deinitialize the controller - * - * @note This function should not be executed in the context of Bluetooth host task. - * - * @note This function should be called after the NimBLE host is deinitialized. - * - * Below is the sequence of APIs to be called to disable/deinit NimBLE host and ESP controller: - * - * @code{c} - * int ret = nimble_port_stop(); - * if (ret == 0) { - * nimble_port_deinit(); - * - * ret = esp_nimble_hci_and_controller_deinit(); - * if (ret != ESP_OK) { - ESP_LOGE(TAG, "esp_nimble_hci_and_controller_deinit() failed with error: %d", ret); - * } - * } - * @endcode - * - * If nimble_port_freertos_init() is used during initialization, then - * nimble_port_freertos_deinit() should be called in the host task after nimble_port_run(). - * - * @return - * - ESP_OK if the deinitialization is successful - * - Appropriate error codes from esp_err_t in case of an error - */ -esp_err_t esp_nimble_hci_and_controller_deinit(void); - -#ifdef __cplusplus -} -#endif - -#endif /* __ESP_NIMBLE_HCI_H__ */ -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/esp-hci/src/esp_nimble_hci.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/esp-hci/src/esp_nimble_hci.c deleted file mode 100644 index 8ae48a9c7..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/esp-hci/src/esp_nimble_hci.c +++ /dev/null @@ -1,585 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifdef ESP_PLATFORM - -#include -#include "nimble/porting/nimble/include/sysinit/sysinit.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "nimble/nimble/host/include/host/ble_hs.h" -#include "nimble/porting/nimble/include/nimble/nimble_port.h" -#include "nimble/porting/npl/freertos/include/nimble/nimble_port_freertos.h" -#include "../include/esp_nimble_hci.h" -#include "../../port/include/esp_nimble_mem.h" -#include -#include -#include "../include/esp_compiler.h" -/* IPC is used to improve performance when calls come from a processor not running the NimBLE stack */ -/* but does not exist for solo */ -#ifndef CONFIG_FREERTOS_UNICORE - #include "esp_ipc.h" -#endif - -#define NIMBLE_VHCI_TIMEOUT_MS 2000 -#define BLE_HCI_EVENT_HDR_LEN (2) -#define BLE_HCI_CMD_HDR_LEN (3) - -static ble_hci_trans_rx_cmd_fn *ble_hci_rx_cmd_hs_cb; -static void *ble_hci_rx_cmd_hs_arg; - -static ble_hci_trans_rx_acl_fn *ble_hci_rx_acl_hs_cb; -static void *ble_hci_rx_acl_hs_arg; - -static struct os_mbuf_pool ble_hci_acl_mbuf_pool; -static struct os_mempool_ext ble_hci_acl_pool; -/* - * The MBUF payload size must accommodate the HCI data header size plus the - * maximum ACL data packet length. The ACL block size is the size of the - * mbufs we will allocate. - */ -#define ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) \ - + BLE_MBUF_MEMBLOCK_OVERHEAD \ - + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) - -static os_membuf_t *ble_hci_acl_buf; - -static struct os_mempool ble_hci_cmd_pool; -static os_membuf_t *ble_hci_cmd_buf; - -static struct os_mempool ble_hci_evt_hi_pool; -static os_membuf_t *ble_hci_evt_hi_buf; - -static struct os_mempool ble_hci_evt_lo_pool; -static os_membuf_t *ble_hci_evt_lo_buf; - -static SemaphoreHandle_t vhci_send_sem; -const static char *TAG = "NimBLE"; - -int os_msys_buf_alloc(void); -void os_msys_buf_free(void); - -void ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb, - void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg) -{ - ble_hci_rx_cmd_hs_cb = cmd_cb; - ble_hci_rx_cmd_hs_arg = cmd_arg; - ble_hci_rx_acl_hs_cb = acl_cb; - ble_hci_rx_acl_hs_arg = acl_arg; -} - -/* Added; Called from the core NimBLE is running on, not used for unicore */ -#ifndef CONFIG_FREERTOS_UNICORE -void ble_hci_trans_hs_cmd_tx_on_core(void *arg) -{ - // Ugly but necessary as the arduino core does not provide enough IPC stack for variables. - esp_vhci_host_send_packet((uint8_t*)arg, *((uint8_t*)arg + 3) + 1 + BLE_HCI_CMD_HDR_LEN); -} -#endif - -/* Modified to use ipc calls in arduino to correct performance issues */ -int ble_hci_trans_hs_cmd_tx(uint8_t *cmd) -{ - uint16_t len; - uint8_t rc = 0; - - assert(cmd != NULL); - *cmd = BLE_HCI_UART_H4_CMD; - len = BLE_HCI_CMD_HDR_LEN + cmd[3] + 1; - if (!esp_vhci_host_check_send_available()) { - ESP_LOGD(TAG, "Controller not ready to receive packets"); - } - - if (xSemaphoreTake(vhci_send_sem, NIMBLE_VHCI_TIMEOUT_MS / portTICK_PERIOD_MS) == pdTRUE) { -/* esp_ipc_call_blocking does not exist for solo */ -#ifndef CONFIG_FREERTOS_UNICORE - if (xPortGetCoreID() != CONFIG_BT_NIMBLE_PINNED_TO_CORE && !xPortInIsrContext()) { - esp_ipc_call_blocking(CONFIG_BT_NIMBLE_PINNED_TO_CORE, - ble_hci_trans_hs_cmd_tx_on_core, cmd); - } else { - esp_vhci_host_send_packet(cmd, len); - } -#else /* Unicore */ - esp_vhci_host_send_packet(cmd, len); -#endif - } else { - rc = BLE_HS_ETIMEOUT_HCI; - } - - ble_hci_trans_buf_free(cmd); - return rc; -} - -int ble_hci_trans_ll_evt_tx(uint8_t *hci_ev) -{ - int rc = ESP_FAIL; - - if (ble_hci_rx_cmd_hs_cb) { - rc = ble_hci_rx_cmd_hs_cb(hci_ev, ble_hci_rx_cmd_hs_arg); - } - return rc; -} - -/* Added; Called from the core NimBLE is running on, not used for unicore */ -#ifndef CONFIG_FREERTOS_UNICORE -void ble_hci_trans_hs_acl_tx_on_core(void *arg) -{ - // Ugly but necessary as the arduino core does not provide enough IPC stack for variables. - esp_vhci_host_send_packet((uint8_t*)arg + 2, *(uint16_t*)arg); -} -#endif - -/* Modified to use ipc calls in arduino to correct performance issues */ -int ble_hci_trans_hs_acl_tx(struct os_mbuf *om) -{ - uint16_t len = 0; - uint8_t data[MYNEWT_VAL(BLE_ACL_BUF_SIZE) + 3], rc = 0; -#ifndef CONFIG_FREERTOS_UNICORE - bool tx_using_nimble_core = 0; -#endif - /* If this packet is zero length, just free it */ - if (OS_MBUF_PKTLEN(om) == 0) { - os_mbuf_free_chain(om); - return 0; - } - - if (!esp_vhci_host_check_send_available()) { - ESP_LOGD(TAG, "Controller not ready to receive packets"); - } - - len = 1 + OS_MBUF_PKTLEN(om); -/* Don't check core ID if unicore */ -#ifndef CONFIG_FREERTOS_UNICORE - tx_using_nimble_core = xPortGetCoreID() != CONFIG_BT_NIMBLE_PINNED_TO_CORE; - if (tx_using_nimble_core && !xPortInIsrContext()) { - data[0] = len; - data[1] = (len >> 8); - data[2] = BLE_HCI_UART_H4_ACL; - os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[3]); - } else { - data[0] = BLE_HCI_UART_H4_ACL; - os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[1]); - } -#else /* Unicore */ - data[0] = BLE_HCI_UART_H4_ACL; - os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[1]); -#endif - - if (xSemaphoreTake(vhci_send_sem, NIMBLE_VHCI_TIMEOUT_MS / portTICK_PERIOD_MS) == pdTRUE) { -/* esp_ipc_call_blocking does not exist for solo */ -#ifndef CONFIG_FREERTOS_UNICORE - if (tx_using_nimble_core && !xPortInIsrContext()) { - esp_ipc_call_blocking(CONFIG_BT_NIMBLE_PINNED_TO_CORE, - ble_hci_trans_hs_acl_tx_on_core, data); - } else { - esp_vhci_host_send_packet(data, len); - } -#else /* Unicore */ - esp_vhci_host_send_packet(data, len); -#endif - } else { - rc = BLE_HS_ETIMEOUT_HCI; - } - - os_mbuf_free_chain(om); - - return rc; -} - -int ble_hci_trans_ll_acl_tx(struct os_mbuf *om) -{ - int rc = ESP_FAIL; - - if (ble_hci_rx_acl_hs_cb) { - rc = ble_hci_rx_acl_hs_cb(om, ble_hci_rx_acl_hs_arg); - } - return rc; -} - -uint8_t *ble_hci_trans_buf_alloc(int type) -{ - uint8_t *buf; - - switch (type) { - case BLE_HCI_TRANS_BUF_CMD: - buf = os_memblock_get(&ble_hci_cmd_pool); - break; - - case BLE_HCI_TRANS_BUF_EVT_HI: - buf = os_memblock_get(&ble_hci_evt_hi_pool); - if (buf == NULL) { - /* If no high-priority event buffers remain, try to grab a - * low-priority one. - */ - buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - } - break; - - case BLE_HCI_TRANS_BUF_EVT_LO: - buf = os_memblock_get(&ble_hci_evt_lo_pool); - break; - - default: - assert(0); - buf = NULL; - } - - return buf; -} - -void ble_hci_trans_buf_free(uint8_t *buf) -{ - int rc; - /* XXX: this may look a bit odd, but the controller uses the command - * buffer to send back the command complete/status as an immediate - * response to the command. This was done to insure that the controller - * could always send back one of these events when a command was received. - * Thus, we check to see which pool the buffer came from so we can free - * it to the appropriate pool - */ - if (os_memblock_from(&ble_hci_evt_hi_pool, buf)) { - rc = os_memblock_put(&ble_hci_evt_hi_pool, buf); - assert(rc == 0); - } else if (os_memblock_from(&ble_hci_evt_lo_pool, buf)) { - rc = os_memblock_put(&ble_hci_evt_lo_pool, buf); - assert(rc == 0); - } else { - assert(os_memblock_from(&ble_hci_cmd_pool, buf)); - rc = os_memblock_put(&ble_hci_cmd_pool, buf); - assert(rc == 0); - } -} - -/** - * Unsupported; the RAM transport does not have a dedicated ACL data packet - * pool. - */ -int ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg) -{ - ble_hci_acl_pool.mpe_put_cb = cb; - ble_hci_acl_pool.mpe_put_arg = arg; - return 0; -} - -int ble_hci_trans_reset(void) -{ - /* No work to do. All allocated buffers are owned by the host or - * controller, and they will get freed by their owners. - */ - return 0; -} - -/** - * Allocates a buffer (mbuf) for ACL operation. - * - * @return The allocated buffer on success; - * NULL on buffer exhaustion. - */ -static struct os_mbuf *ble_hci_trans_acl_buf_alloc(void) -{ - struct os_mbuf *m; - uint8_t usrhdr_len; - -#if MYNEWT_VAL(BLE_DEVICE) - usrhdr_len = sizeof(struct ble_mbuf_hdr); -#elif MYNEWT_VAL(BLE_HS_FLOW_CTRL) - usrhdr_len = BLE_MBUF_HS_HDR_LEN; -#else - usrhdr_len = 0; -#endif - - m = os_mbuf_get_pkthdr(&ble_hci_acl_mbuf_pool, usrhdr_len); - return m; -} - -static void ble_hci_rx_acl(uint8_t *data, uint16_t len) -{ - struct os_mbuf *m; - int rc; - int sr; - if (len < BLE_HCI_DATA_HDR_SZ || len > MYNEWT_VAL(BLE_ACL_BUF_SIZE)) { - return; - } - - m = ble_hci_trans_acl_buf_alloc(); - - if (!m) { - ESP_LOGE(TAG, "%s failed to allocate ACL buffers; increase ACL_BUF_COUNT", __func__); - return; - } - if ((rc = os_mbuf_append(m, data, len)) != 0) { - ESP_LOGE(TAG, "%s failed to os_mbuf_append; rc = %d", __func__, rc); - os_mbuf_free_chain(m); - return; - } - OS_ENTER_CRITICAL(sr); - if (ble_hci_rx_acl_hs_cb) { - ble_hci_rx_acl_hs_cb(m, NULL); - } - OS_EXIT_CRITICAL(sr); -} - -static void ble_hci_transport_init(void) -{ - int rc; - - /* Ensure this function only gets called by sysinit. */ - SYSINIT_ASSERT_ACTIVE(); - - rc = os_mempool_ext_init(&ble_hci_acl_pool, - MYNEWT_VAL(BLE_ACL_BUF_COUNT), - ACL_BLOCK_SIZE, - ble_hci_acl_buf, - "ble_hci_acl_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mbuf_pool_init(&ble_hci_acl_mbuf_pool, - &ble_hci_acl_pool.mpe_mp, - ACL_BLOCK_SIZE, - MYNEWT_VAL(BLE_ACL_BUF_COUNT)); - SYSINIT_PANIC_ASSERT(rc == 0); - - /* - * Create memory pool of HCI command buffers. NOTE: we currently dont - * allow this to be configured. The controller will only allow one - * outstanding command. We decided to keep this a pool in case we allow - * allow the controller to handle more than one outstanding command. - */ - rc = os_mempool_init(&ble_hci_cmd_pool, - 1, - BLE_HCI_TRANS_CMD_SZ, - ble_hci_cmd_buf, - "ble_hci_cmd_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_evt_hi_pool, - MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - ble_hci_evt_hi_buf, - "ble_hci_evt_hi_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_evt_lo_pool, - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - ble_hci_evt_lo_buf, - "ble_hci_evt_lo_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); -} - -/* - * @brief: BT controller callback function, used to notify the upper layer that - * controller is ready to receive command - */ -static void controller_rcv_pkt_ready(void) -{ - if (vhci_send_sem) { - xSemaphoreGive(vhci_send_sem); - } -} - -/* - * @brief: BT controller callback function, to transfer data packet to the host - */ -static int host_rcv_pkt(uint8_t *data, uint16_t len) -{ - - if (data[0] == BLE_HCI_UART_H4_EVT) { - uint8_t *evbuf; - int totlen; - int rc; - - totlen = BLE_HCI_EVENT_HDR_LEN + data[2]; - assert(totlen <= UINT8_MAX + BLE_HCI_EVENT_HDR_LEN); - - if (totlen > MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) { - ESP_LOGE(TAG, "Received HCI data length at host (%d) exceeds maximum configured HCI event buffer size (%d).", - totlen, MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)); - ble_hs_sched_reset(BLE_HS_ECONTROLLER); - return 0; - } - - if (data[1] == BLE_HCI_EVCODE_HW_ERROR) { - assert(0); - } - - /* Allocate LE Advertising Report Event from lo pool only */ - if ((data[1] == BLE_HCI_EVCODE_LE_META) && (data[3] == BLE_HCI_LE_SUBEV_ADV_RPT)) { - evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - /* Skip advertising report if we're out of memory */ - if (!evbuf) { - return 0; - } - } else { - evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - assert(evbuf != NULL); - } - - memcpy(evbuf, &data[1], totlen); - - rc = ble_hci_trans_ll_evt_tx(evbuf); - assert(rc == 0); - } else if (data[0] == BLE_HCI_UART_H4_ACL) { - ble_hci_rx_acl(data + 1, len - 1); - } - return 0; -} - -static const esp_vhci_host_callback_t vhci_host_cb = { - .notify_host_send_available = controller_rcv_pkt_ready, - .notify_host_recv = host_rcv_pkt, -}; - -static void ble_buf_free(void) -{ - os_msys_buf_free(); - - nimble_platform_mem_free(ble_hci_evt_hi_buf); - ble_hci_evt_hi_buf = NULL; - nimble_platform_mem_free(ble_hci_evt_lo_buf); - ble_hci_evt_lo_buf = NULL; - nimble_platform_mem_free(ble_hci_cmd_buf); - ble_hci_cmd_buf = NULL; - nimble_platform_mem_free(ble_hci_acl_buf); - ble_hci_acl_buf = NULL; -} - -static esp_err_t ble_buf_alloc(void) -{ - if (os_msys_buf_alloc()) { - return ESP_ERR_NO_MEM; - } - - ble_hci_evt_hi_buf = (os_membuf_t *) nimble_platform_mem_calloc(1, - (sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)))); - - ble_hci_evt_lo_buf = (os_membuf_t *) nimble_platform_mem_calloc(1, - (sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)))); - - ble_hci_cmd_buf = (os_membuf_t *) nimble_platform_mem_calloc(1, - (sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ))); - - ble_hci_acl_buf = (os_membuf_t *) nimble_platform_mem_calloc(1, - (sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT), - ACL_BLOCK_SIZE))); - - if (!ble_hci_evt_hi_buf || !ble_hci_evt_lo_buf || !ble_hci_cmd_buf || !ble_hci_acl_buf) { - ble_buf_free(); - return ESP_ERR_NO_MEM; - } - return ESP_OK; -} - -esp_err_t esp_nimble_hci_init(void) -{ - esp_err_t ret; - - ret = ble_buf_alloc(); - if (ret != ESP_OK) { - goto err; - } - if ((ret = esp_vhci_host_register_callback(&vhci_host_cb)) != ESP_OK) { - goto err; - } - - ble_hci_transport_init(); - - vhci_send_sem = xSemaphoreCreateBinary(); - if (vhci_send_sem == NULL) { - ret = ESP_ERR_NO_MEM; - goto err; - } - - xSemaphoreGive(vhci_send_sem); - - return ret; -err: - ble_buf_free(); - return ret; - -} - -esp_err_t esp_nimble_hci_and_controller_init(void) -{ - esp_err_t ret; - - esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); - - esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); - - if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) { - return ret; - } - - if ((ret = esp_bt_controller_enable(ESP_BT_MODE_BLE)) != ESP_OK) { - return ret; - } - return esp_nimble_hci_init(); -} - -static esp_err_t ble_hci_transport_deinit(void) -{ - int ret = 0; - - ret += os_mempool_clear(&ble_hci_evt_lo_pool); - - ret += os_mempool_clear(&ble_hci_evt_hi_pool); - - ret += os_mempool_clear(&ble_hci_cmd_pool); - - ret += os_mempool_ext_clear(&ble_hci_acl_pool); - - if (ret) { - return ESP_FAIL; - } else { - return ESP_OK; - } -} - -esp_err_t esp_nimble_hci_deinit(void) -{ - if (vhci_send_sem) { - /* Dummy take & give semaphore before deleting */ - xSemaphoreTake(vhci_send_sem, portMAX_DELAY); - xSemaphoreGive(vhci_send_sem); - vSemaphoreDelete(vhci_send_sem); - vhci_send_sem = NULL; - } - esp_err_t ret = ble_hci_transport_deinit(); - if (ret != ESP_OK) { - return ret; - } - - ble_buf_free(); - - return ESP_OK; -} - -esp_err_t esp_nimble_hci_and_controller_deinit(void) -{ - int ret; - ret = esp_nimble_hci_deinit(); - if (ret != ESP_OK) { - return ret; - } - - ret = esp_bt_controller_disable(); - if (ret != ESP_OK) { - return ret; - } - - ret = esp_bt_controller_deinit(); - if (ret != ESP_OK) { - return ret; - } - - return ESP_OK; -} - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/port/include/esp_nimble_cfg.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/port/include/esp_nimble_cfg.h deleted file mode 100644 index 3b1e4e3ae..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/port/include/esp_nimble_cfg.h +++ /dev/null @@ -1,1474 +0,0 @@ - -#ifndef __ESP_NIMBLE_CFG__ -#define __ESP_NIMBLE_CFG__ -#include "nimconfig.h" - -/** - * This macro exists to ensure code includes this header when needed. If code - * checks the existence of a setting directly via ifdef without including this - * header, the setting macro will silently evaluate to 0. In contrast, an - * attempt to use these macros without including this header will result in a - * compiler error. - */ -#define MYNEWT_VAL(x) MYNEWT_VAL_ ## x - -/*** kernel/os */ -#ifndef MYNEWT_VAL_MSYS_1_BLOCK_COUNT -#ifdef CONFIG_BT_NIMBLE_MESH -#define MYNEWT_VAL_MSYS_1_BLOCK_COUNT (CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT + 8) -#else -#define MYNEWT_VAL_MSYS_1_BLOCK_COUNT CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT -#endif -#endif - -#ifndef MYNEWT_VAL_MSYS_1_BLOCK_SIZE -#define MYNEWT_VAL_MSYS_1_BLOCK_SIZE (292) -#endif - -#ifndef MYNEWT_VAL_MSYS_1_SANITY_MIN_COUNT -#define MYNEWT_VAL_MSYS_1_SANITY_MIN_COUNT (0) -#endif - -#ifndef MYNEWT_VAL_MSYS_2_BLOCK_COUNT -#define MYNEWT_VAL_MSYS_2_BLOCK_COUNT (0) -#endif - -#ifndef MYNEWT_VAL_MSYS_2_BLOCK_SIZE -#define MYNEWT_VAL_MSYS_2_BLOCK_SIZE (0) -#endif - -#ifndef MYNEWT_VAL_OS_CPUTIME_FREQ -#define MYNEWT_VAL_OS_CPUTIME_FREQ (1000000) -#endif - -#ifndef MYNEWT_VAL_OS_CPUTIME_TIMER_NUM -#define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (0) -#endif - -/*** nimble */ -#ifndef MYNEWT_VAL_BLE_EXT_ADV -#define MYNEWT_VAL_BLE_EXT_ADV (CONFIG_BT_NIMBLE_EXT_ADV) -#endif - -#ifndef MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE -#ifdef CONFIG_BT_NIMBLE_EXT_ADV -#define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (CONFIG_BT_NIMBLE_MAX_EXT_ADV_DATA_LEN) -#else -#define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_MAX_CONNECTIONS -#define MYNEWT_VAL_BLE_MAX_CONNECTIONS CONFIG_BT_NIMBLE_MAX_CONNECTIONS -#endif - -#ifndef MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES -#ifdef CONFIG_BT_NIMBLE_EXT_ADV -#define MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES (CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES) -#else -#define MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_MAX_PERIODIC_SYNCS -#ifdef CONFIG_BT_NIMBLE_ENABLE_PERIODIC_ADV -#define MYNEWT_VAL_BLE_MAX_PERIODIC_SYNCS (CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS) -#else -#define MYNEWT_VAL_BLE_MAX_PERIODIC_SYNCS (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER -#ifdef CONFIG_BT_NIMBLE_ROLE_BROADCASTER -#define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) -#else -#define MYNEWT_VAL_BLE_ROLE_BROADCASTER (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_ROLE_CENTRAL -#ifdef CONFIG_BT_NIMBLE_ROLE_CENTRAL -#define MYNEWT_VAL_BLE_ROLE_CENTRAL (1) -#else -#define MYNEWT_VAL_BLE_ROLE_CENTRAL (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_ROLE_OBSERVER -#ifdef CONFIG_BT_NIMBLE_ROLE_OBSERVER -#define MYNEWT_VAL_BLE_ROLE_OBSERVER (1) -#else -#define MYNEWT_VAL_BLE_ROLE_OBSERVER (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_ROLE_PERIPHERAL -#ifdef CONFIG_BT_NIMBLE_ROLE_PERIPHERAL -#define MYNEWT_VAL_BLE_ROLE_PERIPHERAL (1) -#else -#define MYNEWT_VAL_BLE_ROLE_PERIPHERAL (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_WHITELIST -#define MYNEWT_VAL_BLE_WHITELIST (1) -#endif - -/*** @apache-mynewt-nimble/nimble/controller */ -#ifndef MYNEWT_VAL_BLE_DEVICE -#define MYNEWT_VAL_BLE_DEVICE (0) -#endif - -/* Overridden by @apache-mynewt-nimble/nimble/controller (defined by @apache-mynewt-nimble/nimble/controller) */ -#ifndef MYNEWT_VAL_BLE_HW_WHITELIST_ENABLE -#define MYNEWT_VAL_BLE_HW_WHITELIST_ENABLE (0) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_ADD_STRICT_SCHED_PERIODS -#define MYNEWT_VAL_BLE_LL_ADD_STRICT_SCHED_PERIODS (0) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ (1) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_DATA_LEN_EXT -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_DATA_LEN_EXT (1) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_EXT_SCAN_FILT -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_EXT_SCAN_FILT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_2M_PHY -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_2M_PHY (0) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CODED_PHY -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CODED_PHY (0) -#endif - -/* Overridden by @apache-mynewt-nimble/nimble/controller (defined by @apache-mynewt-nimble/nimble/controller) */ -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CSA2 -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CSA2 (1) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION (1) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_PING -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_PING (MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV (MYNEWT_VAL_BLE_EXT_ADV) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PRIVACY -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PRIVACY (1) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG (1) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_CONN_INIT_MAX_TX_BYTES -#define MYNEWT_VAL_BLE_LL_CONN_INIT_MAX_TX_BYTES (27) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_CONN_INIT_MIN_WIN_OFFSET -#define MYNEWT_VAL_BLE_LL_CONN_INIT_MIN_WIN_OFFSET (0) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_CONN_INIT_SLOTS -#define MYNEWT_VAL_BLE_LL_CONN_INIT_SLOTS (4) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_DIRECT_TEST_MODE -#define MYNEWT_VAL_BLE_LL_DIRECT_TEST_MODE (0) -#endif - -/* Overridden by @apache-mynewt-nimble/nimble/controller (defined by @apache-mynewt-nimble/nimble/controller) */ -#ifndef MYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT -#define MYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT (5) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_MASTER_SCA -#define MYNEWT_VAL_BLE_LL_MASTER_SCA (4) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE -#define MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE (251) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_MFRG_ID -#define MYNEWT_VAL_BLE_LL_MFRG_ID (0xFFFF) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_NUM_SCAN_DUP_ADVS -#define MYNEWT_VAL_BLE_LL_NUM_SCAN_DUP_ADVS (8) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_NUM_SCAN_RSP_ADVS -#define MYNEWT_VAL_BLE_LL_NUM_SCAN_RSP_ADVS (8) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_OUR_SCA -#define MYNEWT_VAL_BLE_LL_OUR_SCA (60) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_PRIO -#define MYNEWT_VAL_BLE_LL_PRIO (0) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_RESOLV_LIST_SIZE -#define MYNEWT_VAL_BLE_LL_RESOLV_LIST_SIZE (4) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_RNG_BUFSIZE -#define MYNEWT_VAL_BLE_LL_RNG_BUFSIZE (32) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_STRICT_CONN_SCHEDULING -#define MYNEWT_VAL_BLE_LL_STRICT_CONN_SCHEDULING (0) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_SUPP_MAX_RX_BYTES -#define MYNEWT_VAL_BLE_LL_SUPP_MAX_RX_BYTES (MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_SUPP_MAX_TX_BYTES -#define MYNEWT_VAL_BLE_LL_SUPP_MAX_TX_BYTES (MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_SYSVIEW -#define MYNEWT_VAL_BLE_LL_SYSVIEW (0) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_TX_PWR_DBM -#define MYNEWT_VAL_BLE_LL_TX_PWR_DBM (0) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_USECS_PER_PERIOD -#define MYNEWT_VAL_BLE_LL_USECS_PER_PERIOD (3250) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_VND_EVENT_ON_ASSERT -#define MYNEWT_VAL_BLE_LL_VND_EVENT_ON_ASSERT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_LL_WHITELIST_SIZE -#define MYNEWT_VAL_BLE_LL_WHITELIST_SIZE (8) -#endif - -#ifndef MYNEWT_VAL_BLE_LP_CLOCK -#define MYNEWT_VAL_BLE_LP_CLOCK (1) -#endif - -#ifndef MYNEWT_VAL_BLE_NUM_COMP_PKT_RATE -#define MYNEWT_VAL_BLE_NUM_COMP_PKT_RATE ((2 * OS_TICKS_PER_SEC)) -#endif - -#ifndef MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR -#define MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR ((uint8_t[6]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) -#endif - -#ifndef MYNEWT_VAL_BLE_XTAL_SETTLE_TIME -#define MYNEWT_VAL_BLE_XTAL_SETTLE_TIME (0) -#endif - -/*** @apache-mynewt-nimble/nimble/host */ -#ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU -#define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU -#endif - -#ifndef MYNEWT_VAL_BLE_HS_LOG_LVL -#define MYNEWT_VAL_BLE_HS_LOG_LVL CONFIG_BT_NIMBLE_LOG_LEVEL -#endif - -#ifndef MYNEWT_VAL_BLE_PERIODIC_ADV -#ifdef CONFIG_BT_NIMBLE_EXT_ADV -#define MYNEWT_VAL_BLE_PERIODIC_ADV (CONFIG_BT_NIMBLE_ENABLE_PERIODIC_ADV) -#else -#define MYNEWT_VAL_BLE_PERIODIC_ADV (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER -#define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER (0) -#endif - -#ifndef MYNEWT_VAL_BLE_VERSION -#define MYNEWT_VAL_BLE_VERSION (50) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_FIND_INFO -#define MYNEWT_VAL_BLE_ATT_SVR_FIND_INFO (1) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_FIND_TYPE -#define MYNEWT_VAL_BLE_ATT_SVR_FIND_TYPE (1) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_INDICATE -#define MYNEWT_VAL_BLE_ATT_SVR_INDICATE (1) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_MAX_PREP_ENTRIES -#define MYNEWT_VAL_BLE_ATT_SVR_MAX_PREP_ENTRIES (64) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY -#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE -#define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE_TMO -#define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE_TMO (30000) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ -#define MYNEWT_VAL_BLE_ATT_SVR_READ (1) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_BLOB -#define MYNEWT_VAL_BLE_ATT_SVR_READ_BLOB (1) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_GROUP_TYPE -#define MYNEWT_VAL_BLE_ATT_SVR_READ_GROUP_TYPE (1) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_MULT -#define MYNEWT_VAL_BLE_ATT_SVR_READ_MULT (1) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_TYPE -#define MYNEWT_VAL_BLE_ATT_SVR_READ_TYPE (1) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_SIGNED_WRITE -#define MYNEWT_VAL_BLE_ATT_SVR_SIGNED_WRITE (1) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_WRITE -#define MYNEWT_VAL_BLE_ATT_SVR_WRITE (1) -#endif - -#ifndef MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP -#define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1) -#endif - -#ifndef MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE -#define MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE (1) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_DISC_ALL_CHRS -#define MYNEWT_VAL_BLE_GATT_DISC_ALL_CHRS (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_DISC_ALL_DSCS -#define MYNEWT_VAL_BLE_GATT_DISC_ALL_DSCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_DISC_ALL_SVCS -#define MYNEWT_VAL_BLE_GATT_DISC_ALL_SVCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_DISC_CHR_UUID -#define MYNEWT_VAL_BLE_GATT_DISC_CHR_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_DISC_SVC_UUID -#define MYNEWT_VAL_BLE_GATT_DISC_SVC_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_FIND_INC_SVCS -#define MYNEWT_VAL_BLE_GATT_FIND_INC_SVCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_INDICATE -#define MYNEWT_VAL_BLE_GATT_INDICATE (1) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_MAX_PROCS -#define MYNEWT_VAL_BLE_GATT_MAX_PROCS (4) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_NOTIFY -#define MYNEWT_VAL_BLE_GATT_NOTIFY (1) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_READ -#define MYNEWT_VAL_BLE_GATT_READ (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_READ_LONG -#define MYNEWT_VAL_BLE_GATT_READ_LONG (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_READ_MAX_ATTRS -#define MYNEWT_VAL_BLE_GATT_READ_MAX_ATTRS (8) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT -#define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_READ_UUID -#define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_RESUME_RATE -#define MYNEWT_VAL_BLE_GATT_RESUME_RATE (1000) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_SIGNED_WRITE -#define MYNEWT_VAL_BLE_GATT_SIGNED_WRITE (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_WRITE -#define MYNEWT_VAL_BLE_GATT_WRITE (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_WRITE_LONG -#define MYNEWT_VAL_BLE_GATT_WRITE_LONG (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_WRITE_MAX_ATTRS -#define MYNEWT_VAL_BLE_GATT_WRITE_MAX_ATTRS (4) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_WRITE_NO_RSP -#define MYNEWT_VAL_BLE_GATT_WRITE_NO_RSP (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_GATT_WRITE_RELIABLE -#define MYNEWT_VAL_BLE_GATT_WRITE_RELIABLE (MYNEWT_VAL_BLE_ROLE_CENTRAL) -#endif - -#ifndef MYNEWT_VAL_BLE_HOST -#define MYNEWT_VAL_BLE_HOST (1) -#endif - -#ifndef MYNEWT_VAL_ESP_BLE_MESH -#ifdef CONFIG_BLE_MESH_HCI_5_0 -#define MYNEWT_VAL_ESP_BLE_MESH (1) -#else -#define MYNEWT_VAL_ESP_BLE_MESH (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_HS_DEBUG -#ifdef CONFIG_BT_NIMBLE_DEBUG -#define MYNEWT_VAL_BLE_HS_DEBUG (1) -#else -#define MYNEWT_VAL_BLE_HS_DEBUG (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS -#ifdef CONFIG_BT_NIMBLE_SM_SC_DEBUG_KEYS -#define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (1) -#else -#define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_HS_AUTO_START -#define MYNEWT_VAL_BLE_HS_AUTO_START (1) -#endif - -#ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL -#ifdef CONFIG_BT_NIMBLE_HS_FLOW_CTRL -#define MYNEWT_VAL_BLE_HS_FLOW_CTRL (1) -#else -#define MYNEWT_VAL_BLE_HS_FLOW_CTRL (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL_ITVL -#define MYNEWT_VAL_BLE_HS_FLOW_CTRL_ITVL CONFIG_BT_NIMBLE_HS_FLOW_CTRL_ITVL -#endif - -#ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL_THRESH -#define MYNEWT_VAL_BLE_HS_FLOW_CTRL_THRESH CONFIG_BT_NIMBLE_HS_FLOW_CTRL_THRESH -#endif - -#ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT -#define MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT CONFIG_BT_NIMBLE_HS_FLOW_CTRL_TX_ON_DISCONNECT -#endif - -#ifndef MYNEWT_VAL_BLE_HS_PHONY_HCI_ACKS -#define MYNEWT_VAL_BLE_HS_PHONY_HCI_ACKS (0) -#endif - -#ifndef MYNEWT_VAL_BLE_HS_REQUIRE_OS -#define MYNEWT_VAL_BLE_HS_REQUIRE_OS (1) -#endif - -#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN -#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN (1) -#endif - -#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT -#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT CONFIG_BT_NIMBLE_HS_STOP_TIMEOUT_MS -#endif - -#ifndef MYNEWT_VAL_BLE_HS_SYSINIT_STAGE -#define MYNEWT_VAL_BLE_HS_SYSINIT_STAGE (200) -#endif - -#ifndef MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM -#define MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM -#endif - -#ifndef MYNEWT_VAL_BLE_L2CAP_COC_MPS -#define MYNEWT_VAL_BLE_L2CAP_COC_MPS (MYNEWT_VAL_MSYS_1_BLOCK_SIZE - 8) -#endif - -#ifndef MYNEWT_VAL_BLE_L2CAP_JOIN_RX_FRAGS -#define MYNEWT_VAL_BLE_L2CAP_JOIN_RX_FRAGS (1) -#endif - -#ifndef MYNEWT_VAL_BLE_L2CAP_MAX_CHANS -#define MYNEWT_VAL_BLE_L2CAP_MAX_CHANS (3*MYNEWT_VAL_BLE_MAX_CONNECTIONS) -#endif - -#ifndef MYNEWT_VAL_BLE_L2CAP_RX_FRAG_TIMEOUT -#define MYNEWT_VAL_BLE_L2CAP_RX_FRAG_TIMEOUT (30000) -#endif - -#ifndef MYNEWT_VAL_BLE_L2CAP_SIG_MAX_PROCS -#define MYNEWT_VAL_BLE_L2CAP_SIG_MAX_PROCS (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH -#ifdef CONFIG_BT_NIMBLE_MESH -#define MYNEWT_VAL_BLE_MESH (1) -#else -#define MYNEWT_VAL_BLE_MESH (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT -#define MYNEWT_VAL_BLE_MONITOR_RTT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("monitor") -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART -#define MYNEWT_VAL_BLE_MONITOR_UART (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE -#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV -#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") -#endif - -#if CONFIG_IDF_TARGET_ESP32 -#define MYNEWT_VAL_BLE_HOST_BASED_PRIVACY (1) -#else -#ifndef MYNEWT_VAL_BLE_HOST_BASED_PRIVACY -#define MYNEWT_VAL_BLE_HOST_BASED_PRIVACY (CONFIG_BT_NIMBLE_HOST_BASED_PRIVACY) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT -#define MYNEWT_VAL_BLE_RPA_TIMEOUT (CONFIG_BT_NIMBLE_RPA_TIMEOUT) -#endif - -#ifndef MYNEWT_VAL_BLE_SM_BONDING -#define MYNEWT_VAL_BLE_SM_BONDING (1) -#endif - -#ifndef MYNEWT_VAL_BLE_SM_IO_CAP -#define MYNEWT_VAL_BLE_SM_IO_CAP (BLE_HS_IO_NO_INPUT_OUTPUT) -#endif - -#ifndef MYNEWT_VAL_BLE_SM_KEYPRESS -#define MYNEWT_VAL_BLE_SM_KEYPRESS (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SM_LEGACY -#ifdef CONFIG_BT_NIMBLE_SM_LEGACY -#define MYNEWT_VAL_BLE_SM_LEGACY (1) -#else -#define MYNEWT_VAL_BLE_SM_LEGACY (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS -#define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) -#endif - -#ifndef MYNEWT_VAL_BLE_SM_MITM -#define MYNEWT_VAL_BLE_SM_MITM (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SM_OOB_DATA_FLAG -#define MYNEWT_VAL_BLE_SM_OOB_DATA_FLAG (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SM_OUR_KEY_DIST -#define MYNEWT_VAL_BLE_SM_OUR_KEY_DIST (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SM_SC -#ifdef CONFIG_BT_NIMBLE_SM_SC -#define MYNEWT_VAL_BLE_SM_SC (1) -#else -#define MYNEWT_VAL_BLE_SM_SC (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST -#define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) -#endif - -#ifndef MYNEWT_VAL_BLE_CRYPTO_STACK_MBEDTLS -#define MYNEWT_VAL_BLE_CRYPTO_STACK_MBEDTLS (CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS) -#endif - -#ifndef MYNEWT_VAL_BLE_STORE_MAX_BONDS -#define MYNEWT_VAL_BLE_STORE_MAX_BONDS CONFIG_BT_NIMBLE_MAX_BONDS -#endif - -#ifndef MYNEWT_VAL_BLE_STORE_MAX_CCCDS -#define MYNEWT_VAL_BLE_STORE_MAX_CCCDS CONFIG_BT_NIMBLE_MAX_CCCDS -#endif - -/*** @apache-mynewt-nimble/nimble/host/mesh */ -#ifndef MYNEWT_VAL_BLE_MESH_ACCESS_LOG_LVL -#define MYNEWT_VAL_BLE_MESH_ACCESS_LOG_LVL (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_ACCESS_LOG_MOD -#define MYNEWT_VAL_BLE_MESH_ACCESS_LOG_MOD (10) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT -#define MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT (20) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_ADV_LOG_LVL -#define MYNEWT_VAL_BLE_MESH_ADV_LOG_LVL (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_ADV_LOG_MOD -#define MYNEWT_VAL_BLE_MESH_ADV_LOG_MOD (11) -#endif - -#ifndef MYNEWT_VAL_BLE_STORE_CONFIG_PERSIST -#ifdef CONFIG_BT_NIMBLE_NVS_PERSIST -#define MYNEWT_VAL_BLE_STORE_CONFIG_PERSIST (CONFIG_BT_NIMBLE_NVS_PERSIST) -#else -#define MYNEWT_VAL_BLE_STORE_CONFIG_PERSIST (0) -#endif -#endif - -/*** nimble/host/services/ans */ -#ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT -#define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0) -#endif - - -#ifndef MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT -#define MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT (0) -#endif - -/*** nimble/host/services/bas */ -#ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE -#define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE (1) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_READ_PERM -#define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_READ_PERM (0) -#endif -#ifndef MYNEWT_VAL_BLE_MESH_ADV_TASK_PRIO -#define MYNEWT_VAL_BLE_MESH_ADV_TASK_PRIO (9) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT -#define MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT (4) -#endif - -/*** @apache-mynewt-nimble/nimble/host/mesh */ -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT -#define MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT (20) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT -#define MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_CFG_CLI -#define MYNEWT_VAL_BLE_MESH_CFG_CLI (0) -#endif -#ifndef MYNEWT_VAL_BLE_MESH_CRPL -#define MYNEWT_VAL_BLE_MESH_CRPL (10) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG -#define MYNEWT_VAL_BLE_MESH_DEBUG (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_ACCESS -#define MYNEWT_VAL_BLE_MESH_DEBUG_ACCESS (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_ADV -#define MYNEWT_VAL_BLE_MESH_DEBUG_ADV (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG -#define MYNEWT_VAL_BLE_MESH_DEBUG (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_ACCESS -#define MYNEWT_VAL_BLE_MESH_DEBUG_ACCESS (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_ADV -#define MYNEWT_VAL_BLE_MESH_DEBUG_ADV (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_BEACON -#define MYNEWT_VAL_BLE_MESH_DEBUG_BEACON (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_CRYPTO -#define MYNEWT_VAL_BLE_MESH_DEBUG_CRYPTO (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_FRIEND -#define MYNEWT_VAL_BLE_MESH_DEBUG_FRIEND (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_LOW_POWER -#define MYNEWT_VAL_BLE_MESH_DEBUG_LOW_POWER (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_MODEL -#define MYNEWT_VAL_BLE_MESH_DEBUG_MODEL (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_NET -#define MYNEWT_VAL_BLE_MESH_DEBUG_NET (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_PROV -#define MYNEWT_VAL_BLE_MESH_DEBUG_PROV (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_PROXY -#define MYNEWT_VAL_BLE_MESH_DEBUG_PROXY (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_SETTINGS -#define MYNEWT_VAL_BLE_MESH_DEBUG_SETTINGS (1) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_TRANS -#define MYNEWT_VAL_BLE_MESH_DEBUG_TRANS (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_DEVICE_NAME -#define MYNEWT_VAL_BLE_MESH_DEVICE_NAME CONFIG_BT_NIMBLE_MESH_DEVICE_NAME -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_DEV_UUID -#define MYNEWT_VAL_BLE_MESH_DEV_UUID (((uint8_t[16]){0x11, 0x22, 0})) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_FRIEND -#ifdef CONFIG_BT_NIMBLE_MESH_FRIEND -#define MYNEWT_VAL_BLE_MESH_FRIEND (1) -#else -#define MYNEWT_VAL_BLE_MESH_FRIEND (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_LOG_LVL -#define MYNEWT_VAL_BLE_MESH_FRIEND_LOG_LVL (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_LOG_MOD -#define MYNEWT_VAL_BLE_MESH_FRIEND_LOG_MOD (14) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_LPN_COUNT -#define MYNEWT_VAL_BLE_MESH_FRIEND_LPN_COUNT (2) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_QUEUE_SIZE -#define MYNEWT_VAL_BLE_MESH_FRIEND_QUEUE_SIZE (16) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_RECV_WIN -#define MYNEWT_VAL_BLE_MESH_FRIEND_RECV_WIN (255) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_SEG_RX -#define MYNEWT_VAL_BLE_MESH_FRIEND_SEG_RX (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_SUB_LIST_SIZE -#define MYNEWT_VAL_BLE_MESH_FRIEND_SUB_LIST_SIZE (3) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_GATT_PROXY -#ifdef CONFIG_BT_NIMBLE_MESH_GATT_PROXY -#define MYNEWT_VAL_BLE_MESH_GATT_PROXY (1) -#else -#define MYNEWT_VAL_BLE_MESH_GATT_PROXY (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_HEALTH_CLI -#define MYNEWT_VAL_BLE_MESH_HEALTH_CLI (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_IVU_DIVIDER -#define MYNEWT_VAL_BLE_MESH_IVU_DIVIDER (4) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_IV_UPDATE_TEST -#define MYNEWT_VAL_BLE_MESH_IV_UPDATE_TEST (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LABEL_COUNT -#define MYNEWT_VAL_BLE_MESH_LABEL_COUNT (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LOG_LVL -#define MYNEWT_VAL_BLE_MESH_LOG_LVL (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LOG_MOD -#define MYNEWT_VAL_BLE_MESH_LOG_MOD (9) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LOW_POWER -#ifdef CONFIG_BT_NIMBLE_MESH_LOW_POWER -#define MYNEWT_VAL_BLE_MESH_LOW_POWER (1) -#else -#define MYNEWT_VAL_BLE_MESH_LOW_POWER (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LOW_POWER_LOG_LVL -#define MYNEWT_VAL_BLE_MESH_LOW_POWER_LOG_LVL (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LOW_POWER_LOG_MOD -#define MYNEWT_VAL_BLE_MESH_LOW_POWER_LOG_MOD (15) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LPN_AUTO -#define MYNEWT_VAL_BLE_MESH_LPN_AUTO (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LPN_AUTO_TIMEOUT -#define MYNEWT_VAL_BLE_MESH_LPN_AUTO_TIMEOUT (15) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LPN_ESTABLISHMENT -#define MYNEWT_VAL_BLE_MESH_LPN_ESTABLISHMENT (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LPN_GROUPS -#define MYNEWT_VAL_BLE_MESH_LPN_GROUPS (10) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR -#define MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LPN_INIT_POLL_TIMEOUT -#define MYNEWT_VAL_BLE_MESH_LPN_INIT_POLL_TIMEOUT (MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LPN_MIN_QUEUE_SIZE -#define MYNEWT_VAL_BLE_MESH_LPN_MIN_QUEUE_SIZE (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT -#define MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT (300) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LPN_RECV_DELAY -#define MYNEWT_VAL_BLE_MESH_LPN_RECV_DELAY (100) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LPN_RECV_WIN_FACTOR -#define MYNEWT_VAL_BLE_MESH_LPN_RECV_WIN_FACTOR (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LPN_RETRY_TIMEOUT -#define MYNEWT_VAL_BLE_MESH_LPN_RETRY_TIMEOUT (8) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LPN_RSSI_FACTOR -#define MYNEWT_VAL_BLE_MESH_LPN_RSSI_FACTOR (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LPN_SCAN_LATENCY -#define MYNEWT_VAL_BLE_MESH_LPN_SCAN_LATENCY (10) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_MODEL_EXTENSIONS -#define MYNEWT_VAL_BLE_MESH_MODEL_EXTENSIONS (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_MODEL_GROUP_COUNT -#define MYNEWT_VAL_BLE_MESH_MODEL_GROUP_COUNT (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_MODEL_KEY_COUNT -#define MYNEWT_VAL_BLE_MESH_MODEL_KEY_COUNT (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_MODEL_LOG_LVL -#define MYNEWT_VAL_BLE_MESH_MODEL_LOG_LVL (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_MODEL_LOG_MOD -#define MYNEWT_VAL_BLE_MESH_MODEL_LOG_MOD (16) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE -#define MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE (10) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_NET_LOG_LVL -#define MYNEWT_VAL_BLE_MESH_NET_LOG_LVL (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_NET_LOG_MOD -#define MYNEWT_VAL_BLE_MESH_NET_LOG_MOD (17) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_NODE_COUNT -#define MYNEWT_VAL_BLE_MESH_NODE_COUNT CONFIG_BT_NIMBLE_MESH_NODE_COUNT -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_NODE_ID_TIMEOUT -#define MYNEWT_VAL_BLE_MESH_NODE_ID_TIMEOUT (60) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_OOB_INPUT_ACTIONS -#define MYNEWT_VAL_BLE_MESH_OOB_INPUT_ACTIONS (((BT_MESH_NO_INPUT))) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_OOB_INPUT_SIZE -#define MYNEWT_VAL_BLE_MESH_OOB_INPUT_SIZE (4) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_OOB_OUTPUT_ACTIONS -#define MYNEWT_VAL_BLE_MESH_OOB_OUTPUT_ACTIONS (((BT_MESH_DISPLAY_NUMBER))) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_OOB_OUTPUT_SIZE -#define MYNEWT_VAL_BLE_MESH_OOB_OUTPUT_SIZE (4) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_PB_ADV -#ifdef CONFIG_BT_NIMBLE_MESH_PB_ADV -#define MYNEWT_VAL_BLE_MESH_PB_ADV (1) -#else -#define MYNEWT_VAL_BLE_MESH_PB_ADV (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_PB_GATT -#ifdef CONFIG_BT_NIMBLE_MESH_PB_GATT -#define MYNEWT_VAL_BLE_MESH_PB_GATT (1) -#else -#define MYNEWT_VAL_BLE_MESH_PB_GATT (0) -#endif -#endif - -/* Overridden by @apache-mynewt-nimble/nimble/host/mesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_PROV -#ifdef CONFIG_BT_NIMBLE_MESH_PROV -#define MYNEWT_VAL_BLE_MESH_PROV (1) -#else -#define MYNEWT_VAL_BLE_MESH_PROV (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_PROVISIONER -#ifdef CONFIG_BT_NIMBLE_MESH_PROVISIONER -#define MYNEWT_VAL_BLE_MESH_PROVISIONER (1) -#else -#define MYNEWT_VAL_BLE_MESH_PROVISIONER (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_CDB -#define MYNEWT_VAL_BLE_MESH_CDB (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_PROV_LOG_LVL -#define MYNEWT_VAL_BLE_MESH_PROV_LOG_LVL (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_PROV_LOG_MOD -#define MYNEWT_VAL_BLE_MESH_PROV_LOG_MOD (18) -#endif - -/* Overridden by @apache-mynewt-nimble/nimble/host/mesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_PROXY -#ifdef CONFIG_BT_NIMBLE_MESH_PROXY -#define MYNEWT_VAL_BLE_MESH_PROXY (1) -#else -#define MYNEWT_VAL_BLE_MESH_PROXY (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE -#define MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_PROXY_LOG_LVL -#define MYNEWT_VAL_BLE_MESH_PROXY_LOG_LVL (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_PROXY_LOG_MOD -#define MYNEWT_VAL_BLE_MESH_PROXY_LOG_MOD (19) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RELAY -#ifdef CONFIG_BT_NIMBLE_MESH_RELAY -#define MYNEWT_VAL_BLE_MESH_RELAY (1) -#else -#define MYNEWT_VAL_BLE_MESH_RELAY (0) -#endif -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT -#define MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT (5) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RX_SDU_MAX -#define MYNEWT_VAL_BLE_MESH_RX_SDU_MAX (72) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_SEG_BUFS -#define MYNEWT_VAL_BLE_MESH_SEG_BUFS (72) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MAX -#define MYNEWT_VAL_BLE_MESH_RX_SEG_MAX (3) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT -#define MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT (2) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_SEG_RETRANSMIT_ATTEMPTS -#define MYNEWT_VAL_BLE_MESH_SEG_RETRANSMIT_ATTEMPTS (4) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_SEQ_STORE_RATE -#define MYNEWT_VAL_BLE_MESH_SEQ_STORE_RATE (128) -#endif - - -#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_COUNT -#define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_COUNT (4) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST -#define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST (400) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP -#define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP (50) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS -#define MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS (3) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_DEFAULT_TTL -#define MYNEWT_VAL_BLE_MESH_DEFAULT_TTL (7) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT -#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT (2) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL -#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL (20) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT -#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT (2) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT -#define MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT (500) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RELAY_ENABLED -#define MYNEWT_VAL_BLE_MESH_RELAY_ENABLED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED -#define MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED -#define MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_BEACON_ENABLED -#define MYNEWT_VAL_BLE_MESH_BEACON_ENABLED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL -#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL (20) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_SETTINGS -#define MYNEWT_VAL_BLE_MESH_SETTINGS (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_SETTINGS_LOG_LVL -#define MYNEWT_VAL_BLE_MESH_SETTINGS_LOG_LVL (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_SETTINGS_LOG_MOD -#define MYNEWT_VAL_BLE_MESH_SETTINGS_LOG_MOD (20) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_SHELL -#define MYNEWT_VAL_BLE_MESH_SHELL (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_SHELL_MODELS -#define MYNEWT_VAL_BLE_MESH_SHELL_MODELS (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_STORE_TIMEOUT -#define MYNEWT_VAL_BLE_MESH_STORE_TIMEOUT (2) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_SUBNET_COUNT -#define MYNEWT_VAL_BLE_MESH_SUBNET_COUNT (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_SYSINIT_STAGE -#define MYNEWT_VAL_BLE_MESH_SYSINIT_STAGE (500) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_SYSINIT_STAGE_SHELL -#define MYNEWT_VAL_BLE_MESH_SYSINIT_STAGE_SHELL (1000) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_TESTING -#define MYNEWT_VAL_BLE_MESH_TESTING (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_TRANS_LOG_LVL -#define MYNEWT_VAL_BLE_MESH_TRANS_LOG_LVL (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_TRANS_LOG_MOD -#define MYNEWT_VAL_BLE_MESH_TRANS_LOG_MOD (21) -#endif - -/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_MAX -#define MYNEWT_VAL_BLE_MESH_TX_SEG_MAX (6) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT -#define MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT (4) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT -#define MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT (5) -#endif - -/*** @apache-mynewt-nimble/nimble/host/services/ans */ -#ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT -#define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_ANS_SYSINIT_STAGE -#define MYNEWT_VAL_BLE_SVC_ANS_SYSINIT_STAGE (303) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT -#define MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT (0) -#endif - -/*** @apache-mynewt-nimble/nimble/host/services/bas */ -#ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE -#define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE (1) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_READ_PERM -#define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_READ_PERM (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_BAS_SYSINIT_STAGE -#define MYNEWT_VAL_BLE_SVC_BAS_SYSINIT_STAGE (303) -#endif - -/*** @apache-mynewt-nimble/nimble/host/services/dis */ -#ifndef MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM -#define MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM (-1) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_DEFAULT (NULL) -#endif - -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ -#ifndef MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM -#define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM (-1) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_DEFAULT (NULL) -#endif - -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ -#ifndef MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM -#define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM (-1) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_DEFAULT (NULL) -#endif - -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ -#ifndef MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM -#define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM (-1) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT ("NimBLE") -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM -#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_DEFAULT (NULL) -#endif - -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ -#ifndef MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM -#define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM (-1) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_DEFAULT (NULL) -#endif - -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ -#ifndef MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM -#define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM (-1) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSINIT_STAGE -#define MYNEWT_VAL_BLE_SVC_DIS_SYSINIT_STAGE (303) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT (NULL) -#endif - -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ -#ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM -#define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM (-1) -#endif - -/*** @apache-mynewt-nimble/nimble/host/services/gap */ -#ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE -#define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE_WRITE_PERM -#define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE_WRITE_PERM (-1) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION -#define MYNEWT_VAL_BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION (-1) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME -#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH -#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_WRITE_PERM -#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_WRITE_PERM (-1) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL -#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL -#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_GAP_PPCP_SLAVE_LATENCY -#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_SLAVE_LATENCY (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SVC_GAP_PPCP_SUPERVISION_TMO -#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_SUPERVISION_TMO (0) -#endif - -/*** nimble/transport */ -#ifndef MYNEWT_VAL_BLE_HCI_TRANSPORT_EMSPI -#define MYNEWT_VAL_BLE_HCI_TRANSPORT_EMSPI (0) -#endif - -/* Overridden by targets/porting-nimble (defined by nimble/transport) */ -#ifndef MYNEWT_VAL_BLE_HCI_TRANSPORT_NIMBLE_BUILTIN -#define MYNEWT_VAL_BLE_HCI_TRANSPORT_NIMBLE_BUILTIN (0) -#endif - -#ifndef MYNEWT_VAL_BLE_HCI_TRANSPORT_RAM -#define MYNEWT_VAL_BLE_HCI_TRANSPORT_RAM (0) -#endif - -#ifndef MYNEWT_VAL_BLE_HCI_TRANSPORT_SOCKET -#define MYNEWT_VAL_BLE_HCI_TRANSPORT_SOCKET (0) -#endif - -/* Overridden by targets/porting-nimble (defined by nimble/transport) */ -#ifndef MYNEWT_VAL_BLE_HCI_TRANSPORT_UART -#define MYNEWT_VAL_BLE_HCI_TRANSPORT_UART (1) -#endif - -/*** nimble/transport/uart */ -#ifndef MYNEWT_VAL_BLE_ACL_BUF_COUNT -#define MYNEWT_VAL_BLE_ACL_BUF_COUNT CONFIG_BT_NIMBLE_ACL_BUF_COUNT -#endif - -#ifndef MYNEWT_VAL_BLE_ACL_BUF_SIZE -#define MYNEWT_VAL_BLE_ACL_BUF_SIZE CONFIG_BT_NIMBLE_ACL_BUF_SIZE -#endif - -#ifndef MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT -#define MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT (12) -#endif - -#ifndef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE -#define MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE -#endif - -#ifndef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT -#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT CONFIG_BT_NIMBLE_HCI_EVT_HI_BUF_COUNT -#endif - -#ifndef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT -#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT CONFIG_BT_NIMBLE_HCI_EVT_LO_BUF_COUNT -#endif - -/* Overridden by targets/porting-nimble (defined by nimble/transport/uart) */ -#ifndef MYNEWT_VAL_BLE_HCI_UART_BAUD -#define MYNEWT_VAL_BLE_HCI_UART_BAUD (115200) -#endif - -#ifndef MYNEWT_VAL_BLE_HCI_UART_DATA_BITS -#define MYNEWT_VAL_BLE_HCI_UART_DATA_BITS (8) -#endif - -/* Overridden by targets/porting-nimble (defined by nimble/transport/uart) */ -#ifndef MYNEWT_VAL_BLE_HCI_UART_FLOW_CTRL -#define MYNEWT_VAL_BLE_HCI_UART_FLOW_CTRL (0) -#endif - -#ifndef MYNEWT_VAL_BLE_HCI_UART_PARITY -#define MYNEWT_VAL_BLE_HCI_UART_PARITY (HAL_UART_PARITY_NONE) -#endif - -#ifndef MYNEWT_VAL_BLE_HCI_UART_PORT -#define MYNEWT_VAL_BLE_HCI_UART_PORT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_HCI_UART_STOP_BITS -#define MYNEWT_VAL_BLE_HCI_UART_STOP_BITS (1) -#endif - -#ifndef CONFIG_BLE_TX_CCA_ENABLED -#define MYNEWT_VAL_BLE_TX_CCA_ENABLED (0) -#else -#define MYNEWT_VAL_BLE_TX_CCA_ENABLED (CONFIG_BLE_TX_CCA_ENABLED) -#endif - -#ifndef CONFIG_BLE_CCA_RSSI_THRESH -#define MYNEWT_VAL_BLE_CCA_RSSI_THRESH (50) -#else -#define MYNEWT_VAL_BLE_CCA_RSSI_THRESH (CONFIG_BLE_CCA_RSSI_THRESH) -#endif - -#ifndef MYNEWT_VAL_NEWT_FEATURE_LOGCFG -#define MYNEWT_VAL_NEWT_FEATURE_LOGCFG (1) -#endif - -#ifndef MYNEWT_VAL_BLE_USE_ESP_TIMER -#ifdef CONFIG_BT_NIMBLE_USE_ESP_TIMER -#define MYNEWT_VAL_BLE_USE_ESP_TIMER (1) -#else -#define MYNEWT_VAL_BLE_USE_ESP_TIMER (0) -#endif -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/port/include/esp_nimble_mem.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/port/include/esp_nimble_mem.h deleted file mode 100644 index 9a89c12b2..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/port/include/esp_nimble_mem.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __ESP_NIMBLE_MEM_H__ -#define __ESP_NIMBLE_MEM_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void *nimble_platform_mem_malloc(size_t size); -void *nimble_platform_mem_calloc(size_t n, size_t size); -void nimble_platform_mem_free(void *ptr); - -#ifdef __cplusplus -} -#endif - -#endif /* __ESP_NIMBLE_MEM_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/port/src/esp_nimble_mem.cpp b/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/port/src/esp_nimble_mem.cpp deleted file mode 100644 index 407091c7f..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/esp_port/port/src/esp_nimble_mem.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifdef ESP_PLATFORM - -#include "esp_attr.h" -#include "esp_heap_caps.h" -#include "nimconfig.h" -#include "../include/esp_nimble_mem.h" - -//Tasmota Patch -extern void *special_malloc(uint32_t size); -extern void *special_calloc(size_t num, size_t size); - - -extern "C" { -IRAM_ATTR void *nimble_platform_mem_malloc(size_t size) -{ - return special_malloc((uint32_t)size); -// #ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL -// return heap_caps_malloc(size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); -// #elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL -// return heap_caps_malloc(size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT); -// #elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT -// return heap_caps_malloc_prefer(size, 2, MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); -// #else -// return malloc(size); -// #endif -} - -IRAM_ATTR void *nimble_platform_mem_calloc(size_t n, size_t size) -{ - return special_calloc(n,size); -// #ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL -// return heap_caps_calloc(n, size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); -// #elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL -// return heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT); -// #elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT -// return heap_caps_calloc_prefer(n, size, 2, MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); -// #else -// return calloc(n, size); -// #endif -} - -IRAM_ATTR void nimble_platform_mem_free(void *ptr) -{ - heap_caps_free(ptr); -} -} //extern "C" -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/AUTHORS b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/AUTHORS deleted file mode 100644 index 0a8e9f806..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/AUTHORS +++ /dev/null @@ -1,15 +0,0 @@ -Architect: -Rafael Misoczki - -Open Source Maintainer: -Constanza Heath -Rafael Misoczki - -Contributors: -Constanza Heath -Rafael Misoczki -Flavio Santes -Jarkko Sakkinen -Chris Morrison -Marti Bolivar -Colin Ian King diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/LICENSE b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/LICENSE deleted file mode 100644 index 2e1db516a..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/LICENSE +++ /dev/null @@ -1,61 +0,0 @@ - -================================================================================ - - TinyCrypt Cryptographic Library - -================================================================================ - - Copyright (c) 2017, Intel Corporation. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - - Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - - Neither the name of the Intel Corporation nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -================================================================================ -Copyright (c) 2014, Kenneth MacKay -All rights reserved. - -https://github.com/kmackay/micro-ecc - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -================================================================================ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/README b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/README deleted file mode 100644 index fb52c196a..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/README +++ /dev/null @@ -1,71 +0,0 @@ - -================================================================================ - - TinyCrypt Cryptographic Library - -================================================================================ - - Copyright (c) 2017, Intel Corporation. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - - Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - - Neither the name of the Intel Corporation nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -================================================================================ - -Overview: - -The TinyCrypt Library provides an implementation for constrained devices of a -minimal set of standard cryptography primitives. - -Please, ***SEE THE DOCUMENTATION*** folder for more information on the supported -cryptographic primitives and the limitations of TinyCrypt library. For usage, -security and technicalities, please see the corresponding header file of each -cryptographic primitive. - -================================================================================ - -Organization: - -/lib: C source code of the cryptographic primitives. -/lib/include/tinycrypt: C header files of the cryptographic primitives. -/tests: Test vectors of the cryptographic primitives. -/doc: Documentation of TinyCrypt. - -================================================================================ - -Building: - -1) In Makefile.conf set: - - CFLAGS for compiler flags. - - CC for compiler. - - ENABLE_TESTS for enabling (true) or disabling (false) tests compilation. -2) In lib/Makefile select the primitives required by your project. -3) In tests/Makefile select the corresponding tests of the selected primitives. -4) make -5) run tests in tests/ - -================================================================================ - diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/VERSION b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/VERSION deleted file mode 100644 index a45be4627..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.2.8 diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/documentation/tinycrypt.rst b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/documentation/tinycrypt.rst deleted file mode 100644 index 356c099a0..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/documentation/tinycrypt.rst +++ /dev/null @@ -1,352 +0,0 @@ - -TinyCrypt Cryptographic Library -############################### -Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - -Overview -******** -The TinyCrypt Library provides an implementation for targeting constrained devices -with a minimal set of standard cryptography primitives, as listed below. To better -serve applications targeting constrained devices, TinyCrypt implementations differ -from the standard specifications (see the Important Remarks section for some -important differences). Certain cryptographic primitives depend on other -primitives, as mentioned in the list below. - -Aside from the Important Remarks section below, valuable information on the usage, -security and technicalities of each cryptographic primitive are found in the -corresponding header file. - -* SHA-256: - - * Type of primitive: Hash function. - * Standard Specification: NIST FIPS PUB 180-4. - * Requires: -- - -* HMAC-SHA256: - - * Type of primitive: Message authentication code. - * Standard Specification: RFC 2104. - * Requires: SHA-256 - -* HMAC-PRNG: - - * Type of primitive: Pseudo-random number generator (256-bit strength). - * Standard Specification: NIST SP 800-90A. - * Requires: SHA-256 and HMAC-SHA256. - -* AES-128: - - * Type of primitive: Block cipher. - * Standard Specification: NIST FIPS PUB 197. - * Requires: -- - -* AES-CBC mode: - - * Type of primitive: Encryption mode of operation. - * Standard Specification: NIST SP 800-38A. - * Requires: AES-128. - -* AES-CTR mode: - - * Type of primitive: Encryption mode of operation. - * Standard Specification: NIST SP 800-38A. - * Requires: AES-128. - -* AES-CMAC mode: - - * Type of primitive: Message authentication code. - * Standard Specification: NIST SP 800-38B. - * Requires: AES-128. - -* AES-CCM mode: - - * Type of primitive: Authenticated encryption. - * Standard Specification: NIST SP 800-38C. - * Requires: AES-128. - -* CTR-PRNG: - - * Type of primitive: Pseudo-random number generator (128-bit strength). - * Standard Specification: NIST SP 800-90A. - * Requires: AES-128. - -* ECC-DH: - - * Type of primitive: Key exchange based on curve NIST p-256. - * Standard Specification: RFC 6090. - * Requires: ECC auxiliary functions (ecc.h/c). - -* ECC-DSA: - - * Type of primitive: Digital signature based on curve NIST p-256. - * Standard Specification: RFC 6090. - * Requires: ECC auxiliary functions (ecc.h/c). - -Design Goals -************ - -* Minimize the code size of each cryptographic primitive. This means minimize - the size of a platform-independent implementation, as presented in TinyCrypt. - Note that various applications may require further features, optimizations with - respect to other metrics and countermeasures for particular threats. These - peculiarities would increase the code size and thus are not considered here. - -* Minimize the dependencies among the cryptographic primitives. This means - that it is unnecessary to build and allocate object code for more primitives - than the ones strictly required by the intended application. In other words, - one can select and compile only the primitives required by the application. - - -Important Remarks -***************** - -The cryptographic implementations in TinyCrypt library have some limitations. -Some of these limitations are inherent to the cryptographic primitives -themselves, while others are specific to TinyCrypt. These limitations were accepted -in order to meet its design goals (in special, minimal code size) and to better -serve applications targeting constrained devices in general. Some of these -limitations are discussed in-depth below. - -General Remarks -*************** - -* TinyCrypt does **not** intend to be fully side-channel resistant. Due to the - variety of side-channel attacks, many of them only relevant to certain - platforms. In this sense, instead of penalizing all library users with - side-channel countermeasures such as increasing the overall code size, - TinyCrypt only implements certain generic timing-attack countermeasures. - -Specific Remarks -**************** - -* SHA-256: - - * The number of bits_hashed in the state is not checked for overflow. Note - however that this will only be a problem if you intend to hash more than - 2^64 bits, which is an extremely large window. - -* HMAC: - - * The HMAC verification process is assumed to be performed by the application. - This compares the computed tag with some given tag. - Note that conventional memory-comparison methods (such as memcmp function) - might be vulnerable to timing attacks; thus be sure to use a constant-time - memory comparison function (such as compare_constant_time - function provided in lib/utils.c). - - * The tc_hmac_final function, responsible for computing the message tag, - cleans the state context before exiting. Thus, applications do not need to - clean the TCHmacState_t ctx after calling tc_hmac_final. This should not - be changed in future versions of the library as there are applications - currently relying on this good-practice/feature of TinyCrypt. - -* HMAC-PRNG: - - * Before using HMAC-PRNG, you *must* find an entropy source to produce a seed. - PRNGs only stretch the seed into a seemingly random output of arbitrary - length. The security of the output is exactly equal to the - unpredictability of the seed. - - * NIST SP 800-90A requires three items as seed material in the initialization - step: entropy seed, personalization and a nonce (which is not implemented). - TinyCrypt requires the personalization byte array and automatically creates - the entropy seed using a mandatory call to the re-seed function. - -* AES-128: - - * The current implementation does not support other key-lengths (such as 256 - bits). Note that if you need AES-256, it doesn't sound as though your - application is running in a constrained environment. AES-256 requires keys - twice the size as for AES-128, and the key schedule is 40% larger. - -* CTR mode: - - * The AES-CTR mode limits the size of a data message they encrypt to 2^32 - blocks. If you need to encrypt larger data sets, your application would - need to replace the key after 2^32 block encryptions. - -* CTR-PRNG: - - * Before using CTR-PRNG, you *must* find an entropy source to produce a seed. - PRNGs only stretch the seed into a seemingly random output of arbitrary - length. The security of the output is exactly equal to the - unpredictability of the seed. - -* CBC mode: - - * TinyCrypt CBC decryption assumes that the iv and the ciphertext are - contiguous (as produced by TinyCrypt CBC encryption). This allows for a - very efficient decryption algorithm that would not otherwise be possible. - -* CMAC mode: - - * AES128-CMAC mode of operation offers 64 bits of security against collision - attacks. Note however that an external attacker cannot generate the tags - him/herself without knowing the MAC key. In this sense, to attack the - collision property of AES128-CMAC, an external attacker would need the - cooperation of the legal user to produce an exponentially high number of - tags (e.g. 2^64) to finally be able to look for collisions and benefit - from them. As an extra precaution, the current implementation allows to at - most 2^48 calls to tc_cmac_update function before re-calling tc_cmac_setup - (allowing a new key to be set), as suggested in Appendix B of SP 800-38B. - -* CCM mode: - - * There are a few tradeoffs for the selection of the parameters of CCM mode. - In special, there is a tradeoff between the maximum number of invocations - of CCM under a given key and the maximum payload length for those - invocations. Both things are related to the parameter 'q' of CCM mode. The - maximum number of invocations of CCM under a given key is determined by - the nonce size, which is: 15-q bytes. The maximum payload length for those - invocations is defined as 2^(8q) bytes. - - To achieve minimal code size, TinyCrypt CCM implementation fixes q = 2, - which is a quite reasonable choice for constrained applications. The - implications of this choice are: - - The nonce size is: 13 bytes. - - The maximum payload length is: 2^16 bytes = 65 KB. - - The mac size parameter is an important parameter to estimate the security - against collision attacks (that aim at finding different messages that - produce the same authentication tag). TinyCrypt CCM implementation - accepts any even integer between 4 and 16, as suggested in SP 800-38C. - - * TinyCrypt CCM implementation accepts associated data of any length between - 0 and (2^16 - 2^8) = 65280 bytes. - - * TinyCrypt CCM implementation accepts: - - * Both non-empty payload and associated data (it encrypts and - authenticates the payload and only authenticates the associated data); - - * Non-empty payload and empty associated data (it encrypts and - authenticates the payload); - - * Non-empty associated data and empty payload (it degenerates to an - authentication-only mode on the associated data). - - * RFC-3610, which also specifies CCM, presents a few relevant security - suggestions, such as: it is recommended for most applications to use a - mac size greater than 8. Besides, it is emphasized that the usage of the - same nonce for two different messages which are encrypted with the same - key obviously destroys the security properties of CCM mode. - -* ECC-DH and ECC-DSA: - - * TinyCrypt ECC implementation is based on micro-ecc (see - https://github.com/kmackay/micro-ecc). In the original micro-ecc - documentation, there is an important remark about the way integers are - represented: - - "Integer representation: To reduce code size, all large integers are - represented using little-endian words - so the least significant word is - first. You can use the 'ecc_bytes2native()' and 'ecc_native2bytes()' - functions to convert between the native integer representation and the - standardized octet representation." - - Note that the assumed bit layout is: {31, 30, ..., 0}, {63, 62, ..., 32}, - {95, 94, ..., 64}, {127, 126, ..., 96} for a very-long-integer (vli) - consisting of 4 unsigned integers (as an example). - - * A cryptographically-secure PRNG function must be set (using uECC_set_rng()) - before calling uECC_make_key() or uECC_sign(). - -Examples of Applications -************************ -It is possible to do useful cryptography with only the given small set of -primitives. With this list of primitives it becomes feasible to support a range -of cryptography usages: - - * Measurement of code, data structures, and other digital artifacts (SHA256); - - * Generate commitments (SHA256); - - * Construct keys (HMAC-SHA256); - - * Extract entropy from strings containing some randomness (HMAC-SHA256); - - * Construct random mappings (HMAC-SHA256); - - * Construct nonces and challenges (HMAC-PRNG, CTR-PRNG); - - * Authenticate using a shared secret (HMAC-SHA256); - - * Create an authenticated, replay-protected session (HMAC-SHA256 + HMAC-PRNG); - - * Authenticated encryption (AES-128 + AES-CCM); - - * Key-exchange (EC-DH); - - * Digital signature (EC-DSA); - -Test Vectors -************ - -The library provides a test program for each cryptographic primitive (see 'test' -folder). Besides illustrating how to use the primitives, these tests evaluate -the correctness of the implementations by checking the results against -well-known publicly validated test vectors. - -For the case of the HMAC-PRNG, due to the necessity of performing an extensive -battery test to produce meaningful conclusions, we suggest the user to evaluate -the unpredictability of the implementation by using the NIST Statistical Test -Suite (see References). - -For the case of the EC-DH and EC-DSA implementations, most of the test vectors -were obtained from the site of the NIST Cryptographic Algorithm Validation -Program (CAVP), see References. - -References -********** - -* `NIST FIPS PUB 180-4 (SHA-256)`_ - -.. _NIST FIPS PUB 180-4 (SHA-256): - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf - -* `NIST FIPS PUB 197 (AES-128)`_ - -.. _NIST FIPS PUB 197 (AES-128): - http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf - -* `NIST SP800-90A (HMAC-PRNG)`_ - -.. _NIST SP800-90A (HMAC-PRNG): - http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf - -* `NIST SP 800-38A (AES-CBC and AES-CTR)`_ - -.. _NIST SP 800-38A (AES-CBC and AES-CTR): - http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - -* `NIST SP 800-38B (AES-CMAC)`_ - -.. _NIST SP 800-38B (AES-CMAC): - http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf - -* `NIST SP 800-38C (AES-CCM)`_ - -.. _NIST SP 800-38C (AES-CCM): - http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf - -* `NIST Statistical Test Suite (useful for testing HMAC-PRNG)`_ - -.. _NIST Statistical Test Suite (useful for testing HMAC-PRNG): - http://csrc.nist.gov/groups/ST/toolkit/rng/documentation_software.html - -* `NIST Cryptographic Algorithm Validation Program (CAVP) site`_ - -.. _NIST Cryptographic Algorithm Validation Program (CAVP) site: - http://csrc.nist.gov/groups/STM/cavp/ - -* `RFC 2104 (HMAC-SHA256)`_ - -.. _RFC 2104 (HMAC-SHA256): - https://www.ietf.org/rfc/rfc2104.txt - -* `RFC 6090 (ECC-DH and ECC-DSA)`_ - -.. _RFC 6090 (ECC-DH and ECC-DSA): - https://www.ietf.org/rfc/rfc6090.txt diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/aes.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/aes.h deleted file mode 100644 index b612213a0..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/aes.h +++ /dev/null @@ -1,130 +0,0 @@ -/* aes.h - TinyCrypt interface to an AES-128 implementation */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief -- Interface to an AES-128 implementation. - * - * Overview: AES-128 is a NIST approved block cipher specified in - * FIPS 197. Block ciphers are deterministic algorithms that - * perform a transformation specified by a symmetric key in fixed- - * length data sets, also called blocks. - * - * Security: AES-128 provides approximately 128 bits of security. - * - * Usage: 1) call tc_aes128_set_encrypt/decrypt_key to set the key. - * - * 2) call tc_aes_encrypt/decrypt to process the data. - */ - -#ifndef __TC_AES_H__ -#define __TC_AES_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define Nb (4) /* number of columns (32-bit words) comprising the state */ -#define Nk (4) /* number of 32-bit words comprising the key */ -#define Nr (10) /* number of rounds */ -#define TC_AES_BLOCK_SIZE (Nb*Nk) -#define TC_AES_KEY_SIZE (Nb*Nk) - -typedef struct tc_aes_key_sched_struct { - unsigned int words[Nb*(Nr+1)]; -} *TCAesKeySched_t; - -/** - * @brief Set AES-128 encryption key - * Uses key k to initialize s - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL - * @note This implementation skips the additional steps required for keys - * larger than 128 bits, and must not be used for AES-192 or - * AES-256 key schedule -- see FIPS 197 for details - * @param s IN/OUT -- initialized struct tc_aes_key_sched_struct - * @param k IN -- points to the AES key - */ -int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k); - -/** - * @brief AES-128 Encryption procedure - * Encrypts contents of in buffer into out buffer under key; - * schedule s - * @note Assumes s was initialized by aes_set_encrypt_key; - * out and in point to 16 byte buffers - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: out == NULL or in == NULL or s == NULL - * @param out IN/OUT -- buffer to receive ciphertext block - * @param in IN -- a plaintext block to encrypt - * @param s IN -- initialized AES key schedule - */ -int tc_aes_encrypt(uint8_t *out, const uint8_t *in, - const TCAesKeySched_t s); - -/** - * @brief Set the AES-128 decryption key - * Uses key k to initialize s - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL - * @note This is the implementation of the straightforward inverse cipher - * using the cipher documented in FIPS-197 figure 12, not the - * equivalent inverse cipher presented in Figure 15 - * @warning This routine skips the additional steps required for keys larger - * than 128, and must not be used for AES-192 or AES-256 key - * schedule -- see FIPS 197 for details - * @param s IN/OUT -- initialized struct tc_aes_key_sched_struct - * @param k IN -- points to the AES key - */ -int tc_aes128_set_decrypt_key(TCAesKeySched_t s, const uint8_t *k); - -/** - * @brief AES-128 Encryption procedure - * Decrypts in buffer into out buffer under key schedule s - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: out is NULL or in is NULL or s is NULL - * @note Assumes s was initialized by aes_set_encrypt_key - * out and in point to 16 byte buffers - * @param out IN/OUT -- buffer to receive ciphertext block - * @param in IN -- a plaintext block to encrypt - * @param s IN -- initialized AES key schedule - */ -int tc_aes_decrypt(uint8_t *out, const uint8_t *in, - const TCAesKeySched_t s); - -#ifdef __cplusplus -} -#endif - -#endif /* __TC_AES_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/cbc_mode.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/cbc_mode.h deleted file mode 100644 index a53318eed..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/cbc_mode.h +++ /dev/null @@ -1,151 +0,0 @@ -/* cbc_mode.h - TinyCrypt interface to a CBC mode implementation */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief Interface to a CBC mode implementation. - * - * Overview: CBC (for "cipher block chaining") mode is a NIST approved mode of - * operation defined in SP 800-38a. It can be used with any block - * cipher to provide confidentiality of strings whose lengths are - * multiples of the block_size of the underlying block cipher. - * TinyCrypt hard codes AES as the block cipher. - * - * Security: CBC mode provides data confidentiality given that the maximum - * number q of blocks encrypted under a single key satisfies - * q < 2^63, which is not a practical constraint (it is considered a - * good practice to replace the encryption when q == 2^56). CBC mode - * provides NO data integrity. - * - * CBC mode assumes that the IV value input into the - * tc_cbc_mode_encrypt is randomly generated. The TinyCrypt library - * provides HMAC-PRNG module, which generates suitable IVs. Other - * methods for generating IVs are acceptable, provided that the - * values of the IVs generated appear random to any adversary, - * including someone with complete knowledge of the system design. - * - * The randomness property on which CBC mode's security depends is - * the unpredictability of the IV. Since it is unpredictable, this - * means in practice that CBC mode requires that the IV is stored - * somehow with the ciphertext in order to recover the plaintext. - * - * TinyCrypt CBC encryption prepends the IV to the ciphertext, - * because this affords a more efficient (few buffers) decryption. - * Hence tc_cbc_mode_encrypt assumes the ciphertext buffer is always - * 16 bytes larger than the plaintext buffer. - * - * Requires: AES-128 - * - * Usage: 1) call tc_cbc_mode_encrypt to encrypt data. - * - * 2) call tc_cbc_mode_decrypt to decrypt data. - * - */ - -#ifndef __TC_CBC_MODE_H__ -#define __TC_CBC_MODE_H__ - -#include "aes.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief CBC encryption procedure - * CBC encrypts inlen bytes of the in buffer into the out buffer - * using the encryption key schedule provided, prepends iv to out - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * out == NULL or - * in == NULL or - * ctr == NULL or - * sched == NULL or - * inlen == 0 or - * (inlen % TC_AES_BLOCK_SIZE) != 0 or - * (outlen % TC_AES_BLOCK_SIZE) != 0 or - * outlen != inlen + TC_AES_BLOCK_SIZE - * @note Assumes: - sched has been configured by aes_set_encrypt_key - * - iv contains a 16 byte random string - * - out buffer is large enough to hold the ciphertext + iv - * - out buffer is a contiguous buffer - * - in holds the plaintext and is a contiguous buffer - * - inlen gives the number of bytes in the in buffer - * @param out IN/OUT -- buffer to receive the ciphertext - * @param outlen IN -- length of ciphertext buffer in bytes - * @param in IN -- plaintext to encrypt - * @param inlen IN -- length of plaintext buffer in bytes - * @param iv IN -- the IV for the this encrypt/decrypt - * @param sched IN -- AES key schedule for this encrypt - */ -int tc_cbc_mode_encrypt(uint8_t *out, unsigned int outlen, const uint8_t *in, - unsigned int inlen, const uint8_t *iv, - const TCAesKeySched_t sched); - -/** - * @brief CBC decryption procedure - * CBC decrypts inlen bytes of the in buffer into the out buffer - * using the provided encryption key schedule - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * out == NULL or - * in == NULL or - * sched == NULL or - * inlen == 0 or - * outlen == 0 or - * (inlen % TC_AES_BLOCK_SIZE) != 0 or - * (outlen % TC_AES_BLOCK_SIZE) != 0 or - * outlen != inlen + TC_AES_BLOCK_SIZE - * @note Assumes:- in == iv + ciphertext, i.e. the iv and the ciphertext are - * contiguous. This allows for a very efficient decryption - * algorithm that would not otherwise be possible - * - sched was configured by aes_set_decrypt_key - * - out buffer is large enough to hold the decrypted plaintext - * and is a contiguous buffer - * - inlen gives the number of bytes in the in buffer - * @param out IN/OUT -- buffer to receive decrypted data - * @param outlen IN -- length of plaintext buffer in bytes - * @param in IN -- ciphertext to decrypt, including IV - * @param inlen IN -- length of ciphertext buffer in bytes - * @param iv IN -- the IV for the this encrypt/decrypt - * @param sched IN -- AES key schedule for this decrypt - * - */ -int tc_cbc_mode_decrypt(uint8_t *out, unsigned int outlen, const uint8_t *in, - unsigned int inlen, const uint8_t *iv, - const TCAesKeySched_t sched); - -#ifdef __cplusplus -} -#endif - -#endif /* __TC_CBC_MODE_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ccm_mode.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ccm_mode.h deleted file mode 100644 index c22ac08d4..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ccm_mode.h +++ /dev/null @@ -1,211 +0,0 @@ -/* ccm_mode.h - TinyCrypt interface to a CCM mode implementation */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief Interface to a CCM mode implementation. - * - * Overview: CCM (for "Counter with CBC-MAC") mode is a NIST approved mode of - * operation defined in SP 800-38C. - * - * TinyCrypt CCM implementation accepts: - * - * 1) Both non-empty payload and associated data (it encrypts and - * authenticates the payload and also authenticates the associated - * data); - * 2) Non-empty payload and empty associated data (it encrypts and - * authenticates the payload); - * 3) Non-empty associated data and empty payload (it degenerates to - * an authentication mode on the associated data). - * - * TinyCrypt CCM implementation accepts associated data of any length - * between 0 and (2^16 - 2^8) bytes. - * - * Security: The mac length parameter is an important parameter to estimate the - * security against collision attacks (that aim at finding different - * messages that produce the same authentication tag). TinyCrypt CCM - * implementation accepts any even integer between 4 and 16, as - * suggested in SP 800-38C. - * - * RFC-3610, which also specifies CCM, presents a few relevant - * security suggestions, such as: it is recommended for most - * applications to use a mac length greater than 8. Besides, the - * usage of the same nonce for two different messages which are - * encrypted with the same key destroys the security of CCM mode. - * - * Requires: AES-128 - * - * Usage: 1) call tc_ccm_config to configure. - * - * 2) call tc_ccm_mode_encrypt to encrypt data and generate tag. - * - * 3) call tc_ccm_mode_decrypt to decrypt data and verify tag. - */ - -#ifndef __TC_CCM_MODE_H__ -#define __TC_CCM_MODE_H__ - -#include "aes.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* max additional authenticated size in bytes: 2^16 - 2^8 = 65280 */ -#define TC_CCM_AAD_MAX_BYTES 0xff00 - -/* max message size in bytes: 2^(8L) = 2^16 = 65536 */ -#define TC_CCM_PAYLOAD_MAX_BYTES 0x10000 - -/* struct tc_ccm_mode_struct represents the state of a CCM computation */ -typedef struct tc_ccm_mode_struct { - TCAesKeySched_t sched; /* AES key schedule */ - uint8_t *nonce; /* nonce required by CCM */ - unsigned int mlen; /* mac length in bytes (parameter t in SP-800 38C) */ -} *TCCcmMode_t; - -/** - * @brief CCM configuration procedure - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * c == NULL or - * sched == NULL or - * nonce == NULL or - * mlen != {4, 6, 8, 10, 12, 16} - * @param c -- CCM state - * @param sched IN -- AES key schedule - * @param nonce IN - nonce - * @param nlen -- nonce length in bytes - * @param mlen -- mac length in bytes (parameter t in SP-800 38C) - */ -int tc_ccm_config(TCCcmMode_t c, TCAesKeySched_t sched, uint8_t *nonce, - unsigned int nlen, unsigned int mlen); - -/** - * @brief CCM tag generation and encryption procedure - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * out == NULL or - * c == NULL or - * ((plen > 0) and (payload == NULL)) or - * ((alen > 0) and (associated_data == NULL)) or - * (alen >= TC_CCM_AAD_MAX_BYTES) or - * (plen >= TC_CCM_PAYLOAD_MAX_BYTES) or - * (olen < plen + maclength) - * - * @param out OUT -- encrypted data - * @param olen IN -- output length in bytes - * @param associated_data IN -- associated data - * @param alen IN -- associated data length in bytes - * @param payload IN -- payload - * @param plen IN -- payload length in bytes - * @param c IN -- CCM state - * - * @note: out buffer should be at least (plen + c->mlen) bytes long. - * - * @note: The sequence b for encryption is formatted as follows: - * b = [FLAGS | nonce | counter ], where: - * FLAGS is 1 byte long - * nonce is 13 bytes long - * counter is 2 bytes long - * The byte FLAGS is composed by the following 8 bits: - * 0-2 bits: used to represent the value of q-1 - * 3-7 btis: always 0's - * - * @note: The sequence b for authentication is formatted as follows: - * b = [FLAGS | nonce | length(mac length)], where: - * FLAGS is 1 byte long - * nonce is 13 bytes long - * length(mac length) is 2 bytes long - * The byte FLAGS is composed by the following 8 bits: - * 0-2 bits: used to represent the value of q-1 - * 3-5 bits: mac length (encoded as: (mlen-2)/2) - * 6: Adata (0 if alen == 0, and 1 otherwise) - * 7: always 0 - */ -int tc_ccm_generation_encryption(uint8_t *out, unsigned int olen, - const uint8_t *associated_data, - unsigned int alen, const uint8_t *payload, - unsigned int plen, TCCcmMode_t c); - -/** - * @brief CCM decryption and tag verification procedure - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * out == NULL or - * c == NULL or - * ((plen > 0) and (payload == NULL)) or - * ((alen > 0) and (associated_data == NULL)) or - * (alen >= TC_CCM_AAD_MAX_BYTES) or - * (plen >= TC_CCM_PAYLOAD_MAX_BYTES) or - * (olen < plen - c->mlen) - * - * @param out OUT -- decrypted data - * @param associated_data IN -- associated data - * @param alen IN -- associated data length in bytes - * @param payload IN -- payload - * @param plen IN -- payload length in bytes - * @param c IN -- CCM state - * - * @note: out buffer should be at least (plen - c->mlen) bytes long. - * - * @note: The sequence b for encryption is formatted as follows: - * b = [FLAGS | nonce | counter ], where: - * FLAGS is 1 byte long - * nonce is 13 bytes long - * counter is 2 bytes long - * The byte FLAGS is composed by the following 8 bits: - * 0-2 bits: used to represent the value of q-1 - * 3-7 btis: always 0's - * - * @note: The sequence b for authentication is formatted as follows: - * b = [FLAGS | nonce | length(mac length)], where: - * FLAGS is 1 byte long - * nonce is 13 bytes long - * length(mac length) is 2 bytes long - * The byte FLAGS is composed by the following 8 bits: - * 0-2 bits: used to represent the value of q-1 - * 3-5 bits: mac length (encoded as: (mlen-2)/2) - * 6: Adata (0 if alen == 0, and 1 otherwise) - * 7: always 0 - */ -int tc_ccm_decryption_verification(uint8_t *out, unsigned int olen, - const uint8_t *associated_data, - unsigned int alen, const uint8_t *payload, unsigned int plen, - TCCcmMode_t c); - -#ifdef __cplusplus -} -#endif - -#endif /* __TC_CCM_MODE_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/cmac_mode.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/cmac_mode.h deleted file mode 100644 index 327097026..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/cmac_mode.h +++ /dev/null @@ -1,194 +0,0 @@ -/* cmac_mode.h -- interface to a CMAC implementation */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief Interface to a CMAC implementation. - * - * Overview: CMAC is defined NIST in SP 800-38B, and is the standard algorithm - * for computing a MAC using a block cipher. It can compute the MAC - * for a byte string of any length. It is distinguished from CBC-MAC - * in the processing of the final message block; CMAC uses a - * different technique to compute the final message block is full - * size or only partial, while CBC-MAC uses the same technique for - * both. This difference permits CMAC to be applied to variable - * length messages, while all messages authenticated by CBC-MAC must - * be the same length. - * - * Security: AES128-CMAC mode of operation offers 64 bits of security against - * collision attacks. Note however that an external attacker cannot - * generate the tags him/herself without knowing the MAC key. In this - * sense, to attack the collision property of AES128-CMAC, an - * external attacker would need the cooperation of the legal user to - * produce an exponentially high number of tags (e.g. 2^64) to - * finally be able to look for collisions and benefit from them. As - * an extra precaution, the current implementation allows to at most - * 2^48 calls to the tc_cmac_update function before re-calling - * tc_cmac_setup (allowing a new key to be set), as suggested in - * Appendix B of SP 800-38B. - * - * Requires: AES-128 - * - * Usage: This implementation provides a "scatter-gather" interface, so that - * the CMAC value can be computed incrementally over a message - * scattered in different segments throughout memory. Experience shows - * this style of interface tends to minimize the burden of programming - * correctly. Like all symmetric key operations, it is session - * oriented. - * - * To begin a CMAC session, use tc_cmac_setup to initialize a struct - * tc_cmac_struct with encryption key and buffer. Our implementation - * always assume that the AES key to be the same size as the block - * cipher block size. Once setup, this data structure can be used for - * many CMAC computations. - * - * Once the state has been setup with a key, computing the CMAC of - * some data requires three steps: - * - * (1) first use tc_cmac_init to initialize a new CMAC computation. - * (2) next mix all of the data into the CMAC computation state using - * tc_cmac_update. If all of the data resides in a single data - * segment then only one tc_cmac_update call is needed; if data - * is scattered throughout memory in n data segments, then n calls - * will be needed. CMAC IS ORDER SENSITIVE, to be able to detect - * attacks that swap bytes, so the order in which data is mixed - * into the state is critical! - * (3) Once all of the data for a message has been mixed, use - * tc_cmac_final to compute the CMAC tag value. - * - * Steps (1)-(3) can be repeated as many times as you want to CMAC - * multiple messages. A practical limit is 2^48 1K messages before you - * have to change the key. - * - * Once you are done computing CMAC with a key, it is a good idea to - * destroy the state so an attacker cannot recover the key; use - * tc_cmac_erase to accomplish this. - */ - -#ifndef __TC_CMAC_MODE_H__ -#define __TC_CMAC_MODE_H__ - -#include "aes.h" - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* padding for last message block */ -#define TC_CMAC_PADDING 0x80 - -/* struct tc_cmac_struct represents the state of a CMAC computation */ -typedef struct tc_cmac_struct { -/* initialization vector */ - uint8_t iv[TC_AES_BLOCK_SIZE]; -/* used if message length is a multiple of block_size bytes */ - uint8_t K1[TC_AES_BLOCK_SIZE]; -/* used if message length isn't a multiple block_size bytes */ - uint8_t K2[TC_AES_BLOCK_SIZE]; -/* where to put bytes that didn't fill a block */ - uint8_t leftover[TC_AES_BLOCK_SIZE]; -/* identifies the encryption key */ - unsigned int keyid; -/* next available leftover location */ - unsigned int leftover_offset; -/* AES key schedule */ - TCAesKeySched_t sched; -/* calls to tc_cmac_update left before re-key */ - uint64_t countdown; -} *TCCmacState_t; - -/** - * @brief Configures the CMAC state to use the given AES key - * @return returns TC_CRYPTO_SUCCESS (1) after having configured the CMAC state - * returns TC_CRYPTO_FAIL (0) if: - * s == NULL or - * key == NULL - * - * @param s IN/OUT -- the state to set up - * @param key IN -- the key to use - * @param sched IN -- AES key schedule - */ -int tc_cmac_setup(TCCmacState_t s, const uint8_t *key, - TCAesKeySched_t sched); - -/** - * @brief Erases the CMAC state - * @return returns TC_CRYPTO_SUCCESS (1) after having configured the CMAC state - * returns TC_CRYPTO_FAIL (0) if: - * s == NULL - * - * @param s IN/OUT -- the state to erase - */ -int tc_cmac_erase(TCCmacState_t s); - -/** - * @brief Initializes a new CMAC computation - * @return returns TC_CRYPTO_SUCCESS (1) after having initialized the CMAC state - * returns TC_CRYPTO_FAIL (0) if: - * s == NULL - * - * @param s IN/OUT -- the state to initialize - */ -int tc_cmac_init(TCCmacState_t s); - -/** - * @brief Incrementally computes CMAC over the next data segment - * @return returns TC_CRYPTO_SUCCESS (1) after successfully updating the CMAC state - * returns TC_CRYPTO_FAIL (0) if: - * s == NULL or - * if data == NULL when dlen > 0 - * - * @param s IN/OUT -- the CMAC state - * @param data IN -- the next data segment to MAC - * @param dlen IN -- the length of data in bytes - */ -int tc_cmac_update(TCCmacState_t s, const uint8_t *data, size_t dlen); - -/** - * @brief Generates the tag from the CMAC state - * @return returns TC_CRYPTO_SUCCESS (1) after successfully generating the tag - * returns TC_CRYPTO_FAIL (0) if: - * tag == NULL or - * s == NULL - * - * @param tag OUT -- the CMAC tag - * @param s IN -- CMAC state - */ -int tc_cmac_final(uint8_t *tag, TCCmacState_t s); - -#ifdef __cplusplus -} -#endif - -#endif /* __TC_CMAC_MODE_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/constants.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/constants.h deleted file mode 100644 index 965490e00..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/constants.h +++ /dev/null @@ -1,61 +0,0 @@ -/* constants.h - TinyCrypt interface to constants */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief -- Interface to constants. - * - */ - -#ifndef __TC_CONSTANTS_H__ -#define __TC_CONSTANTS_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#ifndef NULL -#define NULL ((void *)0) -#endif - -#define TC_CRYPTO_SUCCESS 1 -#define TC_CRYPTO_FAIL 0 - -#define TC_ZERO_BYTE 0x00 - -#ifdef __cplusplus -} -#endif - -#endif /* __TC_CONSTANTS_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ctr_mode.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ctr_mode.h deleted file mode 100644 index e2da5b43b..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ctr_mode.h +++ /dev/null @@ -1,108 +0,0 @@ -/* ctr_mode.h - TinyCrypt interface to CTR mode */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief Interface to CTR mode. - * - * Overview: CTR (pronounced "counter") mode is a NIST approved mode of - * operation defined in SP 800-38a. It can be used with any - * block cipher to provide confidentiality of strings of any - * length. TinyCrypt hard codes AES128 as the block cipher. - * - * Security: CTR mode achieves confidentiality only if the counter value is - * never reused with a same encryption key. If the counter is - * repeated, than an adversary might be able to defeat the scheme. - * - * A usual method to ensure different counter values refers to - * initialize the counter in a given value (0, for example) and - * increases it every time a new block is enciphered. This naturally - * leaves to a limitation on the number q of blocks that can be - * enciphered using a same key: q < 2^(counter size). - * - * TinyCrypt uses a counter of 32 bits. This means that after 2^32 - * block encryptions, the counter will be reused (thus losing CBC - * security). 2^32 block encryptions should be enough for most of - * applications targeting constrained devices. Applications intended - * to encrypt a larger number of blocks must replace the key after - * 2^32 block encryptions. - * - * CTR mode provides NO data integrity. - * - * Requires: AES-128 - * - * Usage: 1) call tc_ctr_mode to process the data to encrypt/decrypt. - * - */ - -#ifndef __TC_CTR_MODE_H__ -#define __TC_CTR_MODE_H__ - -#include "aes.h" -#include "constants.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief CTR mode encryption/decryption procedure. - * CTR mode encrypts (or decrypts) inlen bytes from in buffer into out buffer - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * out == NULL or - * in == NULL or - * ctr == NULL or - * sched == NULL or - * inlen == 0 or - * outlen == 0 or - * inlen != outlen - * @note Assumes:- The current value in ctr has NOT been used with sched - * - out points to inlen bytes - * - in points to inlen bytes - * - ctr is an integer counter in littleEndian format - * - sched was initialized by aes_set_encrypt_key - * @param out OUT -- produced ciphertext (plaintext) - * @param outlen IN -- length of ciphertext buffer in bytes - * @param in IN -- data to encrypt (or decrypt) - * @param inlen IN -- length of input data in bytes - * @param ctr IN/OUT -- the current counter value - * @param sched IN -- an initialized AES key schedule - */ -int tc_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in, - unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched); - -#ifdef __cplusplus -} -#endif - -#endif /* __TC_CTR_MODE_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ctr_prng.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ctr_prng.h deleted file mode 100644 index bff7f9726..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ctr_prng.h +++ /dev/null @@ -1,166 +0,0 @@ -/* ctr_prng.h - TinyCrypt interface to a CTR-PRNG implementation */ - -/* - * Copyright (c) 2016, Chris Morrison - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief Interface to a CTR-PRNG implementation. - * - * Overview: A pseudo-random number generator (PRNG) generates a sequence - * of numbers that have a distribution close to the one expected - * for a sequence of truly random numbers. The NIST Special - * Publication 800-90A specifies several mechanisms to generate - * sequences of pseudo random numbers, including the CTR-PRNG one - * which is based on AES. TinyCrypt implements CTR-PRNG with - * AES-128. - * - * Security: A cryptographically secure PRNG depends on the existence of an - * entropy source to provide a truly random seed as well as the - * security of the primitives used as the building blocks (AES-128 - * in this instance). - * - * Requires: - AES-128 - * - * Usage: 1) call tc_ctr_prng_init to seed the prng context - * - * 2) call tc_ctr_prng_reseed to mix in additional entropy into - * the prng context - * - * 3) call tc_ctr_prng_generate to output the pseudo-random data - * - * 4) call tc_ctr_prng_uninstantiate to zero out the prng context - */ - -#ifndef __TC_CTR_PRNG_H__ -#define __TC_CTR_PRNG_H__ - -#include "aes.h" - -#define TC_CTR_PRNG_RESEED_REQ -1 - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - /* updated each time another BLOCKLEN_BYTES bytes are produced */ - uint8_t V[TC_AES_BLOCK_SIZE]; - - /* updated whenever the PRNG is reseeded */ - struct tc_aes_key_sched_struct key; - - /* number of requests since initialization/reseeding */ - uint64_t reseedCount; -} TCCtrPrng_t; - - -/** - * @brief CTR-PRNG initialization procedure - * Initializes prng context with entropy and personalization string (if any) - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * ctx == NULL, - * entropy == NULL, - * entropyLen < (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) - * @note Only the first (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes of - * both the entropy and personalization inputs are used - - * supplying additional bytes has no effect. - * @param ctx IN/OUT -- the PRNG context to initialize - * @param entropy IN -- entropy used to seed the PRNG - * @param entropyLen IN -- entropy length in bytes - * @param personalization IN -- personalization string used to seed the PRNG - * (may be null) - * @param plen IN -- personalization length in bytes - * - */ -int tc_ctr_prng_init(TCCtrPrng_t * const ctx, - uint8_t const * const entropy, - unsigned int entropyLen, - uint8_t const * const personalization, - unsigned int pLen); - -/** - * @brief CTR-PRNG reseed procedure - * Mixes entropy and additional_input into the prng context - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * ctx == NULL, - * entropy == NULL, - * entropylen < (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) - * @note It is better to reseed an existing prng context rather than - * re-initialise, so that any existing entropy in the context is - * presereved. This offers some protection against undetected failures - * of the entropy source. - * @note Assumes tc_ctr_prng_init has been called for ctx - * @param ctx IN/OUT -- the PRNG state - * @param entropy IN -- entropy to mix into the prng - * @param entropylen IN -- length of entropy in bytes - * @param additional_input IN -- additional input to the prng (may be null) - * @param additionallen IN -- additional input length in bytes - */ -int tc_ctr_prng_reseed(TCCtrPrng_t * const ctx, - uint8_t const * const entropy, - unsigned int entropyLen, - uint8_t const * const additional_input, - unsigned int additionallen); - -/** - * @brief CTR-PRNG generate procedure - * Generates outlen pseudo-random bytes into out buffer, updates prng - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CTR_PRNG_RESEED_REQ (-1) if a reseed is needed - * returns TC_CRYPTO_FAIL (0) if: - * ctx == NULL, - * out == NULL, - * outlen >= 2^16 - * @note Assumes tc_ctr_prng_init has been called for ctx - * @param ctx IN/OUT -- the PRNG context - * @param additional_input IN -- additional input to the prng (may be null) - * @param additionallen IN -- additional input length in bytes - * @param out IN/OUT -- buffer to receive output - * @param outlen IN -- size of out buffer in bytes - */ -int tc_ctr_prng_generate(TCCtrPrng_t * const ctx, - uint8_t const * const additional_input, - unsigned int additionallen, - uint8_t * const out, - unsigned int outlen); - -/** - * @brief CTR-PRNG uninstantiate procedure - * Zeroes the internal state of the supplied prng context - * @return none - * @param ctx IN/OUT -- the PRNG context - */ -void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx); - -#ifdef __cplusplus -} -#endif - -#endif /* __TC_CTR_PRNG_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ecc.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ecc.h deleted file mode 100644 index 8abc949cc..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ecc.h +++ /dev/null @@ -1,545 +0,0 @@ -/* ecc.h - TinyCrypt interface to common ECC functions */ - -/* Copyright (c) 2014, Kenneth MacKay - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief -- Interface to common ECC functions. - * - * Overview: This software is an implementation of common functions - * necessary to elliptic curve cryptography. This implementation uses - * curve NIST p-256. - * - * Security: The curve NIST p-256 provides approximately 128 bits of security. - * - */ - -#ifndef __TC_UECC_H__ -#define __TC_UECC_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Word size (4 bytes considering 32-bits architectures) */ -#define uECC_WORD_SIZE 4 - -/* setting max number of calls to prng: */ -#ifndef uECC_RNG_MAX_TRIES -#define uECC_RNG_MAX_TRIES 64 -#endif - -/* defining data types to store word and bit counts: */ -typedef int8_t wordcount_t; -typedef int16_t bitcount_t; -/* defining data type for comparison result: */ -typedef int8_t cmpresult_t; -/* defining data type to store ECC coordinate/point in 32bits words: */ -typedef unsigned int uECC_word_t; -/* defining data type to store an ECC coordinate/point in 64bits words: */ -typedef uint64_t uECC_dword_t; - -/* defining masks useful for ecc computations: */ -#define HIGH_BIT_SET 0x80000000 -#define uECC_WORD_BITS 32 -#define uECC_WORD_BITS_SHIFT 5 -#define uECC_WORD_BITS_MASK 0x01F - -/* Number of words of 32 bits to represent an element of the the curve p-256: */ -#define NUM_ECC_WORDS 8 -/* Number of bytes to represent an element of the the curve p-256: */ -#define NUM_ECC_BYTES (uECC_WORD_SIZE*NUM_ECC_WORDS) - -/* structure that represents an elliptic curve (e.g. p256):*/ -struct uECC_Curve_t; -typedef const struct uECC_Curve_t * uECC_Curve; -struct uECC_Curve_t { - wordcount_t num_words; - wordcount_t num_bytes; - bitcount_t num_n_bits; - uECC_word_t p[NUM_ECC_WORDS]; - uECC_word_t n[NUM_ECC_WORDS]; - uECC_word_t G[NUM_ECC_WORDS * 2]; - uECC_word_t b[NUM_ECC_WORDS]; - void (*double_jacobian)(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * Z1, - uECC_Curve curve); - void (*x_side)(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve); - void (*mmod_fast)(uECC_word_t *result, uECC_word_t *product); -}; - -/* - * @brief computes doubling of point ion jacobian coordinates, in place. - * @param X1 IN/OUT -- x coordinate - * @param Y1 IN/OUT -- y coordinate - * @param Z1 IN/OUT -- z coordinate - * @param curve IN -- elliptic curve - */ -void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1, - uECC_word_t * Z1, uECC_Curve curve); - -/* - * @brief Computes x^3 + ax + b. result must not overlap x. - * @param result OUT -- x^3 + ax + b - * @param x IN -- value of x - * @param curve IN -- elliptic curve - */ -void x_side_default(uECC_word_t *result, const uECC_word_t *x, - uECC_Curve curve); - -/* - * @brief Computes result = product % curve_p - * from http://www.nsa.gov/ia/_files/nist-routines.pdf - * @param result OUT -- product % curve_p - * @param product IN -- value to be reduced mod curve_p - */ -void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int *product); - -/* Bytes to words ordering: */ -#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##d##c##b##a, 0x##h##g##f##e -#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a -#define BITS_TO_WORDS(num_bits) \ - ((num_bits + ((uECC_WORD_SIZE * 8) - 1)) / (uECC_WORD_SIZE * 8)) -#define BITS_TO_BYTES(num_bits) ((num_bits + 7) / 8) - -/* definition of curve NIST p-256: */ -static const struct uECC_Curve_t curve_secp256r1 = { - NUM_ECC_WORDS, - NUM_ECC_BYTES, - 256, /* num_n_bits */ { - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00), - BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), - BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF) - }, { - BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3), - BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF) - }, { - BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4), - BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77), - BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8), - BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B), - - BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB), - BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B), - BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E), - BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F) - }, { - BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B), - BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65), - BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3), - BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A) - }, - &double_jacobian_default, - &x_side_default, - &vli_mmod_fast_secp256r1 -}; - -uECC_Curve uECC_secp256r1(void); - -/* - * @brief Generates a random integer in the range 0 < random < top. - * Both random and top have num_words words. - * @param random OUT -- random integer in the range 0 < random < top - * @param top IN -- upper limit - * @param num_words IN -- number of words - * @return a random integer in the range 0 < random < top - */ -int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top, - wordcount_t num_words); - - -/* uECC_RNG_Function type - * The RNG function should fill 'size' random bytes into 'dest'. It should - * return 1 if 'dest' was filled with random data, or 0 if the random data could - * not be generated. The filled-in values should be either truly random, or from - * a cryptographically-secure PRNG. - * - * A correctly functioning RNG function must be set (using uECC_set_rng()) - * before calling uECC_make_key() or uECC_sign(). - * - * Setting a correctly functioning RNG function improves the resistance to - * side-channel attacks for uECC_shared_secret(). - * - * A correct RNG function is set by default. If you are building on another - * POSIX-compliant system that supports /dev/random or /dev/urandom, you can - * define uECC_POSIX to use the predefined RNG. - */ -typedef int(*uECC_RNG_Function)(uint8_t *dest, unsigned int size); - -/* - * @brief Set the function that will be used to generate random bytes. The RNG - * function should return 1 if the random data was generated, or 0 if the random - * data could not be generated. - * - * @note On platforms where there is no predefined RNG function, this must be - * called before uECC_make_key() or uECC_sign() are used. - * - * @param rng_function IN -- function that will be used to generate random bytes - */ -void uECC_set_rng(uECC_RNG_Function rng_function); - -/* - * @brief provides current uECC_RNG_Function. - * @return Returns the function that will be used to generate random bytes. - */ -uECC_RNG_Function uECC_get_rng(void); - -/* - * @brief computes the size of a private key for the curve in bytes. - * @param curve IN -- elliptic curve - * @return size of a private key for the curve in bytes. - */ -int uECC_curve_private_key_size(uECC_Curve curve); - -/* - * @brief computes the size of a public key for the curve in bytes. - * @param curve IN -- elliptic curve - * @return the size of a public key for the curve in bytes. - */ -int uECC_curve_public_key_size(uECC_Curve curve); - -/* - * @brief Compute the corresponding public key for a private key. - * @param private_key IN -- The private key to compute the public key for - * @param public_key OUT -- Will be filled in with the corresponding public key - * @param curve - * @return Returns 1 if key was computed successfully, 0 if an error occurred. - */ -int uECC_compute_public_key(const uint8_t *private_key, - uint8_t *public_key, uECC_Curve curve); - -/* - * @brief Compute public-key. - * @return corresponding public-key. - * @param result OUT -- public-key - * @param private_key IN -- private-key - * @param curve IN -- elliptic curve - */ -uECC_word_t EccPoint_compute_public_key(uECC_word_t *result, - uECC_word_t *private_key, uECC_Curve curve); - -/* - * @brief Regularize the bitcount for the private key so that attackers cannot - * use a side channel attack to learn the number of leading zeros. - * @return Regularized k - * @param k IN -- private-key - * @param k0 IN/OUT -- regularized k - * @param k1 IN/OUT -- regularized k - * @param curve IN -- elliptic curve - */ -uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0, - uECC_word_t *k1, uECC_Curve curve); - -/* - * @brief Point multiplication algorithm using Montgomery's ladder with co-Z - * coordinates. See http://eprint.iacr.org/2011/338.pdf. - * @note Result may overlap point. - * @param result OUT -- returns scalar*point - * @param point IN -- elliptic curve point - * @param scalar IN -- scalar - * @param initial_Z IN -- initial value for z - * @param num_bits IN -- number of bits in scalar - * @param curve IN -- elliptic curve - */ -void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point, - const uECC_word_t * scalar, const uECC_word_t * initial_Z, - bitcount_t num_bits, uECC_Curve curve); - -/* - * @brief Constant-time comparison to zero - secure way to compare long integers - * @param vli IN -- very long integer - * @param num_words IN -- number of words in the vli - * @return 1 if vli == 0, 0 otherwise. - */ -uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words); - -/* - * @brief Check if 'point' is the point at infinity - * @param point IN -- elliptic curve point - * @param curve IN -- elliptic curve - * @return if 'point' is the point at infinity, 0 otherwise. - */ -uECC_word_t EccPoint_isZero(const uECC_word_t *point, uECC_Curve curve); - -/* - * @brief computes the sign of left - right, in constant time. - * @param left IN -- left term to be compared - * @param right IN -- right term to be compared - * @param num_words IN -- number of words - * @return the sign of left - right - */ -cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right, - wordcount_t num_words); - -/* - * @brief computes sign of left - right, not in constant time. - * @note should not be used if inputs are part of a secret - * @param left IN -- left term to be compared - * @param right IN -- right term to be compared - * @param num_words IN -- number of words - * @return the sign of left - right - */ -cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, const uECC_word_t *right, - wordcount_t num_words); - -/* - * @brief Computes result = (left - right) % mod. - * @note Assumes that (left < mod) and (right < mod), and that result does not - * overlap mod. - * @param result OUT -- (left - right) % mod - * @param left IN -- leftright term in modular subtraction - * @param right IN -- right term in modular subtraction - * @param mod IN -- mod - * @param num_words IN -- number of words - */ -void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left, - const uECC_word_t *right, const uECC_word_t *mod, - wordcount_t num_words); - -/* - * @brief Computes P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) or - * P => P', Q => P + Q - * @note assumes Input P = (x1, y1, Z), Q = (x2, y2, Z) - * @param X1 IN -- x coordinate of P - * @param Y1 IN -- y coordinate of P - * @param X2 IN -- x coordinate of Q - * @param Y2 IN -- y coordinate of Q - * @param curve IN -- elliptic curve - */ -void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * X2, - uECC_word_t * Y2, uECC_Curve curve); - -/* - * @brief Computes (x1 * z^2, y1 * z^3) - * @param X1 IN -- previous x1 coordinate - * @param Y1 IN -- previous y1 coordinate - * @param Z IN -- z value - * @param curve IN -- elliptic curve - */ -void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z, - uECC_Curve curve); - -/* - * @brief Check if bit is set. - * @return Returns nonzero if bit 'bit' of vli is set. - * @warning It is assumed that the value provided in 'bit' is within the - * boundaries of the word-array 'vli'. - * @note The bit ordering layout assumed for vli is: {31, 30, ..., 0}, - * {63, 62, ..., 32}, {95, 94, ..., 64}, {127, 126,..., 96} for a vli consisting - * of 4 uECC_word_t elements. - */ -uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit); - -/* - * @brief Computes result = product % mod, where product is 2N words long. - * @param result OUT -- product % mod - * @param mod IN -- module - * @param num_words IN -- number of words - * @warning Currently only designed to work for curve_p or curve_n. - */ -void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product, - const uECC_word_t *mod, wordcount_t num_words); - -/* - * @brief Computes modular product (using curve->mmod_fast) - * @param result OUT -- (left * right) mod % curve_p - * @param left IN -- left term in product - * @param right IN -- right term in product - * @param curve IN -- elliptic curve - */ -void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left, - const uECC_word_t *right, uECC_Curve curve); - -/* - * @brief Computes result = left - right. - * @note Can modify in place. - * @param result OUT -- left - right - * @param left IN -- left term in subtraction - * @param right IN -- right term in subtraction - * @param num_words IN -- number of words - * @return borrow - */ -uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left, - const uECC_word_t *right, wordcount_t num_words); - -/* - * @brief Constant-time comparison function(secure way to compare long ints) - * @param left IN -- left term in comparison - * @param right IN -- right term in comparison - * @param num_words IN -- number of words - * @return Returns 0 if left == right, 1 otherwise. - */ -uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right, - wordcount_t num_words); - -/* - * @brief Computes (left * right) % mod - * @param result OUT -- (left * right) % mod - * @param left IN -- left term in product - * @param right IN -- right term in product - * @param mod IN -- mod - * @param num_words IN -- number of words - */ -void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left, - const uECC_word_t *right, const uECC_word_t *mod, - wordcount_t num_words); - -/* - * @brief Computes (1 / input) % mod - * @note All VLIs are the same size. - * @note See "Euclid's GCD to Montgomery Multiplication to the Great Divide" - * @param result OUT -- (1 / input) % mod - * @param input IN -- value to be modular inverted - * @param mod IN -- mod - * @param num_words -- number of words - */ -void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input, - const uECC_word_t *mod, wordcount_t num_words); - -/* - * @brief Sets dest = src. - * @param dest OUT -- destination buffer - * @param src IN -- origin buffer - * @param num_words IN -- number of words - */ -void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, - wordcount_t num_words); - -/* - * @brief Computes (left + right) % mod. - * @note Assumes that (left < mod) and right < mod), and that result does not - * overlap mod. - * @param result OUT -- (left + right) % mod. - * @param left IN -- left term in addition - * @param right IN -- right term in addition - * @param mod IN -- mod - * @param num_words IN -- number of words - */ -void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left, - const uECC_word_t *right, const uECC_word_t *mod, - wordcount_t num_words); - -/* - * @brief Counts the number of bits required to represent vli. - * @param vli IN -- very long integer - * @param max_words IN -- number of words - * @return number of bits in given vli - */ -bitcount_t uECC_vli_numBits(const uECC_word_t *vli, - const wordcount_t max_words); - -/* - * @brief Erases (set to 0) vli - * @param vli IN -- very long integer - * @param num_words IN -- number of words - */ -void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words); - -/* - * @brief check if it is a valid point in the curve - * @param point IN -- point to be checked - * @param curve IN -- elliptic curve - * @return 0 if point is valid - * @exception returns -1 if it is a point at infinity - * @exception returns -2 if x or y is smaller than p, - * @exception returns -3 if y^2 != x^3 + ax + b. - */ -int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve); - -/* - * @brief Check if a public key is valid. - * @param public_key IN -- The public key to be checked. - * @return returns 0 if the public key is valid - * @exception returns -1 if it is a point at infinity - * @exception returns -2 if x or y is smaller than p, - * @exception returns -3 if y^2 != x^3 + ax + b. - * @exception returns -4 if public key is the group generator. - * - * @note Note that you are not required to check for a valid public key before - * using any other uECC functions. However, you may wish to avoid spending CPU - * time computing a shared secret or verifying a signature using an invalid - * public key. - */ -int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve); - - /* - * @brief Converts an integer in uECC native format to big-endian bytes. - * @param bytes OUT -- bytes representation - * @param num_bytes IN -- number of bytes - * @param native IN -- uECC native representation - */ -void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes, - const unsigned int *native); - -/* - * @brief Converts big-endian bytes to an integer in uECC native format. - * @param native OUT -- uECC native representation - * @param bytes IN -- bytes representation - * @param num_bytes IN -- number of bytes - */ -void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes, - int num_bytes); - -#ifdef __cplusplus -} -#endif - -#endif /* __TC_UECC_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ecc_dh.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ecc_dh.h deleted file mode 100644 index 930e9162e..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ecc_dh.h +++ /dev/null @@ -1,131 +0,0 @@ -/* ecc_dh.h - TinyCrypt interface to EC-DH implementation */ - -/* - * Copyright (c) 2014, Kenneth MacKay - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief -- Interface to EC-DH implementation. - * - * Overview: This software is an implementation of EC-DH. This implementation - * uses curve NIST p-256. - * - * Security: The curve NIST p-256 provides approximately 128 bits of security. - */ - -#ifndef __TC_ECC_DH_H__ -#define __TC_ECC_DH_H__ - -#include "ecc.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Create a public/private key pair. - * @return returns TC_CRYPTO_SUCCESS (1) if the key pair was generated successfully - * returns TC_CRYPTO_FAIL (0) if error while generating key pair - * - * @param p_public_key OUT -- Will be filled in with the public key. Must be at - * least 2 * the curve size (in bytes) long. For curve secp256r1, p_public_key - * must be 64 bytes long. - * @param p_private_key OUT -- Will be filled in with the private key. Must be as - * long as the curve order (for secp256r1, p_private_key must be 32 bytes long). - * - * @note side-channel countermeasure: algorithm strengthened against timing - * attack. - * @warning A cryptographically-secure PRNG function must be set (using - * uECC_set_rng()) before calling uECC_make_key(). - */ -int uECC_make_key(uint8_t *p_public_key, uint8_t *p_private_key, uECC_Curve curve); - -#ifdef ENABLE_TESTS - -/** - * @brief Create a public/private key pair given a specific d. - * - * @note THIS FUNCTION SHOULD BE CALLED ONLY FOR TEST PURPOSES. Refer to - * uECC_make_key() function for real applications. - */ -int uECC_make_key_with_d(uint8_t *p_public_key, uint8_t *p_private_key, - unsigned int *d, uECC_Curve curve); -#endif - -/** - * @brief Compute a shared secret given your secret key and someone else's - * public key. - * @return returns TC_CRYPTO_SUCCESS (1) if the shared secret was computed successfully - * returns TC_CRYPTO_FAIL (0) otherwise - * - * @param p_secret OUT -- Will be filled in with the shared secret value. Must be - * the same size as the curve size (for curve secp256r1, secret must be 32 bytes - * long. - * @param p_public_key IN -- The public key of the remote party. - * @param p_private_key IN -- Your private key. - * - * @warning It is recommended to use the output of uECC_shared_secret() as the - * input of a recommended Key Derivation Function (see NIST SP 800-108) in - * order to produce a cryptographically secure symmetric key. - */ -int uECC_shared_secret(const uint8_t *p_public_key, const uint8_t *p_private_key, - uint8_t *p_secret, uECC_Curve curve); - -#ifdef __cplusplus -} -#endif - -#endif /* __TC_ECC_DH_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ecc_dsa.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ecc_dsa.h deleted file mode 100644 index 8cb421b7a..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ecc_dsa.h +++ /dev/null @@ -1,139 +0,0 @@ -/* ecc_dh.h - TinyCrypt interface to EC-DSA implementation */ - -/* - * Copyright (c) 2014, Kenneth MacKay - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief -- Interface to EC-DSA implementation. - * - * Overview: This software is an implementation of EC-DSA. This implementation - * uses curve NIST p-256. - * - * Security: The curve NIST p-256 provides approximately 128 bits of security. - * - * Usage: - To sign: Compute a hash of the data you wish to sign (SHA-2 is - * recommended) and pass it in to ecdsa_sign function along with your - * private key and a random number. You must use a new non-predictable - * random number to generate each new signature. - * - To verify a signature: Compute the hash of the signed data using - * the same hash as the signer and pass it to this function along with - * the signer's public key and the signature values (r and s). - */ - -#ifndef __TC_ECC_DSA_H__ -#define __TC_ECC_DSA_H__ - -#include "ecc.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Generate an ECDSA signature for a given hash value. - * @return returns TC_CRYPTO_SUCCESS (1) if the signature generated successfully - * returns TC_CRYPTO_FAIL (0) if an error occurred. - * - * @param p_private_key IN -- Your private key. - * @param p_message_hash IN -- The hash of the message to sign. - * @param p_hash_size IN -- The size of p_message_hash in bytes. - * @param p_signature OUT -- Will be filled in with the signature value. Must be - * at least 2 * curve size long (for secp256r1, signature must be 64 bytes long). - * - * @warning A cryptographically-secure PRNG function must be set (using - * uECC_set_rng()) before calling uECC_sign(). - * @note Usage: Compute a hash of the data you wish to sign (SHA-2 is - * recommended) and pass it in to this function along with your private key. - * @note side-channel countermeasure: algorithm strengthened against timing - * attack. - */ -int uECC_sign(const uint8_t *p_private_key, const uint8_t *p_message_hash, - unsigned p_hash_size, uint8_t *p_signature, uECC_Curve curve); - -#ifdef ENABLE_TESTS -/* - * THIS FUNCTION SHOULD BE CALLED FOR TEST PURPOSES ONLY. - * Refer to uECC_sign() function for real applications. - */ -int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, - unsigned int hash_size, uECC_word_t *k, uint8_t *signature, - uECC_Curve curve); -#endif - -/** - * @brief Verify an ECDSA signature. - * @return returns TC_SUCCESS (1) if the signature is valid - * returns TC_FAIL (0) if the signature is invalid. - * - * @param p_public_key IN -- The signer's public key. - * @param p_message_hash IN -- The hash of the signed data. - * @param p_hash_size IN -- The size of p_message_hash in bytes. - * @param p_signature IN -- The signature values. - * - * @note Usage: Compute the hash of the signed data using the same hash as the - * signer and pass it to this function along with the signer's public key and - * the signature values (hash_size and signature). - */ -int uECC_verify(const uint8_t *p_public_key, const uint8_t *p_message_hash, - unsigned int p_hash_size, const uint8_t *p_signature, uECC_Curve curve); - -#ifdef __cplusplus -} -#endif - -#endif /* __TC_ECC_DSA_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ecc_platform_specific.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ecc_platform_specific.h deleted file mode 100644 index a55adf4f6..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/ecc_platform_specific.h +++ /dev/null @@ -1,81 +0,0 @@ -/* uECC_platform_specific.h - Interface to platform specific functions*/ - -/* Copyright (c) 2014, Kenneth MacKay - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE.*/ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * uECC_platform_specific.h -- Interface to platform specific functions - */ - -#ifndef __UECC_PLATFORM_SPECIFIC_H_ -#define __UECC_PLATFORM_SPECIFIC_H_ - -/* - * The RNG function should fill 'size' random bytes into 'dest'. It should - * return 1 if 'dest' was filled with random data, or 0 if the random data could - * not be generated. The filled-in values should be either truly random, or from - * a cryptographically-secure PRNG. - * - * A cryptographically-secure PRNG function must be set (using uECC_set_rng()) - * before calling uECC_make_key() or uECC_sign(). - * - * Setting a cryptographically-secure PRNG function improves the resistance to - * side-channel attacks for uECC_shared_secret(). - * - * A correct PRNG function is set by default (default_RNG_defined = 1) and works - * for some platforms, such as Unix and Linux. For other platforms, you may need - * to provide another PRNG function. -*/ -#define default_RNG_defined 0 - -int default_CSPRNG(uint8_t *dest, unsigned int size); - -#endif /* __UECC_PLATFORM_SPECIFIC_H_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/hmac.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/hmac.h deleted file mode 100644 index cfa7d38cd..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/hmac.h +++ /dev/null @@ -1,139 +0,0 @@ -/* hmac.h - TinyCrypt interface to an HMAC implementation */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief Interface to an HMAC implementation. - * - * Overview: HMAC is a message authentication code based on hash functions. - * TinyCrypt hard codes SHA-256 as the hash function. A message - * authentication code based on hash functions is also called a - * keyed cryptographic hash function since it performs a - * transformation specified by a key in an arbitrary length data - * set into a fixed length data set (also called tag). - * - * Security: The security of the HMAC depends on the length of the key and - * on the security of the hash function. Note that HMAC primitives - * are much less affected by collision attacks than their - * corresponding hash functions. - * - * Requires: SHA-256 - * - * Usage: 1) call tc_hmac_set_key to set the HMAC key. - * - * 2) call tc_hmac_init to initialize a struct hash_state before - * processing the data. - * - * 3) call tc_hmac_update to process the next input segment; - * tc_hmac_update can be called as many times as needed to process - * all of the segments of the input; the order is important. - * - * 4) call tc_hmac_final to out put the tag. - */ - -#ifndef __TC_HMAC_H__ -#define __TC_HMAC_H__ - -#include "sha256.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct tc_hmac_state_struct { - /* the internal state required by h */ - struct tc_sha256_state_struct hash_state; - /* HMAC key schedule */ - uint8_t key[2*TC_SHA256_BLOCK_SIZE]; -}; -typedef struct tc_hmac_state_struct *TCHmacState_t; - -/** - * @brief HMAC set key procedure - * Configures ctx to use key - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if - * ctx == NULL or - * key == NULL or - * key_size == 0 - * @param ctx IN/OUT -- the struct tc_hmac_state_struct to initial - * @param key IN -- the HMAC key to configure - * @param key_size IN -- the HMAC key size - */ -int tc_hmac_set_key(TCHmacState_t ctx, const uint8_t *key, - unsigned int key_size); - -/** - * @brief HMAC init procedure - * Initializes ctx to begin the next HMAC operation - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: ctx == NULL or key == NULL - * @param ctx IN/OUT -- struct tc_hmac_state_struct buffer to init - */ -int tc_hmac_init(TCHmacState_t ctx); - -/** - * @brief HMAC update procedure - * Mixes data_length bytes addressed by data into state - * @return returns TC_CRYPTO_SUCCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: ctx == NULL or key == NULL - * @note Assumes state has been initialized by tc_hmac_init - * @param ctx IN/OUT -- state of HMAC computation so far - * @param data IN -- data to incorporate into state - * @param data_length IN -- size of data in bytes - */ -int tc_hmac_update(TCHmacState_t ctx, const void *data, - unsigned int data_length); - -/** - * @brief HMAC final procedure - * Writes the HMAC tag into the tag buffer - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * tag == NULL or - * ctx == NULL or - * key == NULL or - * taglen != TC_SHA256_DIGEST_SIZE - * @note ctx is erased before exiting. This should never be changed/removed. - * @note Assumes the tag bufer is at least sizeof(hmac_tag_size(state)) bytes - * state has been initialized by tc_hmac_init - * @param tag IN/OUT -- buffer to receive computed HMAC tag - * @param taglen IN -- size of tag in bytes - * @param ctx IN/OUT -- the HMAC state for computing tag - */ -int tc_hmac_final(uint8_t *tag, unsigned int taglen, TCHmacState_t ctx); - -#ifdef __cplusplus -} -#endif - -#endif /*__TC_HMAC_H__*/ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/hmac_prng.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/hmac_prng.h deleted file mode 100644 index 24f417e6b..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/hmac_prng.h +++ /dev/null @@ -1,164 +0,0 @@ -/* hmac_prng.h - TinyCrypt interface to an HMAC-PRNG implementation */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief Interface to an HMAC-PRNG implementation. - * - * Overview: A pseudo-random number generator (PRNG) generates a sequence - * of numbers that have a distribution close to the one expected - * for a sequence of truly random numbers. The NIST Special - * Publication 800-90A specifies several mechanisms to generate - * sequences of pseudo random numbers, including the HMAC-PRNG one - * which is based on HMAC. TinyCrypt implements HMAC-PRNG with - * certain modifications from the NIST SP 800-90A spec. - * - * Security: A cryptographically secure PRNG depends on the existence of an - * entropy source to provide a truly random seed as well as the - * security of the primitives used as the building blocks (HMAC and - * SHA256, for TinyCrypt). - * - * The NIST SP 800-90A standard tolerates a null personalization, - * while TinyCrypt requires a non-null personalization. This is - * because a personalization string (the host name concatenated - * with a time stamp, for example) is easily computed and might be - * the last line of defense against failure of the entropy source. - * - * Requires: - SHA-256 - * - HMAC - * - * Usage: 1) call tc_hmac_prng_init to set the HMAC key and process the - * personalization data. - * - * 2) call tc_hmac_prng_reseed to process the seed and additional - * input. - * - * 3) call tc_hmac_prng_generate to out put the pseudo-random data. - */ - -#ifndef __TC_HMAC_PRNG_H__ -#define __TC_HMAC_PRNG_H__ - -#include "sha256.h" -#include "hmac.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define TC_HMAC_PRNG_RESEED_REQ -1 - -struct tc_hmac_prng_struct { - /* the HMAC instance for this PRNG */ - struct tc_hmac_state_struct h; - /* the PRNG key */ - uint8_t key[TC_SHA256_DIGEST_SIZE]; - /* PRNG state */ - uint8_t v[TC_SHA256_DIGEST_SIZE]; - /* calls to tc_hmac_prng_generate left before re-seed */ - unsigned int countdown; -}; - -typedef struct tc_hmac_prng_struct *TCHmacPrng_t; - -/** - * @brief HMAC-PRNG initialization procedure - * Initializes prng with personalization, disables tc_hmac_prng_generate - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * prng == NULL, - * personalization == NULL, - * plen > MAX_PLEN - * @note Assumes: - personalization != NULL. - * The personalization is a platform unique string (e.g., the host - * name) and is the last line of defense against failure of the - * entropy source - * @warning NIST SP 800-90A specifies 3 items as seed material during - * initialization: entropy seed, personalization, and an optional - * nonce. TinyCrypts requires instead a non-null personalization - * (which is easily computed) and indirectly requires an entropy - * seed (since the reseed function is mandatorily called after - * init) - * @param prng IN/OUT -- the PRNG state to initialize - * @param personalization IN -- personalization string - * @param plen IN -- personalization length in bytes - */ -int tc_hmac_prng_init(TCHmacPrng_t prng, - const uint8_t *personalization, - unsigned int plen); - -/** - * @brief HMAC-PRNG reseed procedure - * Mixes seed into prng, enables tc_hmac_prng_generate - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * prng == NULL, - * seed == NULL, - * seedlen < MIN_SLEN, - * seendlen > MAX_SLEN, - * additional_input != (const uint8_t *) 0 && additionallen == 0, - * additional_input != (const uint8_t *) 0 && additionallen > MAX_ALEN - * @note Assumes:- tc_hmac_prng_init has been called for prng - * - seed has sufficient entropy. - * - * @param prng IN/OUT -- the PRNG state - * @param seed IN -- entropy to mix into the prng - * @param seedlen IN -- length of seed in bytes - * @param additional_input IN -- additional input to the prng - * @param additionallen IN -- additional input length in bytes - */ -int tc_hmac_prng_reseed(TCHmacPrng_t prng, const uint8_t *seed, - unsigned int seedlen, const uint8_t *additional_input, - unsigned int additionallen); - -/** - * @brief HMAC-PRNG generate procedure - * Generates outlen pseudo-random bytes into out buffer, updates prng - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_HMAC_PRNG_RESEED_REQ (-1) if a reseed is needed - * returns TC_CRYPTO_FAIL (0) if: - * out == NULL, - * prng == NULL, - * outlen == 0, - * outlen >= MAX_OUT - * @note Assumes tc_hmac_prng_init has been called for prng - * @param out IN/OUT -- buffer to receive output - * @param outlen IN -- size of out buffer in bytes - * @param prng IN/OUT -- the PRNG state - */ -int tc_hmac_prng_generate(uint8_t *out, unsigned int outlen, TCHmacPrng_t prng); - -#ifdef __cplusplus -} -#endif - -#endif /* __TC_HMAC_PRNG_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/sha256.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/sha256.h deleted file mode 100644 index af5e8baf7..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/sha256.h +++ /dev/null @@ -1,129 +0,0 @@ -/* sha256.h - TinyCrypt interface to a SHA-256 implementation */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief Interface to a SHA-256 implementation. - * - * Overview: SHA-256 is a NIST approved cryptographic hashing algorithm - * specified in FIPS 180. A hash algorithm maps data of arbitrary - * size to data of fixed length. - * - * Security: SHA-256 provides 128 bits of security against collision attacks - * and 256 bits of security against pre-image attacks. SHA-256 does - * NOT behave like a random oracle, but it can be used as one if - * the string being hashed is prefix-free encoded before hashing. - * - * Usage: 1) call tc_sha256_init to initialize a struct - * tc_sha256_state_struct before hashing a new string. - * - * 2) call tc_sha256_update to hash the next string segment; - * tc_sha256_update can be called as many times as needed to hash - * all of the segments of a string; the order is important. - * - * 3) call tc_sha256_final to out put the digest from a hashing - * operation. - */ - -#ifndef __TC_SHA256_H__ -#define __TC_SHA256_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define TC_SHA256_BLOCK_SIZE (64) -#define TC_SHA256_DIGEST_SIZE (32) -#define TC_SHA256_STATE_BLOCKS (TC_SHA256_DIGEST_SIZE/4) - -struct tc_sha256_state_struct { - unsigned int iv[TC_SHA256_STATE_BLOCKS]; - uint64_t bits_hashed; - uint8_t leftover[TC_SHA256_BLOCK_SIZE]; - size_t leftover_offset; -}; - -typedef struct tc_sha256_state_struct *TCSha256State_t; - -/** - * @brief SHA256 initialization procedure - * Initializes s - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if s == NULL - * @param s Sha256 state struct - */ -int tc_sha256_init(TCSha256State_t s); - -/** - * @brief SHA256 update procedure - * Hashes data_length bytes addressed by data into state s - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * s == NULL, - * s->iv == NULL, - * data == NULL - * @note Assumes s has been initialized by tc_sha256_init - * @warning The state buffer 'leftover' is left in memory after processing - * If your application intends to have sensitive data in this - * buffer, remind to erase it after the data has been processed - * @param s Sha256 state struct - * @param data message to hash - * @param datalen length of message to hash - */ -int tc_sha256_update (TCSha256State_t s, const uint8_t *data, size_t datalen); - -/** - * @brief SHA256 final procedure - * Inserts the completed hash computation into digest - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * s == NULL, - * s->iv == NULL, - * digest == NULL - * @note Assumes: s has been initialized by tc_sha256_init - * digest points to at least TC_SHA256_DIGEST_SIZE bytes - * @warning The state buffer 'leftover' is left in memory after processing - * If your application intends to have sensitive data in this - * buffer, remind to erase it after the data has been processed - * @param digest unsigned eight bit integer - * @param Sha256 state struct - */ -int tc_sha256_final(uint8_t *digest, TCSha256State_t s); - -#ifdef __cplusplus -} -#endif - -#endif /* __TC_SHA256_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/utils.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/utils.h deleted file mode 100644 index bab5c3202..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/include/tinycrypt/utils.h +++ /dev/null @@ -1,95 +0,0 @@ -/* utils.h - TinyCrypt interface to platform-dependent run-time operations */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief Interface to platform-dependent run-time operations. - * - */ - -#ifndef __TC_UTILS_H__ -#define __TC_UTILS_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Copy the the buffer 'from' to the buffer 'to'. - * @return returns TC_CRYPTO_SUCCESS (1) - * returns TC_CRYPTO_FAIL (0) if: - * from_len > to_len. - * - * @param to OUT -- destination buffer - * @param to_len IN -- length of destination buffer - * @param from IN -- origin buffer - * @param from_len IN -- length of origin buffer - */ -unsigned int _copy(uint8_t *to, unsigned int to_len, - const uint8_t *from, unsigned int from_len); - -/** - * @brief Set the value 'val' into the buffer 'to', 'len' times. - * - * @param to OUT -- destination buffer - * @param val IN -- value to be set in 'to' - * @param len IN -- number of times the value will be copied - */ -void _set(void *to, uint8_t val, unsigned int len); - -/* - * @brief AES specific doubling function, which utilizes - * the finite field used by AES. - * @return Returns a^2 - * - * @param a IN/OUT -- value to be doubled - */ -uint8_t _double_byte(uint8_t a); - -/* - * @brief Constant-time algorithm to compare if two sequences of bytes are equal - * @return Returns 0 if equal, and non-zero otherwise - * - * @param a IN -- sequence of bytes a - * @param b IN -- sequence of bytes b - * @param size IN -- size of sequences a and b - */ -int _compare(const uint8_t *a, const uint8_t *b, size_t size); - -#ifdef __cplusplus -} -#endif - -#endif /* __TC_UTILS_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/aes_decrypt.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/aes_decrypt.c deleted file mode 100644 index 0bab6e280..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/aes_decrypt.c +++ /dev/null @@ -1,164 +0,0 @@ -/* aes_decrypt.c - TinyCrypt implementation of AES decryption procedure */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "../include/tinycrypt/aes.h" -#include "../include/tinycrypt/constants.h" -#include "../include/tinycrypt/utils.h" - -static const uint8_t inv_sbox[256] = { - 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, - 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, - 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, - 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, - 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, - 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, - 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, - 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, - 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, - 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, - 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, - 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, - 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, - 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, - 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, - 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, - 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, - 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, - 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, - 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, - 0x55, 0x21, 0x0c, 0x7d -}; - -int tc_aes128_set_decrypt_key(TCAesKeySched_t s, const uint8_t *k) -{ - return tc_aes128_set_encrypt_key(s, k); -} - -#define mult8(a)(_double_byte(_double_byte(_double_byte(a)))) -#define mult9(a)(mult8(a)^(a)) -#define multb(a)(mult8(a)^_double_byte(a)^(a)) -#define multd(a)(mult8(a)^_double_byte(_double_byte(a))^(a)) -#define multe(a)(mult8(a)^_double_byte(_double_byte(a))^_double_byte(a)) - -static inline void mult_row_column(uint8_t *out, const uint8_t *in) -{ - out[0] = multe(in[0]) ^ multb(in[1]) ^ multd(in[2]) ^ mult9(in[3]); - out[1] = mult9(in[0]) ^ multe(in[1]) ^ multb(in[2]) ^ multd(in[3]); - out[2] = multd(in[0]) ^ mult9(in[1]) ^ multe(in[2]) ^ multb(in[3]); - out[3] = multb(in[0]) ^ multd(in[1]) ^ mult9(in[2]) ^ multe(in[3]); -} - -static inline void inv_mix_columns(uint8_t *s) -{ - uint8_t t[Nb*Nk]; - - mult_row_column(t, s); - mult_row_column(&t[Nb], s+Nb); - mult_row_column(&t[2*Nb], s+(2*Nb)); - mult_row_column(&t[3*Nb], s+(3*Nb)); - (void)_copy(s, sizeof(t), t, sizeof(t)); -} - -static inline void add_round_key(uint8_t *s, const unsigned int *k) -{ - s[0] ^= (uint8_t)(k[0] >> 24); s[1] ^= (uint8_t)(k[0] >> 16); - s[2] ^= (uint8_t)(k[0] >> 8); s[3] ^= (uint8_t)(k[0]); - s[4] ^= (uint8_t)(k[1] >> 24); s[5] ^= (uint8_t)(k[1] >> 16); - s[6] ^= (uint8_t)(k[1] >> 8); s[7] ^= (uint8_t)(k[1]); - s[8] ^= (uint8_t)(k[2] >> 24); s[9] ^= (uint8_t)(k[2] >> 16); - s[10] ^= (uint8_t)(k[2] >> 8); s[11] ^= (uint8_t)(k[2]); - s[12] ^= (uint8_t)(k[3] >> 24); s[13] ^= (uint8_t)(k[3] >> 16); - s[14] ^= (uint8_t)(k[3] >> 8); s[15] ^= (uint8_t)(k[3]); -} - -static inline void inv_sub_bytes(uint8_t *s) -{ - unsigned int i; - - for (i = 0; i < (Nb*Nk); ++i) { - s[i] = inv_sbox[s[i]]; - } -} - -/* - * This inv_shift_rows also implements the matrix flip required for - * inv_mix_columns, but performs it here to reduce the number of memory - * operations. - */ -static inline void inv_shift_rows(uint8_t *s) -{ - uint8_t t[Nb*Nk]; - - t[0] = s[0]; t[1] = s[13]; t[2] = s[10]; t[3] = s[7]; - t[4] = s[4]; t[5] = s[1]; t[6] = s[14]; t[7] = s[11]; - t[8] = s[8]; t[9] = s[5]; t[10] = s[2]; t[11] = s[15]; - t[12] = s[12]; t[13] = s[9]; t[14] = s[6]; t[15] = s[3]; - (void)_copy(s, sizeof(t), t, sizeof(t)); -} - -int tc_aes_decrypt(uint8_t *out, const uint8_t *in, const TCAesKeySched_t s) -{ - uint8_t state[Nk*Nb]; - unsigned int i; - - if (out == (uint8_t *) 0) { - return TC_CRYPTO_FAIL; - } else if (in == (const uint8_t *) 0) { - return TC_CRYPTO_FAIL; - } else if (s == (TCAesKeySched_t) 0) { - return TC_CRYPTO_FAIL; - } - - (void)_copy(state, sizeof(state), in, sizeof(state)); - - add_round_key(state, s->words + Nb*Nr); - - for (i = Nr - 1; i > 0; --i) { - inv_shift_rows(state); - inv_sub_bytes(state); - add_round_key(state, s->words + Nb*i); - inv_mix_columns(state); - } - - inv_shift_rows(state); - inv_sub_bytes(state); - add_round_key(state, s->words); - - (void)_copy(out, sizeof(state), state, sizeof(state)); - - /*zeroing out the state buffer */ - _set(state, TC_ZERO_BYTE, sizeof(state)); - - - return TC_CRYPTO_SUCCESS; -} diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/aes_encrypt.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/aes_encrypt.c deleted file mode 100644 index bdc434bce..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/aes_encrypt.c +++ /dev/null @@ -1,191 +0,0 @@ -/* aes_encrypt.c - TinyCrypt implementation of AES encryption procedure */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "../include/tinycrypt/aes.h" -#include "../include/tinycrypt/utils.h" -#include "../include/tinycrypt/constants.h" - -static const uint8_t sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, - 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, - 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, - 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, - 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, - 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, - 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, - 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, - 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, - 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, - 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, - 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, - 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, - 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, - 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, - 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, - 0xb0, 0x54, 0xbb, 0x16 -}; - -static inline unsigned int rotword(unsigned int a) -{ - return (((a) >> 24)|((a) << 8)); -} - -#define subbyte(a, o)(sbox[((a) >> (o))&0xff] << (o)) -#define subword(a)(subbyte(a, 24)|subbyte(a, 16)|subbyte(a, 8)|subbyte(a, 0)) - -int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k) -{ - const unsigned int rconst[11] = { - 0x00000000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, - 0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000 - }; - unsigned int i; - unsigned int t; - - if (s == (TCAesKeySched_t) 0) { - return TC_CRYPTO_FAIL; - } else if (k == (const uint8_t *) 0) { - return TC_CRYPTO_FAIL; - } - - for (i = 0; i < Nk; ++i) { - s->words[i] = (k[Nb*i]<<24) | (k[Nb*i+1]<<16) | - (k[Nb*i+2]<<8) | (k[Nb*i+3]); - } - - for (; i < (Nb * (Nr + 1)); ++i) { - t = s->words[i-1]; - if ((i % Nk) == 0) { - t = subword(rotword(t)) ^ rconst[i/Nk]; - } - s->words[i] = s->words[i-Nk] ^ t; - } - - return TC_CRYPTO_SUCCESS; -} - -static inline void add_round_key(uint8_t *s, const unsigned int *k) -{ - s[0] ^= (uint8_t)(k[0] >> 24); s[1] ^= (uint8_t)(k[0] >> 16); - s[2] ^= (uint8_t)(k[0] >> 8); s[3] ^= (uint8_t)(k[0]); - s[4] ^= (uint8_t)(k[1] >> 24); s[5] ^= (uint8_t)(k[1] >> 16); - s[6] ^= (uint8_t)(k[1] >> 8); s[7] ^= (uint8_t)(k[1]); - s[8] ^= (uint8_t)(k[2] >> 24); s[9] ^= (uint8_t)(k[2] >> 16); - s[10] ^= (uint8_t)(k[2] >> 8); s[11] ^= (uint8_t)(k[2]); - s[12] ^= (uint8_t)(k[3] >> 24); s[13] ^= (uint8_t)(k[3] >> 16); - s[14] ^= (uint8_t)(k[3] >> 8); s[15] ^= (uint8_t)(k[3]); -} - -static inline void sub_bytes(uint8_t *s) -{ - unsigned int i; - - for (i = 0; i < (Nb * Nk); ++i) { - s[i] = sbox[s[i]]; - } -} - -#define triple(a)(_double_byte(a)^(a)) - -static inline void mult_row_column(uint8_t *out, const uint8_t *in) -{ - out[0] = _double_byte(in[0]) ^ triple(in[1]) ^ in[2] ^ in[3]; - out[1] = in[0] ^ _double_byte(in[1]) ^ triple(in[2]) ^ in[3]; - out[2] = in[0] ^ in[1] ^ _double_byte(in[2]) ^ triple(in[3]); - out[3] = triple(in[0]) ^ in[1] ^ in[2] ^ _double_byte(in[3]); -} - -static inline void mix_columns(uint8_t *s) -{ - uint8_t t[Nb*Nk]; - - mult_row_column(t, s); - mult_row_column(&t[Nb], s+Nb); - mult_row_column(&t[2 * Nb], s + (2 * Nb)); - mult_row_column(&t[3 * Nb], s + (3 * Nb)); - (void) _copy(s, sizeof(t), t, sizeof(t)); -} - -/* - * This shift_rows also implements the matrix flip required for mix_columns, but - * performs it here to reduce the number of memory operations. - */ -static inline void shift_rows(uint8_t *s) -{ - uint8_t t[Nb * Nk]; - - t[0] = s[0]; t[1] = s[5]; t[2] = s[10]; t[3] = s[15]; - t[4] = s[4]; t[5] = s[9]; t[6] = s[14]; t[7] = s[3]; - t[8] = s[8]; t[9] = s[13]; t[10] = s[2]; t[11] = s[7]; - t[12] = s[12]; t[13] = s[1]; t[14] = s[6]; t[15] = s[11]; - (void) _copy(s, sizeof(t), t, sizeof(t)); -} - -int tc_aes_encrypt(uint8_t *out, const uint8_t *in, const TCAesKeySched_t s) -{ - uint8_t state[Nk*Nb]; - unsigned int i; - - if (out == (uint8_t *) 0) { - return TC_CRYPTO_FAIL; - } else if (in == (const uint8_t *) 0) { - return TC_CRYPTO_FAIL; - } else if (s == (TCAesKeySched_t) 0) { - return TC_CRYPTO_FAIL; - } - - (void)_copy(state, sizeof(state), in, sizeof(state)); - add_round_key(state, s->words); - - for (i = 0; i < (Nr - 1); ++i) { - sub_bytes(state); - shift_rows(state); - mix_columns(state); - add_round_key(state, s->words + Nb*(i+1)); - } - - sub_bytes(state); - shift_rows(state); - add_round_key(state, s->words + Nb*(i+1)); - - (void)_copy(out, sizeof(state), state, sizeof(state)); - - /* zeroing out the state buffer */ - _set(state, TC_ZERO_BYTE, sizeof(state)); - - return TC_CRYPTO_SUCCESS; -} diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/cbc_mode.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/cbc_mode.c deleted file mode 100644 index b743878a9..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/cbc_mode.c +++ /dev/null @@ -1,114 +0,0 @@ -/* cbc_mode.c - TinyCrypt implementation of CBC mode encryption & decryption */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "../include/tinycrypt/cbc_mode.h" -#include "../include/tinycrypt/constants.h" -#include "../include/tinycrypt/utils.h" - -int tc_cbc_mode_encrypt(uint8_t *out, unsigned int outlen, const uint8_t *in, - unsigned int inlen, const uint8_t *iv, - const TCAesKeySched_t sched) -{ - - uint8_t buffer[TC_AES_BLOCK_SIZE]; - unsigned int n, m; - - /* input sanity check: */ - if (out == (uint8_t *) 0 || - in == (const uint8_t *) 0 || - sched == (TCAesKeySched_t) 0 || - inlen == 0 || - outlen == 0 || - (inlen % TC_AES_BLOCK_SIZE) != 0 || - (outlen % TC_AES_BLOCK_SIZE) != 0 || - outlen != inlen + TC_AES_BLOCK_SIZE) { - return TC_CRYPTO_FAIL; - } - - /* copy iv to the buffer */ - (void)_copy(buffer, TC_AES_BLOCK_SIZE, iv, TC_AES_BLOCK_SIZE); - /* copy iv to the output buffer */ - (void)_copy(out, TC_AES_BLOCK_SIZE, iv, TC_AES_BLOCK_SIZE); - out += TC_AES_BLOCK_SIZE; - - for (n = m = 0; n < inlen; ++n) { - buffer[m++] ^= *in++; - if (m == TC_AES_BLOCK_SIZE) { - (void)tc_aes_encrypt(buffer, buffer, sched); - (void)_copy(out, TC_AES_BLOCK_SIZE, - buffer, TC_AES_BLOCK_SIZE); - out += TC_AES_BLOCK_SIZE; - m = 0; - } - } - - return TC_CRYPTO_SUCCESS; -} - -int tc_cbc_mode_decrypt(uint8_t *out, unsigned int outlen, const uint8_t *in, - unsigned int inlen, const uint8_t *iv, - const TCAesKeySched_t sched) -{ - - uint8_t buffer[TC_AES_BLOCK_SIZE]; - const uint8_t *p; - unsigned int n, m; - - /* sanity check the inputs */ - if (out == (uint8_t *) 0 || - in == (const uint8_t *) 0 || - sched == (TCAesKeySched_t) 0 || - inlen == 0 || - outlen == 0 || - (inlen % TC_AES_BLOCK_SIZE) != 0 || - (outlen % TC_AES_BLOCK_SIZE) != 0 || - outlen != inlen - TC_AES_BLOCK_SIZE) { - return TC_CRYPTO_FAIL; - } - - /* - * Note that in == iv + ciphertext, i.e. the iv and the ciphertext are - * contiguous. This allows for a very efficient decryption algorithm - * that would not otherwise be possible. - */ - p = iv; - for (n = m = 0; n < inlen; ++n) { - if ((n % TC_AES_BLOCK_SIZE) == 0) { - (void)tc_aes_decrypt(buffer, in, sched); - in += TC_AES_BLOCK_SIZE; - m = 0; - } - *out++ = buffer[m++] ^ *p++; - } - - return TC_CRYPTO_SUCCESS; -} diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ccm_mode.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ccm_mode.c deleted file mode 100644 index 598531252..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ccm_mode.c +++ /dev/null @@ -1,266 +0,0 @@ -/* ccm_mode.c - TinyCrypt implementation of CCM mode */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "../include/tinycrypt/ccm_mode.h" -#include "../include/tinycrypt/constants.h" -#include "../include/tinycrypt/utils.h" - -#include - -int tc_ccm_config(TCCcmMode_t c, TCAesKeySched_t sched, uint8_t *nonce, - unsigned int nlen, unsigned int mlen) -{ - - /* input sanity check: */ - if (c == (TCCcmMode_t) 0 || - sched == (TCAesKeySched_t) 0 || - nonce == (uint8_t *) 0) { - return TC_CRYPTO_FAIL; - } else if (nlen != 13) { - return TC_CRYPTO_FAIL; /* The allowed nonce size is: 13. See documentation.*/ - } else if ((mlen < 4) || (mlen > 16) || (mlen & 1)) { - return TC_CRYPTO_FAIL; /* The allowed mac sizes are: 4, 6, 8, 10, 12, 14, 16.*/ - } - - c->mlen = mlen; - c->sched = sched; - c->nonce = nonce; - - return TC_CRYPTO_SUCCESS; -} - -/** - * Variation of CBC-MAC mode used in CCM. - */ -static void ccm_cbc_mac(uint8_t *T, const uint8_t *data, unsigned int dlen, - unsigned int flag, TCAesKeySched_t sched) -{ - - unsigned int i; - - if (flag > 0) { - T[0] ^= (uint8_t)(dlen >> 8); - T[1] ^= (uint8_t)(dlen); - dlen += 2; i = 2; - } else { - i = 0; - } - - while (i < dlen) { - T[i++ % (Nb * Nk)] ^= *data++; - if (((i % (Nb * Nk)) == 0) || dlen == i) { - (void) tc_aes_encrypt(T, T, sched); - } - } -} - -/** - * Variation of CTR mode used in CCM. - * The CTR mode used by CCM is slightly different than the conventional CTR - * mode (the counter is increased before encryption, instead of after - * encryption). Besides, it is assumed that the counter is stored in the last - * 2 bytes of the nonce. - */ -static int ccm_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in, - unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched) -{ - - uint8_t buffer[TC_AES_BLOCK_SIZE]; - uint8_t nonce[TC_AES_BLOCK_SIZE]; - uint16_t block_num; - unsigned int i; - - /* input sanity check: */ - if (out == (uint8_t *) 0 || - in == (uint8_t *) 0 || - ctr == (uint8_t *) 0 || - sched == (TCAesKeySched_t) 0 || - inlen == 0 || - outlen == 0 || - outlen != inlen) { - return TC_CRYPTO_FAIL; - } - - /* copy the counter to the nonce */ - (void) _copy(nonce, sizeof(nonce), ctr, sizeof(nonce)); - - /* select the last 2 bytes of the nonce to be incremented */ - block_num = (uint16_t) ((nonce[14] << 8)|(nonce[15])); - for (i = 0; i < inlen; ++i) { - if ((i % (TC_AES_BLOCK_SIZE)) == 0) { - block_num++; - nonce[14] = (uint8_t)(block_num >> 8); - nonce[15] = (uint8_t)(block_num); - if (!tc_aes_encrypt(buffer, nonce, sched)) { - return TC_CRYPTO_FAIL; - } - } - /* update the output */ - *out++ = buffer[i % (TC_AES_BLOCK_SIZE)] ^ *in++; - } - - /* update the counter */ - ctr[14] = nonce[14]; ctr[15] = nonce[15]; - - return TC_CRYPTO_SUCCESS; -} - -int tc_ccm_generation_encryption(uint8_t *out, unsigned int olen, - const uint8_t *associated_data, - unsigned int alen, const uint8_t *payload, - unsigned int plen, TCCcmMode_t c) -{ - - /* input sanity check: */ - if ((out == (uint8_t *) 0) || - (c == (TCCcmMode_t) 0) || - ((plen > 0) && (payload == (uint8_t *) 0)) || - ((alen > 0) && (associated_data == (uint8_t *) 0)) || - (alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */ - (plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */ - (olen < (plen + c->mlen))) { /* invalid output buffer size */ - return TC_CRYPTO_FAIL; - } - - uint8_t b[Nb * Nk]; - uint8_t tag[Nb * Nk]; - unsigned int i; - - /* GENERATING THE AUTHENTICATION TAG: */ - - /* formatting the sequence b for authentication: */ - b[0] = ((alen > 0) ? 0x40:0) | (((c->mlen - 2) / 2 << 3)) | (1); - for (i = 1; i <= 13; ++i) { - b[i] = c->nonce[i - 1]; - } - b[14] = (uint8_t)(plen >> 8); - b[15] = (uint8_t)(plen); - - /* computing the authentication tag using cbc-mac: */ - (void) tc_aes_encrypt(tag, b, c->sched); - if (alen > 0) { - ccm_cbc_mac(tag, associated_data, alen, 1, c->sched); - } - if (plen > 0) { - ccm_cbc_mac(tag, payload, plen, 0, c->sched); - } - - /* ENCRYPTION: */ - - /* formatting the sequence b for encryption: */ - b[0] = 1; /* q - 1 = 2 - 1 = 1 */ - b[14] = b[15] = TC_ZERO_BYTE; - - /* encrypting payload using ctr mode: */ - ccm_ctr_mode(out, plen, payload, plen, b, c->sched); - - b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter for ctr_mode (0):*/ - - /* encrypting b and adding the tag to the output: */ - (void) tc_aes_encrypt(b, b, c->sched); - out += plen; - for (i = 0; i < c->mlen; ++i) { - *out++ = tag[i] ^ b[i]; - } - - return TC_CRYPTO_SUCCESS; -} - -int tc_ccm_decryption_verification(uint8_t *out, unsigned int olen, - const uint8_t *associated_data, - unsigned int alen, const uint8_t *payload, - unsigned int plen, TCCcmMode_t c) -{ - - /* input sanity check: */ - if ((out == (uint8_t *) 0) || - (c == (TCCcmMode_t) 0) || - ((plen > 0) && (payload == (uint8_t *) 0)) || - ((alen > 0) && (associated_data == (uint8_t *) 0)) || - (alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */ - (plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */ - (olen < plen - c->mlen)) { /* invalid output buffer size */ - return TC_CRYPTO_FAIL; - } - - uint8_t b[Nb * Nk]; - uint8_t tag[Nb * Nk]; - unsigned int i; - - /* DECRYPTION: */ - - /* formatting the sequence b for decryption: */ - b[0] = 1; /* q - 1 = 2 - 1 = 1 */ - for (i = 1; i < 14; ++i) { - b[i] = c->nonce[i - 1]; - } - b[14] = b[15] = TC_ZERO_BYTE; /* initial counter value is 0 */ - - /* decrypting payload using ctr mode: */ - ccm_ctr_mode(out, plen - c->mlen, payload, plen - c->mlen, b, c->sched); - - b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter value (0) */ - - /* encrypting b and restoring the tag from input: */ - (void) tc_aes_encrypt(b, b, c->sched); - for (i = 0; i < c->mlen; ++i) { - tag[i] = *(payload + plen - c->mlen + i) ^ b[i]; - } - - /* VERIFYING THE AUTHENTICATION TAG: */ - - /* formatting the sequence b for authentication: */ - b[0] = ((alen > 0) ? 0x40:0)|(((c->mlen - 2) / 2 << 3)) | (1); - for (i = 1; i < 14; ++i) { - b[i] = c->nonce[i - 1]; - } - b[14] = (uint8_t)((plen - c->mlen) >> 8); - b[15] = (uint8_t)(plen - c->mlen); - - /* computing the authentication tag using cbc-mac: */ - (void) tc_aes_encrypt(b, b, c->sched); - if (alen > 0) { - ccm_cbc_mac(b, associated_data, alen, 1, c->sched); - } - if (plen > 0) { - ccm_cbc_mac(b, out, plen - c->mlen, 0, c->sched); - } - - /* comparing the received tag and the computed one: */ - if (_compare(b, tag, c->mlen) == 0) { - return TC_CRYPTO_SUCCESS; - } else { - /* erase the decrypted buffer in case of mac validation failure: */ - _set(out, 0, plen - c->mlen); - return TC_CRYPTO_FAIL; - } -} diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/cmac_mode.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/cmac_mode.c deleted file mode 100644 index dff28cf03..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/cmac_mode.c +++ /dev/null @@ -1,254 +0,0 @@ -/* cmac_mode.c - TinyCrypt CMAC mode implementation */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "../include/tinycrypt/aes.h" -#include "../include/tinycrypt/cmac_mode.h" -#include "../include/tinycrypt/constants.h" -#include "../include/tinycrypt/utils.h" - -/* max number of calls until change the key (2^48).*/ -const static uint64_t MAX_CALLS = ((uint64_t)1 << 48); - -/* - * gf_wrap -- In our implementation, GF(2^128) is represented as a 16 byte - * array with byte 0 the most significant and byte 15 the least significant. - * High bit carry reduction is based on the primitive polynomial - * - * X^128 + X^7 + X^2 + X + 1, - * - * which leads to the reduction formula X^128 = X^7 + X^2 + X + 1. Indeed, - * since 0 = (X^128 + X^7 + X^2 + 1) mod (X^128 + X^7 + X^2 + X + 1) and since - * addition of polynomials with coefficients in Z/Z(2) is just XOR, we can - * add X^128 to both sides to get - * - * X^128 = (X^7 + X^2 + X + 1) mod (X^128 + X^7 + X^2 + X + 1) - * - * and the coefficients of the polynomial on the right hand side form the - * string 1000 0111 = 0x87, which is the value of gf_wrap. - * - * This gets used in the following way. Doubling in GF(2^128) is just a left - * shift by 1 bit, except when the most significant bit is 1. In the latter - * case, the relation X^128 = X^7 + X^2 + X + 1 says that the high order bit - * that overflows beyond 128 bits can be replaced by addition of - * X^7 + X^2 + X + 1 <--> 0x87 to the low order 128 bits. Since addition - * in GF(2^128) is represented by XOR, we therefore only have to XOR 0x87 - * into the low order byte after a left shift when the starting high order - * bit is 1. - */ -const unsigned char gf_wrap = 0x87; - -/* - * assumes: out != NULL and points to a GF(2^n) value to receive the - * doubled value; - * in != NULL and points to a 16 byte GF(2^n) value - * to double; - * the in and out buffers do not overlap. - * effects: doubles the GF(2^n) value pointed to by "in" and places - * the result in the GF(2^n) value pointed to by "out." - */ -void gf_double(uint8_t *out, uint8_t *in) -{ - - /* start with low order byte */ - uint8_t *x = in + (TC_AES_BLOCK_SIZE - 1); - - /* if msb == 1, we need to add the gf_wrap value, otherwise add 0 */ - uint8_t carry = (in[0] >> 7) ? gf_wrap : 0; - - out += (TC_AES_BLOCK_SIZE - 1); - for (;;) { - *out-- = (*x << 1) ^ carry; - if (x == in) { - break; - } - carry = *x-- >> 7; - } -} - -int tc_cmac_setup(TCCmacState_t s, const uint8_t *key, TCAesKeySched_t sched) -{ - - /* input sanity check: */ - if (s == (TCCmacState_t) 0 || - key == (const uint8_t *) 0) { - return TC_CRYPTO_FAIL; - } - - /* put s into a known state */ - _set(s, 0, sizeof(*s)); - s->sched = sched; - - /* configure the encryption key used by the underlying block cipher */ - tc_aes128_set_encrypt_key(s->sched, key); - - /* compute s->K1 and s->K2 from s->iv using s->keyid */ - _set(s->iv, 0, TC_AES_BLOCK_SIZE); - tc_aes_encrypt(s->iv, s->iv, s->sched); - gf_double (s->K1, s->iv); - gf_double (s->K2, s->K1); - - /* reset s->iv to 0 in case someone wants to compute now */ - tc_cmac_init(s); - - return TC_CRYPTO_SUCCESS; -} - -int tc_cmac_erase(TCCmacState_t s) -{ - if (s == (TCCmacState_t) 0) { - return TC_CRYPTO_FAIL; - } - - /* destroy the current state */ - _set(s, 0, sizeof(*s)); - - return TC_CRYPTO_SUCCESS; -} - -int tc_cmac_init(TCCmacState_t s) -{ - /* input sanity check: */ - if (s == (TCCmacState_t) 0) { - return TC_CRYPTO_FAIL; - } - - /* CMAC starts with an all zero initialization vector */ - _set(s->iv, 0, TC_AES_BLOCK_SIZE); - - /* and the leftover buffer is empty */ - _set(s->leftover, 0, TC_AES_BLOCK_SIZE); - s->leftover_offset = 0; - - /* Set countdown to max number of calls allowed before re-keying: */ - s->countdown = MAX_CALLS; - - return TC_CRYPTO_SUCCESS; -} - -int tc_cmac_update(TCCmacState_t s, const uint8_t *data, size_t data_length) -{ - unsigned int i; - - /* input sanity check: */ - if (s == (TCCmacState_t) 0) { - return TC_CRYPTO_FAIL; - } - if (data_length == 0) { - return TC_CRYPTO_SUCCESS; - } - if (data == (const uint8_t *) 0) { - return TC_CRYPTO_FAIL; - } - - if (s->countdown == 0) { - return TC_CRYPTO_FAIL; - } - - s->countdown--; - - if (s->leftover_offset > 0) { - /* last data added to s didn't end on a TC_AES_BLOCK_SIZE byte boundary */ - size_t remaining_space = TC_AES_BLOCK_SIZE - s->leftover_offset; - - if (data_length < remaining_space) { - /* still not enough data to encrypt this time either */ - _copy(&s->leftover[s->leftover_offset], data_length, data, data_length); - s->leftover_offset += data_length; - return TC_CRYPTO_SUCCESS; - } - /* leftover block is now full; encrypt it first */ - _copy(&s->leftover[s->leftover_offset], - remaining_space, - data, - remaining_space); - data_length -= remaining_space; - data += remaining_space; - s->leftover_offset = 0; - - for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) { - s->iv[i] ^= s->leftover[i]; - } - tc_aes_encrypt(s->iv, s->iv, s->sched); - } - - /* CBC encrypt each (except the last) of the data blocks */ - while (data_length > TC_AES_BLOCK_SIZE) { - for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) { - s->iv[i] ^= data[i]; - } - tc_aes_encrypt(s->iv, s->iv, s->sched); - data += TC_AES_BLOCK_SIZE; - data_length -= TC_AES_BLOCK_SIZE; - } - - if (data_length > 0) { - /* save leftover data for next time */ - _copy(s->leftover, data_length, data, data_length); - s->leftover_offset = data_length; - } - - return TC_CRYPTO_SUCCESS; -} - -int tc_cmac_final(uint8_t *tag, TCCmacState_t s) -{ - uint8_t *k; - unsigned int i; - - /* input sanity check: */ - if (tag == (uint8_t *) 0 || - s == (TCCmacState_t) 0) { - return TC_CRYPTO_FAIL; - } - - if (s->leftover_offset == TC_AES_BLOCK_SIZE) { - /* the last message block is a full-sized block */ - k = (uint8_t *) s->K1; - } else { - /* the final message block is not a full-sized block */ - size_t remaining = TC_AES_BLOCK_SIZE - s->leftover_offset; - - _set(&s->leftover[s->leftover_offset], 0, remaining); - s->leftover[s->leftover_offset] = TC_CMAC_PADDING; - k = (uint8_t *) s->K2; - } - for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) { - s->iv[i] ^= s->leftover[i] ^ k[i]; - } - - tc_aes_encrypt(tag, s->iv, s->sched); - - /* erasing state: */ - tc_cmac_erase(s); - - return TC_CRYPTO_SUCCESS; -} diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ctr_mode.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ctr_mode.c deleted file mode 100644 index 6653afc52..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ctr_mode.c +++ /dev/null @@ -1,85 +0,0 @@ -/* ctr_mode.c - TinyCrypt CTR mode implementation */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "../include/tinycrypt/constants.h" -#include "../include/tinycrypt/ctr_mode.h" -#include "../include/tinycrypt/utils.h" - -int tc_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in, - unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched) -{ - - uint8_t buffer[TC_AES_BLOCK_SIZE]; - uint8_t nonce[TC_AES_BLOCK_SIZE]; - unsigned int block_num; - unsigned int i; - - /* input sanity check: */ - if (out == (uint8_t *) 0 || - in == (uint8_t *) 0 || - ctr == (uint8_t *) 0 || - sched == (TCAesKeySched_t) 0 || - inlen == 0 || - outlen == 0 || - outlen != inlen) { - return TC_CRYPTO_FAIL; - } - - /* copy the ctr to the nonce */ - (void)_copy(nonce, sizeof(nonce), ctr, sizeof(nonce)); - - /* select the last 4 bytes of the nonce to be incremented */ - block_num = (nonce[12] << 24) | (nonce[13] << 16) | - (nonce[14] << 8) | (nonce[15]); - for (i = 0; i < inlen; ++i) { - if ((i % (TC_AES_BLOCK_SIZE)) == 0) { - /* encrypt data using the current nonce */ - if (tc_aes_encrypt(buffer, nonce, sched)) { - block_num++; - nonce[12] = (uint8_t)(block_num >> 24); - nonce[13] = (uint8_t)(block_num >> 16); - nonce[14] = (uint8_t)(block_num >> 8); - nonce[15] = (uint8_t)(block_num); - } else { - return TC_CRYPTO_FAIL; - } - } - /* update the output */ - *out++ = buffer[i%(TC_AES_BLOCK_SIZE)] ^ *in++; - } - - /* update the counter */ - ctr[12] = nonce[12]; ctr[13] = nonce[13]; - ctr[14] = nonce[14]; ctr[15] = nonce[15]; - - return TC_CRYPTO_SUCCESS; -} diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ctr_prng.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ctr_prng.c deleted file mode 100644 index f908932e2..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ctr_prng.c +++ /dev/null @@ -1,283 +0,0 @@ -/* ctr_prng.c - TinyCrypt implementation of CTR-PRNG */ - -/* - * Copyright (c) 2016, Chris Morrison - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "../include/tinycrypt/ctr_prng.h" -#include "../include/tinycrypt/utils.h" -#include "../include/tinycrypt/constants.h" -#include - -/* - * This PRNG is based on the CTR_DRBG described in Recommendation for Random - * Number Generation Using Deterministic Random Bit Generators, - * NIST SP 800-90A Rev. 1. - * - * Annotations to particular steps (e.g. 10.2.1.2 Step 1) refer to the steps - * described in that document. - * - */ - -/** - * @brief Array incrementer - * Treats the supplied array as one contiguous number (MSB in arr[0]), and - * increments it by one - * @return none - * @param arr IN/OUT -- array to be incremented - * @param len IN -- size of arr in bytes - */ -static void arrInc(uint8_t arr[], unsigned int len) -{ - unsigned int i; - if (0 != arr) { - for (i = len; i > 0U; i--) { - if (++arr[i-1] != 0U) { - break; - } - } - } -} - -/** - * @brief CTR PRNG update - * Updates the internal state of supplied the CTR PRNG context - * increments it by one - * @return none - * @note Assumes: providedData is (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes long - * @param ctx IN/OUT -- CTR PRNG state - * @param providedData IN -- data used when updating the internal state - */ -static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const * const providedData) -{ - if (0 != ctx) { - /* 10.2.1.2 step 1 */ - uint8_t temp[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE]; - unsigned int len = 0U; - - /* 10.2.1.2 step 2 */ - while (len < sizeof temp) { - unsigned int blocklen = sizeof(temp) - len; - uint8_t output_block[TC_AES_BLOCK_SIZE]; - - /* 10.2.1.2 step 2.1 */ - arrInc(ctx->V, sizeof ctx->V); - - /* 10.2.1.2 step 2.2 */ - if (blocklen > TC_AES_BLOCK_SIZE) { - blocklen = TC_AES_BLOCK_SIZE; - } - (void)tc_aes_encrypt(output_block, ctx->V, &ctx->key); - - /* 10.2.1.2 step 2.3/step 3 */ - memcpy(&(temp[len]), output_block, blocklen); - - len += blocklen; - } - - /* 10.2.1.2 step 4 */ - if (0 != providedData) { - unsigned int i; - for (i = 0U; i < sizeof temp; i++) { - temp[i] ^= providedData[i]; - } - } - - /* 10.2.1.2 step 5 */ - (void)tc_aes128_set_encrypt_key(&ctx->key, temp); - - /* 10.2.1.2 step 6 */ - memcpy(ctx->V, &(temp[TC_AES_KEY_SIZE]), TC_AES_BLOCK_SIZE); - } -} - -int tc_ctr_prng_init(TCCtrPrng_t * const ctx, - uint8_t const * const entropy, - unsigned int entropyLen, - uint8_t const * const personalization, - unsigned int pLen) -{ - int result = TC_CRYPTO_FAIL; - unsigned int i; - uint8_t personalization_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U}; - uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE]; - uint8_t zeroArr[TC_AES_BLOCK_SIZE] = {0U}; - - if (0 != personalization) { - /* 10.2.1.3.1 step 1 */ - unsigned int len = pLen; - if (len > sizeof personalization_buf) { - len = sizeof personalization_buf; - } - - /* 10.2.1.3.1 step 2 */ - memcpy(personalization_buf, personalization, len); - } - - if ((0 != ctx) && (0 != entropy) && (entropyLen >= sizeof seed_material)) { - /* 10.2.1.3.1 step 3 */ - memcpy(seed_material, entropy, sizeof seed_material); - for (i = 0U; i < sizeof seed_material; i++) { - seed_material[i] ^= personalization_buf[i]; - } - - /* 10.2.1.3.1 step 4 */ - (void)tc_aes128_set_encrypt_key(&ctx->key, zeroArr); - - /* 10.2.1.3.1 step 5 */ - memset(ctx->V, 0x00, sizeof ctx->V); - - /* 10.2.1.3.1 step 6 */ - tc_ctr_prng_update(ctx, seed_material); - - /* 10.2.1.3.1 step 7 */ - ctx->reseedCount = 1U; - - result = TC_CRYPTO_SUCCESS; - } - return result; -} - -int tc_ctr_prng_reseed(TCCtrPrng_t * const ctx, - uint8_t const * const entropy, - unsigned int entropyLen, - uint8_t const * const additional_input, - unsigned int additionallen) -{ - unsigned int i; - int result = TC_CRYPTO_FAIL; - uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U}; - uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE]; - - if (0 != additional_input) { - /* 10.2.1.4.1 step 1 */ - unsigned int len = additionallen; - if (len > sizeof additional_input_buf) { - len = sizeof additional_input_buf; - } - - /* 10.2.1.4.1 step 2 */ - memcpy(additional_input_buf, additional_input, len); - } - - unsigned int seedlen = (unsigned int)TC_AES_KEY_SIZE + (unsigned int)TC_AES_BLOCK_SIZE; - if ((0 != ctx) && (entropyLen >= seedlen)) { - /* 10.2.1.4.1 step 3 */ - memcpy(seed_material, entropy, sizeof seed_material); - for (i = 0U; i < sizeof seed_material; i++) { - seed_material[i] ^= additional_input_buf[i]; - } - - /* 10.2.1.4.1 step 4 */ - tc_ctr_prng_update(ctx, seed_material); - - /* 10.2.1.4.1 step 5 */ - ctx->reseedCount = 1U; - - result = TC_CRYPTO_SUCCESS; - } - return result; -} - -int tc_ctr_prng_generate(TCCtrPrng_t * const ctx, - uint8_t const * const additional_input, - unsigned int additionallen, - uint8_t * const out, - unsigned int outlen) -{ - /* 2^48 - see section 10.2.1 */ - static const uint64_t MAX_REQS_BEFORE_RESEED = 0x1000000000000ULL; - - /* 2^19 bits - see section 10.2.1 */ - static const unsigned int MAX_BYTES_PER_REQ = 65536U; - - unsigned int result = TC_CRYPTO_FAIL; - - if ((0 != ctx) && (0 != out) && (outlen < MAX_BYTES_PER_REQ)) { - /* 10.2.1.5.1 step 1 */ - if (ctx->reseedCount > MAX_REQS_BEFORE_RESEED) { - result = TC_CTR_PRNG_RESEED_REQ; - } else { - uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U}; - if (0 != additional_input) { - /* 10.2.1.5.1 step 2 */ - unsigned int len = additionallen; - if (len > sizeof additional_input_buf) { - len = sizeof additional_input_buf; - } - memcpy(additional_input_buf, additional_input, len); - tc_ctr_prng_update(ctx, additional_input_buf); - } - - /* 10.2.1.5.1 step 3 - implicit */ - - /* 10.2.1.5.1 step 4 */ - unsigned int len = 0U; - while (len < outlen) { - unsigned int blocklen = outlen - len; - uint8_t output_block[TC_AES_BLOCK_SIZE]; - - /* 10.2.1.5.1 step 4.1 */ - arrInc(ctx->V, sizeof ctx->V); - - /* 10.2.1.5.1 step 4.2 */ - (void)tc_aes_encrypt(output_block, ctx->V, &ctx->key); - - /* 10.2.1.5.1 step 4.3/step 5 */ - if (blocklen > TC_AES_BLOCK_SIZE) { - blocklen = TC_AES_BLOCK_SIZE; - } - memcpy(&(out[len]), output_block, blocklen); - - len += blocklen; - } - - /* 10.2.1.5.1 step 6 */ - tc_ctr_prng_update(ctx, additional_input_buf); - - /* 10.2.1.5.1 step 7 */ - ctx->reseedCount++; - - /* 10.2.1.5.1 step 8 */ - result = TC_CRYPTO_SUCCESS; - } - } - - return result; -} - -void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx) -{ - if (0 != ctx) { - memset(ctx->key.words, 0x00, sizeof ctx->key.words); - memset(ctx->V, 0x00, sizeof ctx->V); - ctx->reseedCount = 0U; - } -} - - - - diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc.c deleted file mode 100644 index e7fce278d..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc.c +++ /dev/null @@ -1,942 +0,0 @@ -/* ecc.c - TinyCrypt implementation of common ECC functions */ - -/* - * Copyright (c) 2014, Kenneth MacKay - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "../include/tinycrypt/ecc.h" -#include "../include/tinycrypt/ecc_platform_specific.h" -#include - -/* IMPORTANT: Make sure a cryptographically-secure PRNG is set and the platform - * has access to enough entropy in order to feed the PRNG regularly. */ -#if default_RNG_defined -static uECC_RNG_Function g_rng_function = &default_CSPRNG; -#else -static uECC_RNG_Function g_rng_function = 0; -#endif - -void uECC_set_rng(uECC_RNG_Function rng_function) -{ - g_rng_function = rng_function; -} - -uECC_RNG_Function uECC_get_rng(void) -{ - return g_rng_function; -} - -int uECC_curve_private_key_size(uECC_Curve curve) -{ - return BITS_TO_BYTES(curve->num_n_bits); -} - -int uECC_curve_public_key_size(uECC_Curve curve) -{ - return 2 * curve->num_bytes; -} - -void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words) -{ - wordcount_t i; - for (i = 0; i < num_words; ++i) { - vli[i] = 0; - } -} - -uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words) -{ - uECC_word_t bits = 0; - wordcount_t i; - for (i = 0; i < num_words; ++i) { - bits |= vli[i]; - } - return (bits == 0); -} - -uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit) -{ - return (vli[bit >> uECC_WORD_BITS_SHIFT] & - ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); -} - -/* Counts the number of words in vli. */ -static wordcount_t vli_numDigits(const uECC_word_t *vli, - const wordcount_t max_words) -{ - - wordcount_t i; - /* Search from the end until we find a non-zero digit. We do it in reverse - * because we expect that most digits will be nonzero. */ - for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) { - } - - return (i + 1); -} - -bitcount_t uECC_vli_numBits(const uECC_word_t *vli, - const wordcount_t max_words) -{ - - uECC_word_t i; - uECC_word_t digit; - - wordcount_t num_digits = vli_numDigits(vli, max_words); - if (num_digits == 0) { - return 0; - } - - digit = vli[num_digits - 1]; - for (i = 0; digit; ++i) { - digit >>= 1; - } - - return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i); -} - -void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, - wordcount_t num_words) -{ - wordcount_t i; - - for (i = 0; i < num_words; ++i) { - dest[i] = src[i]; - } -} - -cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) -{ - wordcount_t i; - - for (i = num_words - 1; i >= 0; --i) { - if (left[i] > right[i]) { - return 1; - } else if (left[i] < right[i]) { - return -1; - } - } - return 0; -} - -uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right, - wordcount_t num_words) -{ - - uECC_word_t diff = 0; - wordcount_t i; - - for (i = num_words - 1; i >= 0; --i) { - diff |= (left[i] ^ right[i]); - } - return !(diff == 0); -} - -uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond) -{ - return (p_true*(cond)) | (p_false*(!cond)); -} - -/* Computes result = left - right, returning borrow, in constant time. - * Can modify in place. */ -uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left, - const uECC_word_t *right, wordcount_t num_words) -{ - uECC_word_t borrow = 0; - wordcount_t i; - for (i = 0; i < num_words; ++i) { - uECC_word_t diff = left[i] - right[i] - borrow; - uECC_word_t val = (diff > left[i]); - borrow = cond_set(val, borrow, (diff != left[i])); - - result[i] = diff; - } - return borrow; -} - -/* Computes result = left + right, returning carry, in constant time. - * Can modify in place. */ -static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left, - const uECC_word_t *right, wordcount_t num_words) -{ - uECC_word_t carry = 0; - wordcount_t i; - for (i = 0; i < num_words; ++i) { - uECC_word_t sum = left[i] + right[i] + carry; - uECC_word_t val = (sum < left[i]); - carry = cond_set(val, carry, (sum != left[i])); - result[i] = sum; - } - return carry; -} - -cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right, - wordcount_t num_words) -{ - uECC_word_t tmp[NUM_ECC_WORDS]; - uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words); - uECC_word_t equal = uECC_vli_isZero(tmp, num_words); - return (!equal - 2 * neg); -} - -/* Computes vli = vli >> 1. */ -static void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words) -{ - uECC_word_t *end = vli; - uECC_word_t carry = 0; - - vli += num_words; - while (vli-- > end) { - uECC_word_t temp = *vli; - *vli = (temp >> 1) | carry; - carry = temp << (uECC_WORD_BITS - 1); - } -} - -static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0, - uECC_word_t *r1, uECC_word_t *r2) -{ - - uECC_dword_t p = (uECC_dword_t)a * b; - uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0; - r01 += p; - *r2 += (r01 < p); - *r1 = r01 >> uECC_WORD_BITS; - *r0 = (uECC_word_t)r01; - -} - -/* Computes result = left * right. Result must be 2 * num_words long. */ -static void uECC_vli_mult(uECC_word_t *result, const uECC_word_t *left, - const uECC_word_t *right, wordcount_t num_words) -{ - - uECC_word_t r0 = 0; - uECC_word_t r1 = 0; - uECC_word_t r2 = 0; - wordcount_t i, k; - - /* Compute each digit of result in sequence, maintaining the carries. */ - for (k = 0; k < num_words; ++k) { - - for (i = 0; i <= k; ++i) { - muladd(left[i], right[k - i], &r0, &r1, &r2); - } - - result[k] = r0; - r0 = r1; - r1 = r2; - r2 = 0; - } - - for (k = num_words; k < num_words * 2 - 1; ++k) { - - for (i = (k + 1) - num_words; i < num_words; ++i) { - muladd(left[i], right[k - i], &r0, &r1, &r2); - } - result[k] = r0; - r0 = r1; - r1 = r2; - r2 = 0; - } - result[num_words * 2 - 1] = r0; -} - -void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left, - const uECC_word_t *right, const uECC_word_t *mod, - wordcount_t num_words) -{ - uECC_word_t carry = uECC_vli_add(result, left, right, num_words); - if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) { - /* result > mod (result = mod + remainder), so subtract mod to get - * remainder. */ - uECC_vli_sub(result, result, mod, num_words); - } -} - -void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left, - const uECC_word_t *right, const uECC_word_t *mod, - wordcount_t num_words) -{ - uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words); - if (l_borrow) { - /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x, - * we can get the correct result from result + mod (with overflow). */ - uECC_vli_add(result, result, mod, num_words); - } -} - -/* Computes result = product % mod, where product is 2N words long. */ -/* Currently only designed to work for curve_p or curve_n. */ -void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product, - const uECC_word_t *mod, wordcount_t num_words) -{ - uECC_word_t mod_multiple[2 * NUM_ECC_WORDS]; - uECC_word_t tmp[2 * NUM_ECC_WORDS]; - uECC_word_t *v[2] = {tmp, product}; - uECC_word_t index; - - /* Shift mod so its highest set bit is at the maximum position. */ - bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) - - uECC_vli_numBits(mod, num_words); - wordcount_t word_shift = shift / uECC_WORD_BITS; - wordcount_t bit_shift = shift % uECC_WORD_BITS; - uECC_word_t carry = 0; - uECC_vli_clear(mod_multiple, word_shift); - if (bit_shift > 0) { - for(index = 0; index < (uECC_word_t)num_words; ++index) { - mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry; - carry = mod[index] >> (uECC_WORD_BITS - bit_shift); - } - } else { - uECC_vli_set(mod_multiple + word_shift, mod, num_words); - } - - for (index = 1; shift >= 0; --shift) { - uECC_word_t borrow = 0; - wordcount_t i; - for (i = 0; i < num_words * 2; ++i) { - uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow; - if (diff != v[index][i]) { - borrow = (diff > v[index][i]); - } - v[1 - index][i] = diff; - } - /* Swap the index if there was no borrow */ - index = !(index ^ borrow); - uECC_vli_rshift1(mod_multiple, num_words); - mod_multiple[num_words - 1] |= mod_multiple[num_words] << - (uECC_WORD_BITS - 1); - uECC_vli_rshift1(mod_multiple + num_words, num_words); - } - uECC_vli_set(result, v[index], num_words); -} - -void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left, - const uECC_word_t *right, const uECC_word_t *mod, - wordcount_t num_words) -{ - uECC_word_t product[2 * NUM_ECC_WORDS]; - uECC_vli_mult(product, left, right, num_words); - uECC_vli_mmod(result, product, mod, num_words); -} - -void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left, - const uECC_word_t *right, uECC_Curve curve) -{ - uECC_word_t product[2 * NUM_ECC_WORDS]; - uECC_vli_mult(product, left, right, curve->num_words); - - curve->mmod_fast(result, product); -} - -static void uECC_vli_modSquare_fast(uECC_word_t *result, - const uECC_word_t *left, - uECC_Curve curve) -{ - uECC_vli_modMult_fast(result, left, left, curve); -} - - -#define EVEN(vli) (!(vli[0] & 1)) - -static void vli_modInv_update(uECC_word_t *uv, - const uECC_word_t *mod, - wordcount_t num_words) -{ - - uECC_word_t carry = 0; - - if (!EVEN(uv)) { - carry = uECC_vli_add(uv, uv, mod, num_words); - } - uECC_vli_rshift1(uv, num_words); - if (carry) { - uv[num_words - 1] |= HIGH_BIT_SET; - } -} - -void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input, - const uECC_word_t *mod, wordcount_t num_words) -{ - uECC_word_t a[NUM_ECC_WORDS], b[NUM_ECC_WORDS]; - uECC_word_t u[NUM_ECC_WORDS], v[NUM_ECC_WORDS]; - cmpresult_t cmpResult; - - if (uECC_vli_isZero(input, num_words)) { - uECC_vli_clear(result, num_words); - return; - } - - uECC_vli_set(a, input, num_words); - uECC_vli_set(b, mod, num_words); - uECC_vli_clear(u, num_words); - u[0] = 1; - uECC_vli_clear(v, num_words); - while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) { - if (EVEN(a)) { - uECC_vli_rshift1(a, num_words); - vli_modInv_update(u, mod, num_words); - } else if (EVEN(b)) { - uECC_vli_rshift1(b, num_words); - vli_modInv_update(v, mod, num_words); - } else if (cmpResult > 0) { - uECC_vli_sub(a, a, b, num_words); - uECC_vli_rshift1(a, num_words); - if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) { - uECC_vli_add(u, u, mod, num_words); - } - uECC_vli_sub(u, u, v, num_words); - vli_modInv_update(u, mod, num_words); - } else { - uECC_vli_sub(b, b, a, num_words); - uECC_vli_rshift1(b, num_words); - if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) { - uECC_vli_add(v, v, mod, num_words); - } - uECC_vli_sub(v, v, u, num_words); - vli_modInv_update(v, mod, num_words); - } - } - uECC_vli_set(result, u, num_words); -} - -/* ------ Point operations ------ */ - -void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1, - uECC_word_t * Z1, uECC_Curve curve) -{ - /* t1 = X, t2 = Y, t3 = Z */ - uECC_word_t t4[NUM_ECC_WORDS]; - uECC_word_t t5[NUM_ECC_WORDS]; - wordcount_t num_words = curve->num_words; - - if (uECC_vli_isZero(Z1, num_words)) { - return; - } - - uECC_vli_modSquare_fast(t4, Y1, curve); /* t4 = y1^2 */ - uECC_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */ - uECC_vli_modSquare_fast(t4, t4, curve); /* t4 = y1^4 */ - uECC_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */ - uECC_vli_modSquare_fast(Z1, Z1, curve); /* t3 = z1^2 */ - - uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */ - uECC_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */ - uECC_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */ - uECC_vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */ - - uECC_vli_modAdd(Z1, X1, X1, curve->p, num_words); /* t3 = 2*(x1^2 - z1^4) */ - uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = 3*(x1^2 - z1^4) */ - if (uECC_vli_testBit(X1, 0)) { - uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words); - uECC_vli_rshift1(X1, num_words); - X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1); - } else { - uECC_vli_rshift1(X1, num_words); - } - - /* t1 = 3/2*(x1^2 - z1^4) = B */ - uECC_vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */ - uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */ - uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */ - uECC_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */ - uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */ - /* t4 = B * (A - x3) - y1^4 = y3: */ - uECC_vli_modSub(t4, X1, t4, curve->p, num_words); - - uECC_vli_set(X1, Z1, num_words); - uECC_vli_set(Z1, Y1, num_words); - uECC_vli_set(Y1, t4, num_words); -} - -void x_side_default(uECC_word_t *result, - const uECC_word_t *x, - uECC_Curve curve) -{ - uECC_word_t _3[NUM_ECC_WORDS] = {3}; /* -a = 3 */ - wordcount_t num_words = curve->num_words; - - uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ - uECC_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */ - uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */ - /* r = x^3 - 3x + b: */ - uECC_vli_modAdd(result, result, curve->b, curve->p, num_words); -} - -uECC_Curve uECC_secp256r1(void) -{ - return &curve_secp256r1; -} - -void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int*product) -{ - unsigned int tmp[NUM_ECC_WORDS]; - int carry; - - /* t */ - uECC_vli_set(result, product, NUM_ECC_WORDS); - - /* s1 */ - tmp[0] = tmp[1] = tmp[2] = 0; - tmp[3] = product[11]; - tmp[4] = product[12]; - tmp[5] = product[13]; - tmp[6] = product[14]; - tmp[7] = product[15]; - carry = uECC_vli_add(tmp, tmp, tmp, NUM_ECC_WORDS); - carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS); - - /* s2 */ - tmp[3] = product[12]; - tmp[4] = product[13]; - tmp[5] = product[14]; - tmp[6] = product[15]; - tmp[7] = 0; - carry += uECC_vli_add(tmp, tmp, tmp, NUM_ECC_WORDS); - carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS); - - /* s3 */ - tmp[0] = product[8]; - tmp[1] = product[9]; - tmp[2] = product[10]; - tmp[3] = tmp[4] = tmp[5] = 0; - tmp[6] = product[14]; - tmp[7] = product[15]; - carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS); - - /* s4 */ - tmp[0] = product[9]; - tmp[1] = product[10]; - tmp[2] = product[11]; - tmp[3] = product[13]; - tmp[4] = product[14]; - tmp[5] = product[15]; - tmp[6] = product[13]; - tmp[7] = product[8]; - carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS); - - /* d1 */ - tmp[0] = product[11]; - tmp[1] = product[12]; - tmp[2] = product[13]; - tmp[3] = tmp[4] = tmp[5] = 0; - tmp[6] = product[8]; - tmp[7] = product[10]; - carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS); - - /* d2 */ - tmp[0] = product[12]; - tmp[1] = product[13]; - tmp[2] = product[14]; - tmp[3] = product[15]; - tmp[4] = tmp[5] = 0; - tmp[6] = product[9]; - tmp[7] = product[11]; - carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS); - - /* d3 */ - tmp[0] = product[13]; - tmp[1] = product[14]; - tmp[2] = product[15]; - tmp[3] = product[8]; - tmp[4] = product[9]; - tmp[5] = product[10]; - tmp[6] = 0; - tmp[7] = product[12]; - carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS); - - /* d4 */ - tmp[0] = product[14]; - tmp[1] = product[15]; - tmp[2] = 0; - tmp[3] = product[9]; - tmp[4] = product[10]; - tmp[5] = product[11]; - tmp[6] = 0; - tmp[7] = product[13]; - carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS); - - if (carry < 0) { - do { - carry += uECC_vli_add(result, result, curve_secp256r1.p, NUM_ECC_WORDS); - } - while (carry < 0); - } else { - while (carry || - uECC_vli_cmp_unsafe(curve_secp256r1.p, result, NUM_ECC_WORDS) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp256r1.p, NUM_ECC_WORDS); - } - } -} - -uECC_word_t EccPoint_isZero(const uECC_word_t *point, uECC_Curve curve) -{ - return uECC_vli_isZero(point, curve->num_words * 2); -} - -void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z, - uECC_Curve curve) -{ - uECC_word_t t1[NUM_ECC_WORDS]; - - uECC_vli_modSquare_fast(t1, Z, curve); /* z^2 */ - uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */ - uECC_vli_modMult_fast(t1, t1, Z, curve); /* z^3 */ - uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */ -} - -/* P = (x1, y1) => 2P, (x2, y2) => P' */ -static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1, - uECC_word_t * X2, uECC_word_t * Y2, - const uECC_word_t * const initial_Z, - uECC_Curve curve) -{ - uECC_word_t z[NUM_ECC_WORDS]; - wordcount_t num_words = curve->num_words; - if (initial_Z) { - uECC_vli_set(z, initial_Z, num_words); - } else { - uECC_vli_clear(z, num_words); - z[0] = 1; - } - - uECC_vli_set(X2, X1, num_words); - uECC_vli_set(Y2, Y1, num_words); - - apply_z(X1, Y1, z, curve); - curve->double_jacobian(X1, Y1, z, curve); - apply_z(X2, Y2, z, curve); -} - -void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1, - uECC_word_t * X2, uECC_word_t * Y2, - uECC_Curve curve) -{ - /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ - uECC_word_t t5[NUM_ECC_WORDS]; - wordcount_t num_words = curve->num_words; - - uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ - uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ - uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ - uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ - uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ - uECC_vli_modSquare_fast(t5, Y2, curve); /* t5 = (y2 - y1)^2 = D */ - - uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */ - uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */ - uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */ - uECC_vli_modMult_fast(Y1, Y1, X2, curve); /* t2 = y1*(C - B) */ - uECC_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */ - uECC_vli_modMult_fast(Y2, Y2, X2, curve); /* t4 = (y2 - y1)*(B - x3) */ - uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */ - - uECC_vli_set(X2, t5, num_words); -} - -/* Input P = (x1, y1, Z), Q = (x2, y2, Z) - Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) - or P => P - Q, Q => P + Q - */ -static void XYcZ_addC(uECC_word_t * X1, uECC_word_t * Y1, - uECC_word_t * X2, uECC_word_t * Y2, - uECC_Curve curve) -{ - /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ - uECC_word_t t5[NUM_ECC_WORDS]; - uECC_word_t t6[NUM_ECC_WORDS]; - uECC_word_t t7[NUM_ECC_WORDS]; - wordcount_t num_words = curve->num_words; - - uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ - uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ - uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ - uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ - uECC_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */ - uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ - - uECC_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */ - uECC_vli_modMult_fast(Y1, Y1, t6, curve); /* t2 = y1 * (C - B) = E */ - uECC_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */ - uECC_vli_modSquare_fast(X2, Y2, curve); /* t3 = (y2 - y1)^2 = D */ - uECC_vli_modSub(X2, X2, t6, curve->p, num_words); /* t3 = D - (B + C) = x3 */ - - uECC_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */ - uECC_vli_modMult_fast(Y2, Y2, t7, curve); /* t4 = (y2 - y1)*(B - x3) */ - /* t4 = (y2 - y1)*(B - x3) - E = y3: */ - uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); - - uECC_vli_modSquare_fast(t7, t5, curve); /* t7 = (y2 + y1)^2 = F */ - uECC_vli_modSub(t7, t7, t6, curve->p, num_words); /* t7 = F - (B + C) = x3' */ - uECC_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */ - uECC_vli_modMult_fast(t6, t6, t5, curve); /* t6 = (y2+y1)*(x3' - B) */ - /* t2 = (y2+y1)*(x3' - B) - E = y3': */ - uECC_vli_modSub(Y1, t6, Y1, curve->p, num_words); - - uECC_vli_set(X1, t7, num_words); -} - -void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point, - const uECC_word_t * scalar, - const uECC_word_t * initial_Z, - bitcount_t num_bits, uECC_Curve curve) -{ - /* R0 and R1 */ - uECC_word_t Rx[2][NUM_ECC_WORDS]; - uECC_word_t Ry[2][NUM_ECC_WORDS]; - uECC_word_t z[NUM_ECC_WORDS]; - bitcount_t i; - uECC_word_t nb; - wordcount_t num_words = curve->num_words; - - uECC_vli_set(Rx[1], point, num_words); - uECC_vli_set(Ry[1], point + num_words, num_words); - - XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z, curve); - - for (i = num_bits - 2; i > 0; --i) { - nb = !uECC_vli_testBit(scalar, i); - XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); - XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); - } - - nb = !uECC_vli_testBit(scalar, 0); - XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); - - /* Find final 1/Z value. */ - uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */ - uECC_vli_modMult_fast(z, z, Ry[1 - nb], curve); /* Yb * (X1 - X0) */ - uECC_vli_modMult_fast(z, z, point, curve); /* xP * Yb * (X1 - X0) */ - uECC_vli_modInv(z, z, curve->p, num_words); /* 1 / (xP * Yb * (X1 - X0))*/ - /* yP / (xP * Yb * (X1 - X0)) */ - uECC_vli_modMult_fast(z, z, point + num_words, curve); - /* Xb * yP / (xP * Yb * (X1 - X0)) */ - uECC_vli_modMult_fast(z, z, Rx[1 - nb], curve); - /* End 1/Z calculation */ - - XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); - apply_z(Rx[0], Ry[0], z, curve); - - uECC_vli_set(result, Rx[0], num_words); - uECC_vli_set(result + num_words, Ry[0], num_words); -} - -uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0, - uECC_word_t *k1, uECC_Curve curve) -{ - - wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - - bitcount_t num_n_bits = curve->num_n_bits; - - uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || - (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) && - uECC_vli_testBit(k0, num_n_bits)); - - uECC_vli_add(k1, k0, curve->n, num_n_words); - - return carry; -} - -uECC_word_t EccPoint_compute_public_key(uECC_word_t *result, - uECC_word_t *private_key, - uECC_Curve curve) -{ - - uECC_word_t tmp1[NUM_ECC_WORDS]; - uECC_word_t tmp2[NUM_ECC_WORDS]; - uECC_word_t *p2[2] = {tmp1, tmp2}; - uECC_word_t carry; - - /* Regularize the bitcount for the private key so that attackers cannot - * use a side channel attack to learn the number of leading zeros. */ - carry = regularize_k(private_key, tmp1, tmp2, curve); - - EccPoint_mult(result, curve->G, p2[!carry], 0, curve->num_n_bits + 1, curve); - - if (EccPoint_isZero(result, curve)) { - return 0; - } - return 1; -} - -/* Converts an integer in uECC native format to big-endian bytes. */ -void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes, - const unsigned int *native) -{ - wordcount_t i; - for (i = 0; i < num_bytes; ++i) { - unsigned b = num_bytes - 1 - i; - bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE)); - } -} - -/* Converts big-endian bytes to an integer in uECC native format. */ -void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes, - int num_bytes) -{ - wordcount_t i; - uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE); - for (i = 0; i < num_bytes; ++i) { - unsigned b = num_bytes - 1 - i; - native[b / uECC_WORD_SIZE] |= - (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE)); - } -} - -int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top, - wordcount_t num_words) -{ - uECC_word_t mask = (uECC_word_t)-1; - uECC_word_t tries; - bitcount_t num_bits = uECC_vli_numBits(top, num_words); - - if (!g_rng_function) { - return 0; - } - - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) { - return 0; - } - random[num_words - 1] &= - mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); - if (!uECC_vli_isZero(random, num_words) && - uECC_vli_cmp(top, random, num_words) == 1) { - return 1; - } - } - return 0; -} - - -int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) -{ - uECC_word_t tmp1[NUM_ECC_WORDS]; - uECC_word_t tmp2[NUM_ECC_WORDS]; - wordcount_t num_words = curve->num_words; - - /* The point at infinity is invalid. */ - if (EccPoint_isZero(point, curve)) { - return -1; - } - - /* x and y must be smaller than p. */ - if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 || - uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) { - return -2; - } - - uECC_vli_modSquare_fast(tmp1, point + num_words, curve); - curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */ - - /* Make sure that y^2 == x^3 + ax + b */ - if (uECC_vli_equal(tmp1, tmp2, num_words) != 0) - return -3; - - return 0; -} - -int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve) -{ - - uECC_word_t _public[NUM_ECC_WORDS * 2]; - - uECC_vli_bytesToNative(_public, public_key, curve->num_bytes); - uECC_vli_bytesToNative( - _public + curve->num_words, - public_key + curve->num_bytes, - curve->num_bytes); - - if (uECC_vli_cmp_unsafe(_public, curve->G, NUM_ECC_WORDS * 2) == 0) { - return -4; - } - - return uECC_valid_point(_public, curve); -} - -int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, - uECC_Curve curve) -{ - - uECC_word_t _private[NUM_ECC_WORDS]; - uECC_word_t _public[NUM_ECC_WORDS * 2]; - - uECC_vli_bytesToNative( - _private, - private_key, - BITS_TO_BYTES(curve->num_n_bits)); - - /* Make sure the private key is in the range [1, n-1]. */ - if (uECC_vli_isZero(_private, BITS_TO_WORDS(curve->num_n_bits))) { - return 0; - } - - if (uECC_vli_cmp(curve->n, _private, BITS_TO_WORDS(curve->num_n_bits)) != 1) { - return 0; - } - - /* Compute public key. */ - if (!EccPoint_compute_public_key(_public, _private, curve)) { - return 0; - } - - uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public); - uECC_vli_nativeToBytes( - public_key + - curve->num_bytes, curve->num_bytes, _public + curve->num_words); - return 1; -} - - - diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc_dh.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc_dh.c deleted file mode 100644 index 5cd6a2e2f..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc_dh.c +++ /dev/null @@ -1,200 +0,0 @@ -/* ec_dh.c - TinyCrypt implementation of EC-DH */ - -/* - * Copyright (c) 2014, Kenneth MacKay - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include "../include/tinycrypt/constants.h" -#include "../include/tinycrypt/ecc.h" -#include "../include/tinycrypt/ecc_dh.h" -#include - -#if default_RNG_defined -static uECC_RNG_Function g_rng_function = &default_CSPRNG; -#else -static uECC_RNG_Function g_rng_function = 0; -#endif - -int uECC_make_key_with_d(uint8_t *public_key, uint8_t *private_key, - unsigned int *d, uECC_Curve curve) -{ - - uECC_word_t _private[NUM_ECC_WORDS]; - uECC_word_t _public[NUM_ECC_WORDS * 2]; - - /* This function is designed for test purposes-only (such as validating NIST - * test vectors) as it uses a provided value for d instead of generating - * it uniformly at random. */ - memcpy (_private, d, NUM_ECC_BYTES); - - /* Computing public-key from private: */ - if (EccPoint_compute_public_key(_public, _private, curve)) { - - /* Converting buffers to correct bit order: */ - uECC_vli_nativeToBytes(private_key, - BITS_TO_BYTES(curve->num_n_bits), - _private); - uECC_vli_nativeToBytes(public_key, - curve->num_bytes, - _public); - uECC_vli_nativeToBytes(public_key + curve->num_bytes, - curve->num_bytes, - _public + curve->num_words); - - /* erasing temporary buffer used to store secret: */ - memset(_private, 0, NUM_ECC_BYTES); - - return 1; - } - return 0; -} - -int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve) -{ - - uECC_word_t _random[NUM_ECC_WORDS * 2]; - uECC_word_t _private[NUM_ECC_WORDS]; - uECC_word_t _public[NUM_ECC_WORDS * 2]; - uECC_word_t tries; - - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - /* Generating _private uniformly at random: */ - uECC_RNG_Function rng_function = uECC_get_rng(); - if (!rng_function || - !rng_function((uint8_t *)_random, 2 * NUM_ECC_WORDS*uECC_WORD_SIZE)) { - return 0; - } - - /* computing modular reduction of _random (see FIPS 186.4 B.4.1): */ - uECC_vli_mmod(_private, _random, curve->n, BITS_TO_WORDS(curve->num_n_bits)); - - /* Computing public-key from private: */ - if (EccPoint_compute_public_key(_public, _private, curve)) { - - /* Converting buffers to correct bit order: */ - uECC_vli_nativeToBytes(private_key, - BITS_TO_BYTES(curve->num_n_bits), - _private); - uECC_vli_nativeToBytes(public_key, - curve->num_bytes, - _public); - uECC_vli_nativeToBytes(public_key + curve->num_bytes, - curve->num_bytes, - _public + curve->num_words); - - /* erasing temporary buffer that stored secret: */ - memset(_private, 0, NUM_ECC_BYTES); - - return 1; - } - } - return 0; -} - -int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key, - uint8_t *secret, uECC_Curve curve) -{ - - uECC_word_t _public[NUM_ECC_WORDS * 2]; - uECC_word_t _private[NUM_ECC_WORDS]; - - uECC_word_t tmp[NUM_ECC_WORDS]; - uECC_word_t *p2[2] = {_private, tmp}; - uECC_word_t *initial_Z = 0; - uECC_word_t carry; - wordcount_t num_words = curve->num_words; - wordcount_t num_bytes = curve->num_bytes; - int r; - - /* Converting buffers to correct bit order: */ - uECC_vli_bytesToNative(_private, - private_key, - BITS_TO_BYTES(curve->num_n_bits)); - uECC_vli_bytesToNative(_public, - public_key, - num_bytes); - uECC_vli_bytesToNative(_public + num_words, - public_key + num_bytes, - num_bytes); - - /* Regularize the bitcount for the private key so that attackers cannot use a - * side channel attack to learn the number of leading zeros. */ - carry = regularize_k(_private, _private, tmp, curve); - - /* If an RNG function was specified, try to get a random initial Z value to - * improve protection against side-channel attacks. */ - if (g_rng_function) { - if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) { - r = 0; - goto clear_and_out; - } - initial_Z = p2[carry]; - } - - EccPoint_mult(_public, _public, p2[!carry], initial_Z, curve->num_n_bits + 1, - curve); - - uECC_vli_nativeToBytes(secret, num_bytes, _public); - r = !EccPoint_isZero(_public, curve); - -clear_and_out: - /* erasing temporary buffer used to store secret: */ - memset(p2, 0, sizeof(p2)); - __asm__ __volatile__("" :: "g"(p2) : "memory"); - memset(tmp, 0, sizeof(tmp)); - __asm__ __volatile__("" :: "g"(tmp) : "memory"); - memset(_private, 0, sizeof(_private)); - __asm__ __volatile__("" :: "g"(_private) : "memory"); - - return r; -} diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc_dsa.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc_dsa.c deleted file mode 100644 index 31046c860..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc_dsa.c +++ /dev/null @@ -1,295 +0,0 @@ -/* ec_dsa.c - TinyCrypt implementation of EC-DSA */ - -/* Copyright (c) 2014, Kenneth MacKay - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE.*/ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "../include/tinycrypt/constants.h" -#include "../include/tinycrypt/ecc.h" -#include "../include/tinycrypt/ecc_dsa.h" - -#if default_RNG_defined -static uECC_RNG_Function g_rng_function = &default_CSPRNG; -#else -static uECC_RNG_Function g_rng_function = 0; -#endif - -static void bits2int(uECC_word_t *native, const uint8_t *bits, - unsigned bits_size, uECC_Curve curve) -{ - unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits); - unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits); - int shift; - uECC_word_t carry; - uECC_word_t *ptr; - - if (bits_size > num_n_bytes) { - bits_size = num_n_bytes; - } - - uECC_vli_clear(native, num_n_words); - uECC_vli_bytesToNative(native, bits, bits_size); - if (bits_size * 8 <= (unsigned)curve->num_n_bits) { - return; - } - shift = bits_size * 8 - curve->num_n_bits; - carry = 0; - ptr = native + num_n_words; - while (ptr-- > native) { - uECC_word_t temp = *ptr; - *ptr = (temp >> shift) | carry; - carry = temp << (uECC_WORD_BITS - shift); - } - - /* Reduce mod curve_n */ - if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) { - uECC_vli_sub(native, native, curve->n, num_n_words); - } -} - -int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, - unsigned hash_size, uECC_word_t *k, uint8_t *signature, - uECC_Curve curve) -{ - - uECC_word_t tmp[NUM_ECC_WORDS]; - uECC_word_t s[NUM_ECC_WORDS]; - uECC_word_t *k2[2] = {tmp, s}; - uECC_word_t p[NUM_ECC_WORDS * 2]; - uECC_word_t carry; - wordcount_t num_words = curve->num_words; - wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - bitcount_t num_n_bits = curve->num_n_bits; - - /* Make sure 0 < k < curve_n */ - if (uECC_vli_isZero(k, num_words) || - uECC_vli_cmp(curve->n, k, num_n_words) != 1) { - return 0; - } - - carry = regularize_k(k, tmp, s, curve); - EccPoint_mult(p, curve->G, k2[!carry], 0, num_n_bits + 1, curve); - if (uECC_vli_isZero(p, num_words)) { - return 0; - } - - /* If an RNG function was specified, get a random number - to prevent side channel analysis of k. */ - if (!g_rng_function) { - uECC_vli_clear(tmp, num_n_words); - tmp[0] = 1; - } - else if (!uECC_generate_random_int(tmp, curve->n, num_n_words)) { - return 0; - } - - /* Prevent side channel analysis of uECC_vli_modInv() to determine - bits of k / the private key by premultiplying by a random number */ - uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */ - uECC_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */ - uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */ - - uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */ - - /* tmp = d: */ - uECC_vli_bytesToNative(tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); - - s[num_n_words - 1] = 0; - uECC_vli_set(s, p, num_words); - uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */ - - bits2int(tmp, message_hash, hash_size, curve); - uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */ - uECC_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */ - if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) { - return 0; - } - - uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s); - return 1; -} - -int uECC_sign(const uint8_t *private_key, const uint8_t *message_hash, - unsigned hash_size, uint8_t *signature, uECC_Curve curve) -{ - uECC_word_t _random[2*NUM_ECC_WORDS]; - uECC_word_t k[NUM_ECC_WORDS]; - uECC_word_t tries; - - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - /* Generating _random uniformly at random: */ - uECC_RNG_Function rng_function = uECC_get_rng(); - if (!rng_function || - !rng_function((uint8_t *)_random, 2*NUM_ECC_WORDS*uECC_WORD_SIZE)) { - return 0; - } - - // computing k as modular reduction of _random (see FIPS 186.4 B.5.1): - uECC_vli_mmod(k, _random, curve->n, BITS_TO_WORDS(curve->num_n_bits)); - - if (uECC_sign_with_k(private_key, message_hash, hash_size, k, signature, - curve)) { - return 1; - } - } - return 0; -} - -static bitcount_t smax(bitcount_t a, bitcount_t b) -{ - return (a > b ? a : b); -} - -int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash, - unsigned hash_size, const uint8_t *signature, - uECC_Curve curve) -{ - - uECC_word_t u1[NUM_ECC_WORDS], u2[NUM_ECC_WORDS]; - uECC_word_t z[NUM_ECC_WORDS]; - uECC_word_t sum[NUM_ECC_WORDS * 2]; - uECC_word_t rx[NUM_ECC_WORDS]; - uECC_word_t ry[NUM_ECC_WORDS]; - uECC_word_t tx[NUM_ECC_WORDS]; - uECC_word_t ty[NUM_ECC_WORDS]; - uECC_word_t tz[NUM_ECC_WORDS]; - const uECC_word_t *points[4]; - const uECC_word_t *point; - bitcount_t num_bits; - bitcount_t i; - - uECC_word_t _public[NUM_ECC_WORDS * 2]; - uECC_word_t r[NUM_ECC_WORDS], s[NUM_ECC_WORDS]; - wordcount_t num_words = curve->num_words; - wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - - rx[num_n_words - 1] = 0; - r[num_n_words - 1] = 0; - s[num_n_words - 1] = 0; - - uECC_vli_bytesToNative(_public, public_key, curve->num_bytes); - uECC_vli_bytesToNative(_public + num_words, public_key + curve->num_bytes, - curve->num_bytes); - uECC_vli_bytesToNative(r, signature, curve->num_bytes); - uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes); - - /* r, s must not be 0. */ - if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) { - return 0; - } - - /* r, s must be < n. */ - if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 || - uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) { - return 0; - } - - /* Calculate u1 and u2. */ - uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */ - u1[num_n_words - 1] = 0; - bits2int(u1, message_hash, hash_size, curve); - uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */ - uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */ - - /* Calculate sum = G + Q. */ - uECC_vli_set(sum, _public, num_words); - uECC_vli_set(sum + num_words, _public + num_words, num_words); - uECC_vli_set(tx, curve->G, num_words); - uECC_vli_set(ty, curve->G + num_words, num_words); - uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */ - XYcZ_add(tx, ty, sum, sum + num_words, curve); - uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */ - apply_z(sum, sum + num_words, z, curve); - - /* Use Shamir's trick to calculate u1*G + u2*Q */ - points[0] = 0; - points[1] = curve->G; - points[2] = _public; - points[3] = sum; - num_bits = smax(uECC_vli_numBits(u1, num_n_words), - uECC_vli_numBits(u2, num_n_words)); - - point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | - ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)]; - uECC_vli_set(rx, point, num_words); - uECC_vli_set(ry, point + num_words, num_words); - uECC_vli_clear(z, num_words); - z[0] = 1; - - for (i = num_bits - 2; i >= 0; --i) { - uECC_word_t index; - curve->double_jacobian(rx, ry, z, curve); - - index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1); - point = points[index]; - if (point) { - uECC_vli_set(tx, point, num_words); - uECC_vli_set(ty, point + num_words, num_words); - apply_z(tx, ty, z, curve); - uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */ - XYcZ_add(tx, ty, rx, ry, curve); - uECC_vli_modMult_fast(z, z, tz, curve); - } - } - - uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */ - apply_z(rx, ry, z, curve); - - /* v = x1 (mod n) */ - if (uECC_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) { - uECC_vli_sub(rx, rx, curve->n, num_n_words); - } - - /* Accept only if v == r. */ - return (int)(uECC_vli_equal(rx, r, num_words) == 0); -} - diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc_platform_specific.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc_platform_specific.c deleted file mode 100644 index 1867988f9..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc_platform_specific.c +++ /dev/null @@ -1,105 +0,0 @@ -/* uECC_platform_specific.c - Implementation of platform specific functions*/ - -/* Copyright (c) 2014, Kenneth MacKay - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE.*/ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * uECC_platform_specific.c -- Implementation of platform specific functions - */ - - -#if defined(unix) || defined(__linux__) || defined(__unix__) || \ - defined(__unix) | (defined(__APPLE__) && defined(__MACH__)) || \ - defined(uECC_POSIX) - -/* Some POSIX-like system with /dev/urandom or /dev/random. */ -#include -#include -#include - -#include - -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -int default_CSPRNG(uint8_t *dest, unsigned int size) { - - /* input sanity check: */ - if (dest == (uint8_t *) 0 || (size <= 0)) - return 0; - - int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); - if (fd == -1) { - fd = open("/dev/random", O_RDONLY | O_CLOEXEC); - if (fd == -1) { - return 0; - } - } - - char *ptr = (char *)dest; - size_t left = (size_t) size; - while (left > 0) { - ssize_t bytes_read = read(fd, ptr, left); - if (bytes_read <= 0) { // read failed - close(fd); - return 0; - } - left -= bytes_read; - ptr += bytes_read; - } - - close(fd); - return 1; -} - -#endif /* platform */ - diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/hmac.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/hmac.c deleted file mode 100644 index c86fd35a7..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/hmac.c +++ /dev/null @@ -1,148 +0,0 @@ -/* hmac.c - TinyCrypt implementation of the HMAC algorithm */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "../include/tinycrypt/hmac.h" -#include "../include/tinycrypt/constants.h" -#include "../include/tinycrypt/utils.h" - -static void rekey(uint8_t *key, const uint8_t *new_key, unsigned int key_size) -{ - const uint8_t inner_pad = (uint8_t) 0x36; - const uint8_t outer_pad = (uint8_t) 0x5c; - unsigned int i; - - for (i = 0; i < key_size; ++i) { - key[i] = inner_pad ^ new_key[i]; - key[i + TC_SHA256_BLOCK_SIZE] = outer_pad ^ new_key[i]; - } - for (; i < TC_SHA256_BLOCK_SIZE; ++i) { - key[i] = inner_pad; key[i + TC_SHA256_BLOCK_SIZE] = outer_pad; - } -} - -int tc_hmac_set_key(TCHmacState_t ctx, const uint8_t *key, - unsigned int key_size) -{ - - /* input sanity check: */ - if (ctx == (TCHmacState_t) 0 || - key == (const uint8_t *) 0 || - key_size == 0) { - return TC_CRYPTO_FAIL; - } - - const uint8_t dummy_key[key_size]; - struct tc_hmac_state_struct dummy_state; - - if (key_size <= TC_SHA256_BLOCK_SIZE) { - /* - * The next three lines consist of dummy calls just to avoid - * certain timing attacks. Without these dummy calls, - * adversaries would be able to learn whether the key_size is - * greater than TC_SHA256_BLOCK_SIZE by measuring the time - * consumed in this process. - */ - (void)tc_sha256_init(&dummy_state.hash_state); - (void)tc_sha256_update(&dummy_state.hash_state, - dummy_key, - key_size); - (void)tc_sha256_final(&dummy_state.key[TC_SHA256_DIGEST_SIZE], - &dummy_state.hash_state); - - /* Actual code for when key_size <= TC_SHA256_BLOCK_SIZE: */ - rekey(ctx->key, key, key_size); - } else { - (void)tc_sha256_init(&ctx->hash_state); - (void)tc_sha256_update(&ctx->hash_state, key, key_size); - (void)tc_sha256_final(&ctx->key[TC_SHA256_DIGEST_SIZE], - &ctx->hash_state); - rekey(ctx->key, - &ctx->key[TC_SHA256_DIGEST_SIZE], - TC_SHA256_DIGEST_SIZE); - } - - return TC_CRYPTO_SUCCESS; -} - -int tc_hmac_init(TCHmacState_t ctx) -{ - - /* input sanity check: */ - if (ctx == (TCHmacState_t) 0) { - return TC_CRYPTO_FAIL; - } - - (void) tc_sha256_init(&ctx->hash_state); - (void) tc_sha256_update(&ctx->hash_state, ctx->key, TC_SHA256_BLOCK_SIZE); - - return TC_CRYPTO_SUCCESS; -} - -int tc_hmac_update(TCHmacState_t ctx, - const void *data, - unsigned int data_length) -{ - - /* input sanity check: */ - if (ctx == (TCHmacState_t) 0) { - return TC_CRYPTO_FAIL; - } - - (void)tc_sha256_update(&ctx->hash_state, data, data_length); - - return TC_CRYPTO_SUCCESS; -} - -int tc_hmac_final(uint8_t *tag, unsigned int taglen, TCHmacState_t ctx) -{ - - /* input sanity check: */ - if (tag == (uint8_t *) 0 || - taglen != TC_SHA256_DIGEST_SIZE || - ctx == (TCHmacState_t) 0) { - return TC_CRYPTO_FAIL; - } - - (void) tc_sha256_final(tag, &ctx->hash_state); - - (void)tc_sha256_init(&ctx->hash_state); - (void)tc_sha256_update(&ctx->hash_state, - &ctx->key[TC_SHA256_BLOCK_SIZE], - TC_SHA256_BLOCK_SIZE); - (void)tc_sha256_update(&ctx->hash_state, tag, TC_SHA256_DIGEST_SIZE); - (void)tc_sha256_final(tag, &ctx->hash_state); - - /* destroy the current state */ - _set(ctx, 0, sizeof(*ctx)); - - return TC_CRYPTO_SUCCESS; -} diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/hmac_prng.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/hmac_prng.c deleted file mode 100644 index a41ea43d5..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/hmac_prng.c +++ /dev/null @@ -1,212 +0,0 @@ -/* hmac_prng.c - TinyCrypt implementation of HMAC-PRNG */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "../include/tinycrypt/hmac_prng.h" -#include "../include/tinycrypt/hmac.h" -#include "../include/tinycrypt/constants.h" -#include "../include/tinycrypt/utils.h" - -/* - * min bytes in the seed string. - * MIN_SLEN*8 must be at least the expected security level. - */ -static const unsigned int MIN_SLEN = 32; - -/* - * max bytes in the seed string; - * SP800-90A specifies a maximum of 2^35 bits (i.e., 2^32 bytes). - */ -static const unsigned int MAX_SLEN = UINT32_MAX; - -/* - * max bytes in the personalization string; - * SP800-90A specifies a maximum of 2^35 bits (i.e., 2^32 bytes). - */ -static const unsigned int MAX_PLEN = UINT32_MAX; - -/* - * max bytes in the additional_info string; - * SP800-90A specifies a maximum of 2^35 bits (i.e., 2^32 bytes). - */ -static const unsigned int MAX_ALEN = UINT32_MAX; - -/* - * max number of generates between re-seeds; - * TinyCrypt accepts up to (2^32 - 1) which is the maximal value of - * a 32-bit unsigned int variable, while SP800-90A specifies a maximum of 2^48. - */ -static const unsigned int MAX_GENS = UINT32_MAX; - -/* - * maximum bytes per generate call; - * SP800-90A specifies a maximum up to 2^19. - */ -static const unsigned int MAX_OUT = (1 << 19); - -/* - * Assumes: prng != NULL, e != NULL, len >= 0. - */ -static void update(TCHmacPrng_t prng, const uint8_t *e, unsigned int len) -{ - const uint8_t separator0 = 0x00; - const uint8_t separator1 = 0x01; - - /* use current state, e and separator 0 to compute a new prng key: */ - (void)tc_hmac_init(&prng->h); - (void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v)); - (void)tc_hmac_update(&prng->h, &separator0, sizeof(separator0)); - (void)tc_hmac_update(&prng->h, e, len); - (void)tc_hmac_final(prng->key, sizeof(prng->key), &prng->h); - /* configure the new prng key into the prng's instance of hmac */ - (void)tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key)); - - /* use the new key to compute a new state variable v */ - (void)tc_hmac_init(&prng->h); - (void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v)); - (void)tc_hmac_final(prng->v, sizeof(prng->v), &prng->h); - - /* use current state, e and separator 1 to compute a new prng key: */ - (void)tc_hmac_init(&prng->h); - (void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v)); - (void)tc_hmac_update(&prng->h, &separator1, sizeof(separator1)); - (void)tc_hmac_update(&prng->h, e, len); - (void)tc_hmac_final(prng->key, sizeof(prng->key), &prng->h); - /* configure the new prng key into the prng's instance of hmac */ - (void)tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key)); - - /* use the new key to compute a new state variable v */ - (void)tc_hmac_init(&prng->h); - (void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v)); - (void)tc_hmac_final(prng->v, sizeof(prng->v), &prng->h); -} - -int tc_hmac_prng_init(TCHmacPrng_t prng, - const uint8_t *personalization, - unsigned int plen) -{ - - /* input sanity check: */ - if (prng == (TCHmacPrng_t) 0 || - personalization == (uint8_t *) 0 || - plen > MAX_PLEN) { - return TC_CRYPTO_FAIL; - } - - /* put the generator into a known state: */ - _set(prng->key, 0x00, sizeof(prng->key)); - _set(prng->v, 0x01, sizeof(prng->v)); - tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key)); - /* update assumes SOME key has been configured into HMAC */ - - update(prng, personalization, plen); - - /* force a reseed before allowing tc_hmac_prng_generate to succeed: */ - prng->countdown = 0; - - return TC_CRYPTO_SUCCESS; -} - -int tc_hmac_prng_reseed(TCHmacPrng_t prng, - const uint8_t *seed, - unsigned int seedlen, - const uint8_t *additional_input, - unsigned int additionallen) -{ - - /* input sanity check: */ - if (prng == (TCHmacPrng_t) 0 || - seed == (const uint8_t *) 0 || - seedlen < MIN_SLEN || - seedlen > MAX_SLEN) { - return TC_CRYPTO_FAIL; - } - - if (additional_input != (const uint8_t *) 0) { - /* - * Abort if additional_input is provided but has inappropriate - * length - */ - if (additionallen == 0 || - additionallen > MAX_ALEN) { - return TC_CRYPTO_FAIL; - } else { - /* call update for the seed and additional_input */ - update(prng, seed, seedlen); - update(prng, additional_input, additionallen); - } - } else { - /* call update only for the seed */ - update(prng, seed, seedlen); - } - - /* ... and enable hmac_prng_generate */ - prng->countdown = MAX_GENS; - - return TC_CRYPTO_SUCCESS; -} - -int tc_hmac_prng_generate(uint8_t *out, unsigned int outlen, TCHmacPrng_t prng) -{ - unsigned int bufferlen; - - /* input sanity check: */ - if (out == (uint8_t *) 0 || - prng == (TCHmacPrng_t) 0 || - outlen == 0 || - outlen > MAX_OUT) { - return TC_CRYPTO_FAIL; - } else if (prng->countdown == 0) { - return TC_HMAC_PRNG_RESEED_REQ; - } - - prng->countdown--; - - while (outlen != 0) { - /* operate HMAC in OFB mode to create "random" outputs */ - (void)tc_hmac_init(&prng->h); - (void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v)); - (void)tc_hmac_final(prng->v, sizeof(prng->v), &prng->h); - - bufferlen = (TC_SHA256_DIGEST_SIZE > outlen) ? - outlen : TC_SHA256_DIGEST_SIZE; - (void)_copy(out, bufferlen, prng->v, bufferlen); - - out += bufferlen; - outlen = (outlen > TC_SHA256_DIGEST_SIZE) ? - (outlen - TC_SHA256_DIGEST_SIZE) : 0; - } - - /* block future PRNG compromises from revealing past state */ - update(prng, prng->v, TC_SHA256_DIGEST_SIZE); - - return TC_CRYPTO_SUCCESS; -} diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/sha256.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/sha256.c deleted file mode 100644 index b7e0bba55..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/sha256.c +++ /dev/null @@ -1,217 +0,0 @@ -/* sha256.c - TinyCrypt SHA-256 crypto hash algorithm implementation */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "../include/tinycrypt/sha256.h" -#include "../include/tinycrypt/constants.h" -#include "../include/tinycrypt/utils.h" - -static void compress(unsigned int *iv, const uint8_t *data); - -int tc_sha256_init(TCSha256State_t s) -{ - /* input sanity check: */ - if (s == (TCSha256State_t) 0) { - return TC_CRYPTO_FAIL; - } - - /* - * Setting the initial state values. - * These values correspond to the first 32 bits of the fractional parts - * of the square roots of the first 8 primes: 2, 3, 5, 7, 11, 13, 17 - * and 19. - */ - _set((uint8_t *) s, 0x00, sizeof(*s)); - s->iv[0] = 0x6a09e667; - s->iv[1] = 0xbb67ae85; - s->iv[2] = 0x3c6ef372; - s->iv[3] = 0xa54ff53a; - s->iv[4] = 0x510e527f; - s->iv[5] = 0x9b05688c; - s->iv[6] = 0x1f83d9ab; - s->iv[7] = 0x5be0cd19; - - return TC_CRYPTO_SUCCESS; -} - -int tc_sha256_update(TCSha256State_t s, const uint8_t *data, size_t datalen) -{ - /* input sanity check: */ - if (s == (TCSha256State_t) 0 || - data == (void *) 0) { - return TC_CRYPTO_FAIL; - } else if (datalen == 0) { - return TC_CRYPTO_SUCCESS; - } - - while (datalen-- > 0) { - s->leftover[s->leftover_offset++] = *(data++); - if (s->leftover_offset >= TC_SHA256_BLOCK_SIZE) { - compress(s->iv, s->leftover); - s->leftover_offset = 0; - s->bits_hashed += (TC_SHA256_BLOCK_SIZE << 3); - } - } - - return TC_CRYPTO_SUCCESS; -} - -int tc_sha256_final(uint8_t *digest, TCSha256State_t s) -{ - unsigned int i; - - /* input sanity check: */ - if (digest == (uint8_t *) 0 || - s == (TCSha256State_t) 0) { - return TC_CRYPTO_FAIL; - } - - s->bits_hashed += (s->leftover_offset << 3); - - s->leftover[s->leftover_offset++] = 0x80; /* always room for one byte */ - if (s->leftover_offset > (sizeof(s->leftover) - 8)) { - /* there is not room for all the padding in this block */ - _set(s->leftover + s->leftover_offset, 0x00, - sizeof(s->leftover) - s->leftover_offset); - compress(s->iv, s->leftover); - s->leftover_offset = 0; - } - - /* add the padding and the length in big-Endian format */ - _set(s->leftover + s->leftover_offset, 0x00, - sizeof(s->leftover) - 8 - s->leftover_offset); - s->leftover[sizeof(s->leftover) - 1] = (uint8_t)(s->bits_hashed); - s->leftover[sizeof(s->leftover) - 2] = (uint8_t)(s->bits_hashed >> 8); - s->leftover[sizeof(s->leftover) - 3] = (uint8_t)(s->bits_hashed >> 16); - s->leftover[sizeof(s->leftover) - 4] = (uint8_t)(s->bits_hashed >> 24); - s->leftover[sizeof(s->leftover) - 5] = (uint8_t)(s->bits_hashed >> 32); - s->leftover[sizeof(s->leftover) - 6] = (uint8_t)(s->bits_hashed >> 40); - s->leftover[sizeof(s->leftover) - 7] = (uint8_t)(s->bits_hashed >> 48); - s->leftover[sizeof(s->leftover) - 8] = (uint8_t)(s->bits_hashed >> 56); - - /* hash the padding and length */ - compress(s->iv, s->leftover); - - /* copy the iv out to digest */ - for (i = 0; i < TC_SHA256_STATE_BLOCKS; ++i) { - unsigned int t = *((unsigned int *) &s->iv[i]); - *digest++ = (uint8_t)(t >> 24); - *digest++ = (uint8_t)(t >> 16); - *digest++ = (uint8_t)(t >> 8); - *digest++ = (uint8_t)(t); - } - - /* destroy the current state */ - _set(s, 0, sizeof(*s)); - - return TC_CRYPTO_SUCCESS; -} - -/* - * Initializing SHA-256 Hash constant words K. - * These values correspond to the first 32 bits of the fractional parts of the - * cube roots of the first 64 primes between 2 and 311. - */ -static const unsigned int k256[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, - 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, - 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, - 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, - 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, - 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; - -static inline unsigned int ROTR(unsigned int a, unsigned int n) -{ - return (((a) >> n) | ((a) << (32 - n))); -} - -#define Sigma0(a)(ROTR((a), 2) ^ ROTR((a), 13) ^ ROTR((a), 22)) -#define Sigma1(a)(ROTR((a), 6) ^ ROTR((a), 11) ^ ROTR((a), 25)) -#define sigma0(a)(ROTR((a), 7) ^ ROTR((a), 18) ^ ((a) >> 3)) -#define sigma1(a)(ROTR((a), 17) ^ ROTR((a), 19) ^ ((a) >> 10)) - -#define Ch(a, b, c)(((a) & (b)) ^ ((~(a)) & (c))) -#define Maj(a, b, c)(((a) & (b)) ^ ((a) & (c)) ^ ((b) & (c))) - -static inline unsigned int BigEndian(const uint8_t **c) -{ - unsigned int n = 0; - - n = (((unsigned int)(*((*c)++))) << 24); - n |= ((unsigned int)(*((*c)++)) << 16); - n |= ((unsigned int)(*((*c)++)) << 8); - n |= ((unsigned int)(*((*c)++))); - return n; -} - -static void compress(unsigned int *iv, const uint8_t *data) -{ - unsigned int a, b, c, d, e, f, g, h; - unsigned int s0, s1; - unsigned int t1, t2; - unsigned int work_space[16]; - unsigned int n; - unsigned int i; - - a = iv[0]; b = iv[1]; c = iv[2]; d = iv[3]; - e = iv[4]; f = iv[5]; g = iv[6]; h = iv[7]; - - for (i = 0; i < 16; ++i) { - n = BigEndian(&data); - t1 = work_space[i] = n; - t1 += h + Sigma1(e) + Ch(e, f, g) + k256[i]; - t2 = Sigma0(a) + Maj(a, b, c); - h = g; g = f; f = e; e = d + t1; - d = c; c = b; b = a; a = t1 + t2; - } - - for ( ; i < 64; ++i) { - s0 = work_space[(i+1)&0x0f]; - s0 = sigma0(s0); - s1 = work_space[(i+14)&0x0f]; - s1 = sigma1(s1); - - t1 = work_space[i&0xf] += s0 + s1 + work_space[(i+9)&0xf]; - t1 += h + Sigma1(e) + Ch(e, f, g) + k256[i]; - t2 = Sigma0(a) + Maj(a, b, c); - h = g; g = f; f = e; e = d + t1; - d = c; c = b; b = a; a = t1 + t2; - } - - iv[0] += a; iv[1] += b; iv[2] += c; iv[3] += d; - iv[4] += e; iv[5] += f; iv[6] += g; iv[7] += h; -} diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/utils.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/utils.c deleted file mode 100644 index 792a78178..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/utils.c +++ /dev/null @@ -1,74 +0,0 @@ -/* utils.c - TinyCrypt platform-dependent run-time operations */ - -/* - * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "../include/tinycrypt/utils.h" -#include "../include/tinycrypt/constants.h" - -#include - -#define MASK_TWENTY_SEVEN 0x1b - -unsigned int _copy(uint8_t *to, unsigned int to_len, - const uint8_t *from, unsigned int from_len) -{ - if (from_len <= to_len) { - (void)memcpy(to, from, from_len); - return from_len; - } else { - return TC_CRYPTO_FAIL; - } -} - -void _set(void *to, uint8_t val, unsigned int len) -{ - (void)memset(to, val, len); -} - -/* - * Doubles the value of a byte for values up to 127. - */ -uint8_t _double_byte(uint8_t a) -{ - return ((a<<1) ^ ((a>>7) * MASK_TWENTY_SEVEN)); -} - -int _compare(const uint8_t *a, const uint8_t *b, size_t size) -{ - const uint8_t *tempa = a; - const uint8_t *tempb = b; - uint8_t result = 0; - - for (unsigned int i = 0; i < size; i++) { - result |= tempa[i] ^ tempb[i]; - } - return result; -} diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_hw.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_hw.h deleted file mode 100644 index dfac69b60..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_hw.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_HW_ -#define H_BLE_HW_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" - -#if defined(ARCH_sim) -#define BLE_USES_HW_WHITELIST (0) -#else -#define BLE_USES_HW_WHITELIST MYNEWT_VAL(BLE_HW_WHITELIST_ENABLE) -#endif - -/* Returns the number of hw whitelist elements */ -uint8_t ble_hw_whitelist_size(void); - -/* Clear the whitelist */ -void ble_hw_whitelist_clear(void); - -/* Remove a device from the hw whitelist */ -void ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type); - -/* Add a device to the hw whitelist */ -int ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type); - -/* Enable hw whitelisting */ -void ble_hw_whitelist_enable(void); - -/* Enable hw whitelisting */ -void ble_hw_whitelist_disable(void); - -/* Boolean function returning true if address matches a whitelist entry */ -int ble_hw_whitelist_match(void); - -/* Encrypt data */ -struct ble_encryption_block; -int ble_hw_encrypt_block(struct ble_encryption_block *ecb); - -/* Random number generation */ -typedef void (*ble_rng_isr_cb_t)(uint8_t rnum); -int ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias); - -/** - * Start the random number generator - * - * @return int - */ -int ble_hw_rng_start(void); - -/** - * Stop the random generator - * - * @return int - */ -int ble_hw_rng_stop(void); - -/** - * Read the random number generator. - * - * @return uint8_t - */ -uint8_t ble_hw_rng_read(void); - -/* Clear the resolving list*/ -void ble_hw_resolv_list_clear(void); - -/* Add a device to the hw resolving list */ -int ble_hw_resolv_list_add(uint8_t *irk); - -/* Remove a device from the hw resolving list */ -void ble_hw_resolv_list_rmv(int index); - -/* Returns the size of the whitelist in HW */ -uint8_t ble_hw_resolv_list_size(void); - -/* Enable the resolving list */ -void ble_hw_resolv_list_enable(void); - -/* Disables resolving list devices */ -void ble_hw_resolv_list_disable(void); - -/* Returns index of resolved address; -1 if not resolved */ -int ble_hw_resolv_list_match(void); - -/* Returns public device address or -1 if not present */ -int ble_hw_get_public_addr(ble_addr_t *addr); - -/* Returns random static address or -1 if not present */ -int ble_hw_get_static_addr(ble_addr_t *addr); - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_HW_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll.h deleted file mode 100644 index a289ed00b..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll.h +++ /dev/null @@ -1,622 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_ -#define H_BLE_LL_ - -#include "nimble/porting/nimble/include/stats/stats.h" -#include "nimble/porting/nimble/include/os/os_cputime.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "nimble/nimble/include/nimble/nimble_npl.h" -#include "ble_phy.h" - -#ifdef MYNEWT -#include "./ble_ll_ctrl.h" -#include "hal/hal_system.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768 -#error 32.768kHz clock required -#endif - -#if defined(MYNEWT) && MYNEWT_VAL(BLE_LL_VND_EVENT_ON_ASSERT) -#ifdef NDEBUG -#define BLE_LL_ASSERT(cond) (void(0)) -#else -#define BLE_LL_ASSERT(cond) \ - if (!(cond)) { \ - if (hal_debugger_connected()) { \ - assert(0);\ - } else {\ - ble_ll_hci_ev_send_vendor_err(__FILE__, __LINE__); \ - while(1) {}\ - }\ - } -#endif -#else -#define BLE_LL_ASSERT(cond) assert(cond) -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) -#define BLE_LL_BT5_PHY_SUPPORTED (1) -#else -#define BLE_LL_BT5_PHY_SUPPORTED (0) -#endif - -/* Controller revision. */ -#define BLE_LL_SUB_VERS_NR (0x0000) - -/* Timing jitter as per spec is +/16 usecs */ -#define BLE_LL_JITTER_USECS (16) - - -#if MYNEWT_VAL(BLE_LL_SCA) < 0 -#error Invalid SCA value -#elif MYNEWT_VAL(BLE_LL_SCA) <= 20 -#define BLE_LL_SCA_ENUM 7 -#elif MYNEWT_VAL(BLE_LL_SCA) <= 30 -#define BLE_LL_SCA_ENUM 6 -#elif MYNEWT_VAL(BLE_LL_SCA) <= 50 -#define BLE_LL_SCA_ENUM 5 -#elif MYNEWT_VAL(BLE_LL_SCA) <= 75 -#define BLE_LL_SCA_ENUM 4 -#elif MYNEWT_VAL(BLE_LL_SCA) <= 100 -#define BLE_LL_SCA_ENUM 3 -#elif MYNEWT_VAL(BLE_LL_SCA) <= 150 -#define BLE_LL_SCA_ENUM 2 -#elif MYNEWT_VAL(BLE_LL_SCA) <= 250 -#define BLE_LL_SCA_ENUM 1 -#elif MYNEWT_VAL(BLE_LL_SCA) <= 500 -#define BLE_LL_SCA_ENUM 0 -#else -#error Invalid SCA value -#endif - -/* Packet queue header definition */ -STAILQ_HEAD(ble_ll_pkt_q, os_mbuf_pkthdr); - -/* - * Global Link Layer data object. There is only one Link Layer data object - * per controller although there may be many instances of the link layer state - * machine running. - */ -struct ble_ll_obj -{ - /* Supported features */ - uint64_t ll_supp_features; - - /* Current Link Layer state */ - uint8_t ll_state; - - /* Number of ACL data packets supported */ - uint8_t ll_num_acl_pkts; - - /* ACL data packet size */ - uint16_t ll_acl_pkt_size; - - /* Preferred PHY's */ - uint8_t ll_pref_tx_phys; - uint8_t ll_pref_rx_phys; - - /* Task event queue */ - struct ble_npl_eventq ll_evq; - - /* Wait for response timer */ - struct hal_timer ll_wfr_timer; - - /* Packet receive queue (and event). Holds received packets from PHY */ - struct ble_npl_event ll_rx_pkt_ev; - struct ble_ll_pkt_q ll_rx_pkt_q; - - /* Packet transmit queue */ - struct ble_npl_event ll_tx_pkt_ev; - struct ble_ll_pkt_q ll_tx_pkt_q; - - /* Data buffer overflow event */ - struct ble_npl_event ll_dbuf_overflow_ev; - - /* Number of completed packets event */ - struct ble_npl_event ll_comp_pkt_ev; - - /* HW error callout */ - struct ble_npl_callout ll_hw_err_timer; -}; -extern struct ble_ll_obj g_ble_ll_data; - -/* Link layer statistics */ -STATS_SECT_START(ble_ll_stats) - STATS_SECT_ENTRY(hci_cmds) - STATS_SECT_ENTRY(hci_cmd_errs) - STATS_SECT_ENTRY(hci_events_sent) - STATS_SECT_ENTRY(bad_ll_state) - STATS_SECT_ENTRY(bad_acl_hdr) - STATS_SECT_ENTRY(no_bufs) - STATS_SECT_ENTRY(rx_adv_pdu_crc_ok) - STATS_SECT_ENTRY(rx_adv_pdu_crc_err) - STATS_SECT_ENTRY(rx_adv_bytes_crc_ok) - STATS_SECT_ENTRY(rx_adv_bytes_crc_err) - STATS_SECT_ENTRY(rx_data_pdu_crc_ok) - STATS_SECT_ENTRY(rx_data_pdu_crc_err) - STATS_SECT_ENTRY(rx_data_bytes_crc_ok) - STATS_SECT_ENTRY(rx_data_bytes_crc_err) - STATS_SECT_ENTRY(rx_adv_malformed_pkts) - STATS_SECT_ENTRY(rx_adv_ind) - STATS_SECT_ENTRY(rx_adv_direct_ind) - STATS_SECT_ENTRY(rx_adv_nonconn_ind) - STATS_SECT_ENTRY(rx_adv_ext_ind) - STATS_SECT_ENTRY(rx_scan_reqs) - STATS_SECT_ENTRY(rx_scan_rsps) - STATS_SECT_ENTRY(rx_connect_reqs) - STATS_SECT_ENTRY(rx_scan_ind) - STATS_SECT_ENTRY(rx_aux_connect_rsp) - STATS_SECT_ENTRY(adv_txg) - STATS_SECT_ENTRY(adv_late_starts) - STATS_SECT_ENTRY(adv_resched_pdu_fail) - STATS_SECT_ENTRY(adv_drop_event) - STATS_SECT_ENTRY(sched_state_conn_errs) - STATS_SECT_ENTRY(sched_state_adv_errs) - STATS_SECT_ENTRY(scan_starts) - STATS_SECT_ENTRY(scan_stops) - STATS_SECT_ENTRY(scan_req_txf) - STATS_SECT_ENTRY(scan_req_txg) - STATS_SECT_ENTRY(scan_rsp_txg) - STATS_SECT_ENTRY(aux_missed_adv) - STATS_SECT_ENTRY(aux_scheduled) - STATS_SECT_ENTRY(aux_received) - STATS_SECT_ENTRY(aux_fired_for_read) - STATS_SECT_ENTRY(aux_allocated) - STATS_SECT_ENTRY(aux_freed) - STATS_SECT_ENTRY(aux_sched_cb) - STATS_SECT_ENTRY(aux_conn_req_tx) - STATS_SECT_ENTRY(aux_conn_rsp_tx) - STATS_SECT_ENTRY(aux_conn_rsp_err) - STATS_SECT_ENTRY(aux_scan_req_tx) - STATS_SECT_ENTRY(aux_scan_rsp_err) - STATS_SECT_ENTRY(aux_chain_cnt) - STATS_SECT_ENTRY(aux_chain_err) - STATS_SECT_ENTRY(aux_scan_drop) - STATS_SECT_ENTRY(adv_evt_dropped) - STATS_SECT_ENTRY(scan_timer_stopped) - STATS_SECT_ENTRY(scan_timer_restarted) - STATS_SECT_ENTRY(periodic_adv_drop_event) - STATS_SECT_ENTRY(periodic_chain_drop_event) - STATS_SECT_ENTRY(sync_event_failed) - STATS_SECT_ENTRY(sync_received) - STATS_SECT_ENTRY(sync_chain_failed) - STATS_SECT_ENTRY(sync_missed_err) - STATS_SECT_ENTRY(sync_crc_err) - STATS_SECT_ENTRY(sync_rx_buf_err) - STATS_SECT_ENTRY(sync_scheduled) - STATS_SECT_ENTRY(sched_state_sync_errs) - STATS_SECT_ENTRY(sched_invalid_pdu) -STATS_SECT_END -extern STATS_SECT_DECL(ble_ll_stats) ble_ll_stats; - -/* States */ -#define BLE_LL_STATE_STANDBY (0) -#define BLE_LL_STATE_ADV (1) -#define BLE_LL_STATE_SCANNING (2) -#define BLE_LL_STATE_INITIATING (3) -#define BLE_LL_STATE_CONNECTION (4) -#define BLE_LL_STATE_DTM (5) -#define BLE_LL_STATE_SYNC (6) - -/* LL Features */ -#define BLE_LL_FEAT_LE_ENCRYPTION (0x0000000001) -#define BLE_LL_FEAT_CONN_PARM_REQ (0x0000000002) -#define BLE_LL_FEAT_EXTENDED_REJ (0x0000000004) -#define BLE_LL_FEAT_SLAVE_INIT (0x0000000008) -#define BLE_LL_FEAT_LE_PING (0x0000000010) -#define BLE_LL_FEAT_DATA_LEN_EXT (0x0000000020) -#define BLE_LL_FEAT_LL_PRIVACY (0x0000000040) -#define BLE_LL_FEAT_EXT_SCAN_FILT (0x0000000080) -#define BLE_LL_FEAT_LE_2M_PHY (0x0000000100) -#define BLE_LL_FEAT_STABLE_MOD_ID_TX (0x0000000200) -#define BLE_LL_FEAT_STABLE_MOD_ID_RX (0x0000000400) -#define BLE_LL_FEAT_LE_CODED_PHY (0x0000000800) -#define BLE_LL_FEAT_EXT_ADV (0x0000001000) -#define BLE_LL_FEAT_PERIODIC_ADV (0x0000002000) -#define BLE_LL_FEAT_CSA2 (0x0000004000) -#define BLE_LL_FEAT_LE_POWER_CLASS_1 (0x0000008000) -#define BLE_LL_FEAT_MIN_USED_CHAN (0x0000010000) -#define BLE_LL_FEAT_CTE_REQ (0x0000020000) -#define BLE_LL_FEAT_CTE_RSP (0x0000040000) -#define BLE_LL_FEAT_CTE_TX (0x0000080000) -#define BLE_LL_FEAT_CTE_RX (0x0000100000) -#define BLE_LL_FEAT_CTE_AOD (0x0000200000) -#define BLE_LL_FEAT_CTE_AOA (0x0000400000) -#define BLE_LL_FEAT_CTE_RECV (0x0000800000) -#define BLE_LL_FEAT_SYNC_TRANS_SEND (0x0001000000) -#define BLE_LL_FEAT_SYNC_TRANS_RECV (0x0002000000) -#define BLE_LL_FEAT_SCA_UPDATE (0x0004000000) -#define BLE_LL_FEAT_REM_PKEY (0x0008000000) -#define BLE_LL_FEAT_CIS_MASTER (0x0010000000) -#define BLE_LL_FEAT_CIS_SLAVE (0x0020000000) -#define BLE_LL_FEAT_ISO_BROADCASTER (0x0040000000) -#define BLE_LL_FEAT_SYNC_RECV (0x0080000000) -#define BLE_LL_FEAT_ISO_HOST_SUPPORT (0x0100000000) -#define BLE_LL_FEAT_POWER_CTRL_REQ (0x0200000000) -#define BLE_LL_FEAT_POWER_CHANGE_IND (0x0400000000) -#define BLE_LL_FEAT_PATH_LOSS_MON (0x0800000000) - -/* This is initial mask, so if feature exchange will not happen, - * but host will want to use this procedure, we will try. If not - * succeed, feature bit will be cleared. - * Look at LL Features above to find out what is allowed - */ -#define BLE_LL_CONN_INITIAL_FEATURES (0x00000022) -#define BLE_LL_CONN_CLEAR_FEATURE(connsm, feature) (connsm->conn_features &= ~(feature)) - -/* All the features which can be controlled by the Host */ -#define BLE_LL_HOST_CONTROLLED_FEATURES (BLE_LL_FEAT_ISO_HOST_SUPPORT) - -/* LL timing */ -#define BLE_LL_IFS (150) /* usecs */ -#define BLE_LL_MAFS (300) /* usecs */ - -/* - * BLE LL device address. Note that element 0 of the array is the LSB and - * is sent over the air first. Byte 5 is the MSB and is the last one sent over - * the air. - */ -#define BLE_DEV_ADDR_LEN (6) /* bytes */ - -struct ble_dev_addr -{ - uint8_t u8[BLE_DEV_ADDR_LEN]; -}; - -#define BLE_IS_DEV_ADDR_STATIC(addr) ((addr->u8[5] & 0xc0) == 0xc0) -#define BLE_IS_DEV_ADDR_RESOLVABLE(addr) ((addr->u8[5] & 0xc0) == 0x40) -#define BLE_IS_DEV_ADDR_UNRESOLVABLE(addr) ((addr->u8[5] & 0xc0) == 0x00) - -/* - * LL packet format - * - * -> Preamble (1/2 bytes) - * -> Access Address (4 bytes) - * -> PDU (2 to 257 octets) - * -> CRC (3 bytes) - */ -#define BLE_LL_PREAMBLE_LEN (1) -#define BLE_LL_ACC_ADDR_LEN (4) -#define BLE_LL_CRC_LEN (3) -#define BLE_LL_PDU_HDR_LEN (2) -#define BLE_LL_MAX_PAYLOAD_LEN (255) -#define BLE_LL_MIN_PDU_LEN (BLE_LL_PDU_HDR_LEN) -#define BLE_LL_MAX_PDU_LEN ((BLE_LL_PDU_HDR_LEN) + (BLE_LL_MAX_PAYLOAD_LEN)) -#define BLE_LL_CRCINIT_ADV (0x555555) - -/* Access address for advertising channels */ -#define BLE_ACCESS_ADDR_ADV (0x8E89BED6) - -/* - * Advertising PDU format: - * -> 2 byte header - * -> LSB contains pdu type, txadd and rxadd bits. - * -> MSB contains length (6 bits). Length is length of payload. Does - * not include the header length itself. - * -> Payload (max 37 bytes) - */ -#define BLE_ADV_PDU_HDR_TYPE_MASK (0x0F) -#define BLE_ADV_PDU_HDR_CHSEL_MASK (0x20) -#define BLE_ADV_PDU_HDR_TXADD_MASK (0x40) -#define BLE_ADV_PDU_HDR_RXADD_MASK (0x80) - -/* Advertising channel PDU types */ -#define BLE_ADV_PDU_TYPE_ADV_IND (0) -#define BLE_ADV_PDU_TYPE_ADV_DIRECT_IND (1) -#define BLE_ADV_PDU_TYPE_ADV_NONCONN_IND (2) -#define BLE_ADV_PDU_TYPE_SCAN_REQ (3) -#define BLE_ADV_PDU_TYPE_SCAN_RSP (4) -#define BLE_ADV_PDU_TYPE_CONNECT_IND (5) -#define BLE_ADV_PDU_TYPE_ADV_SCAN_IND (6) -#define BLE_ADV_PDU_TYPE_ADV_EXT_IND (7) -#define BLE_ADV_PDU_TYPE_AUX_ADV_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND -#define BLE_ADV_PDU_TYPE_AUX_SCAN_RSP BLE_ADV_PDU_TYPE_ADV_EXT_IND -#define BLE_ADV_PDU_TYPE_AUX_SYNC_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND -#define BLE_ADV_PDU_TYPE_AUX_CHAIN_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND -#define BLE_ADV_PDU_TYPE_AUX_CONNECT_REQ BLE_ADV_PDU_TYPE_CONNECT_IND -#define BLE_ADV_PDU_TYPE_AUX_SCAN_REQ BLE_ADV_PDU_TYPE_SCAN_REQ -#define BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP (8) - -/* Extended Header Length (6b) + AdvMode (2b) */ -#define BLE_LL_EXT_ADV_HDR_LEN (1) - -#define BLE_LL_EXT_ADV_ADVA_BIT (0) -#define BLE_LL_EXT_ADV_TARGETA_BIT (1) -#define BLE_LL_EXT_ADV_CTE_INFO_BIT (2) -#define BLE_LL_EXT_ADV_DATA_INFO_BIT (3) -#define BLE_LL_EXT_ADV_AUX_PTR_BIT (4) -#define BLE_LL_EXT_ADV_SYNC_INFO_BIT (5) -#define BLE_LL_EXT_ADV_TX_POWER_BIT (6) - -#define BLE_LL_EXT_ADV_FLAGS_SIZE (1) -#define BLE_LL_EXT_ADV_ADVA_SIZE (6) -#define BLE_LL_EXT_ADV_TARGETA_SIZE (6) -#define BLE_LL_EXT_ADV_DATA_INFO_SIZE (2) -#define BLE_LL_EXT_ADV_AUX_PTR_SIZE (3) -#define BLE_LL_EXT_ADV_SYNC_INFO_SIZE (18) -#define BLE_LL_EXT_ADV_TX_POWER_SIZE (1) - -#define BLE_LL_EXT_ADV_MODE_NON_CONN (0x00) -#define BLE_LL_EXT_ADV_MODE_CONN (0x01) -#define BLE_LL_EXT_ADV_MODE_SCAN (0x02) - -/* If Channel Selection Algorithm #2 is supported */ -#define BLE_ADV_PDU_HDR_CHSEL (0x20) - -/* - * TxAdd and RxAdd bit definitions. A 0 is a public address; a 1 is a - * random address. - */ -#define BLE_ADV_PDU_HDR_TXADD_RAND (0x40) -#define BLE_ADV_PDU_HDR_RXADD_RAND (0x80) - -/* - * Data Channel format - * - * -> Header (2 bytes) - * -> LSB contains llid, nesn, sn and md - * -> MSB contains length (8 bits) - * -> Payload (0 to 251) - * -> MIC (0 or 4 bytes) - */ -#define BLE_LL_DATA_HDR_LLID_MASK (0x03) -#define BLE_LL_DATA_HDR_NESN_MASK (0x04) -#define BLE_LL_DATA_HDR_SN_MASK (0x08) -#define BLE_LL_DATA_HDR_MD_MASK (0x10) -#define BLE_LL_DATA_HDR_RSRVD_MASK (0xE0) -#define BLE_LL_DATA_PDU_MAX_PYLD (251) -#define BLE_LL_DATA_MIC_LEN (4) - -/* LLID definitions */ -#define BLE_LL_LLID_RSRVD (0) -#define BLE_LL_LLID_DATA_FRAG (1) -#define BLE_LL_LLID_DATA_START (2) -#define BLE_LL_LLID_CTRL (3) - -#define BLE_LL_LLID_IS_CTRL(hdr) \ - (((hdr) & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) -#define BLE_LL_LLID_IS_DATA(hdr) \ - ((((hdr) & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_DATA_START) || \ - (((hdr) & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_DATA_FRAG)) - -/* - * CONNECT_REQ - * -> InitA (6 bytes) - * -> AdvA (6 bytes) - * -> LLData (22 bytes) - * -> Access address (4 bytes) - * -> CRC init (3 bytes) - * -> WinSize (1 byte) - * -> WinOffset (2 bytes) - * -> Interval (2 bytes) - * -> Latency (2 bytes) - * -> Timeout (2 bytes) - * -> Channel Map (5 bytes) - * -> Hop Increment (5 bits) - * -> SCA (3 bits) - * - * InitA is the initiators public (TxAdd=0) or random (TxAdd=1) address. - * AdvaA is the advertisers public (RxAdd=0) or random (RxAdd=1) address. - * LLData contains connection request data. - * aa: Link Layer's access address - * crc_init: The CRC initialization value used for CRC calculation. - * winsize: The transmit window size = winsize * 1.25 msecs - * winoffset: The transmit window offset = winoffset * 1.25 msecs - * interval: The connection interval = interval * 1.25 msecs. - * latency: connection slave latency = latency - * timeout: Connection supervision timeout = timeout * 10 msecs. - * chanmap: contains channel mapping indicating used and unused data - * channels. Only bits that are 1 are usable. LSB is channel 0. - * hop_inc: Hop increment used for frequency hopping. Random value in - * range of 5 to 16. - */ -#define BLE_CONNECT_REQ_LEN (34) -#define BLE_CONNECT_REQ_PDU_LEN (BLE_CONNECT_REQ_LEN + BLE_LL_PDU_HDR_LEN) - -#define BLE_SCAN_REQ_LEN (12) -#define BLE_SCAN_RSP_MAX_LEN (37) -#define BLE_SCAN_RSP_MAX_EXT_LEN (251) - -#define BLE_LL_ADDR_SUBTYPE_IDENTITY (0) -#define BLE_LL_ADDR_SUBTYPE_RPA (1) -#define BLE_LL_ADDR_SUBTYPE_NRPA (2) - -/* ACAD data types */ -#define BLE_LL_ACAD_CHANNEL_MAP_UPDATE_IND 0x28 - -struct ble_ll_acad_channel_map_update_ind { - uint8_t map[5]; - uint16_t instant; -} __attribute__((packed)); - -/*--- External API ---*/ -/* Initialize the Link Layer */ -void ble_ll_init(void); - -/* Reset the Link Layer */ -int ble_ll_reset(void); - -int ble_ll_is_valid_public_addr(const uint8_t *addr); - -/* 'Boolean' function returning true if address is a valid random address */ -int ble_ll_is_valid_random_addr(const uint8_t *addr); - -/* - * Check if given own_addr_type is valid for current controller configuration - * given the random address provided (when applicable) - */ -int ble_ll_is_valid_own_addr_type(uint8_t own_addr_type, - const uint8_t *random_addr); - -/* Calculate the amount of time in microseconds a PDU with payload length of - * 'payload_len' will take to transmit on a PHY 'phy_mode'. */ -uint32_t ble_ll_pdu_tx_time_get(uint16_t payload_len, int phy_mode); - -/* Calculate maximum octets of PDU payload which can be transmitted during - * 'usecs' on a PHY 'phy_mode'. */ -uint16_t ble_ll_pdu_max_tx_octets_get(uint32_t usecs, int phy_mode); - -/* Is this address a resolvable private address? */ -int ble_ll_is_rpa(const uint8_t *addr, uint8_t addr_type); - -int ble_ll_addr_subtype(const uint8_t *addr, uint8_t addr_type); - -/* Is this address an identity address? */ -int ble_ll_addr_is_id(uint8_t *addr, uint8_t addr_type); - -/* Is 'addr' our device address? 'addr_type' is public (0) or random (!=0) */ -int ble_ll_is_our_devaddr(uint8_t *addr, int addr_type); - -/* Get identity address 'addr_type' is public (0) or random (!=0) */ -uint8_t *ble_ll_get_our_devaddr(uint8_t addr_type); - -/** - * Called to put a packet on the Link Layer transmit packet queue. - * - * @param txpdu Pointer to transmit packet - */ -void ble_ll_acl_data_in(struct os_mbuf *txpkt); - -/** - * Allocates mbuf for received PDU - * - * This allocated mbuf (may be chained if necessary) that has capacity large - * enough to store received PDU of given length. It does not set mbufs length - * as this has to be done by PHY when copying data. - * - * @param len Length of PDU, including PDU header and excluding MIC (if encrypted) - * - * @return mbuf large enough to store received PDU on success - * NULL on failure (oom) - */ -struct os_mbuf *ble_ll_rxpdu_alloc(uint16_t len); - -/* Tell the Link Layer there has been a data buffer overflow */ -void ble_ll_data_buffer_overflow(void); - -/* Tell the link layer there has been a hardware error */ -void ble_ll_hw_error(void); - -/*--- PHY interfaces ---*/ -struct ble_mbuf_hdr; - -/* Called by the PHY when a packet has started */ -int ble_ll_rx_start(uint8_t *rxbuf, uint8_t chan, struct ble_mbuf_hdr *hdr); - -/* Called by the PHY when a packet reception ends */ -int ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr); - -/* Helper callback to tx mbuf using ble_phy_tx() */ -uint8_t ble_ll_tx_mbuf_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte); -uint8_t ble_ll_tx_flat_mbuf_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte); - -/*--- Controller API ---*/ -void ble_ll_mbuf_init(struct os_mbuf *m, uint8_t pdulen, uint8_t hdr); - -/* Set the link layer state */ -void ble_ll_state_set(uint8_t ll_state); - -/* Get the link layer state */ -uint8_t ble_ll_state_get(void); - -/* Send an event to LL task */ -void ble_ll_event_send(struct ble_npl_event *ev); - -/* Hand received pdu's to LL task */ -void ble_ll_rx_pdu_in(struct os_mbuf *rxpdu); - -/* - * Set public address - * - * This can be used to set controller public address from vendor specific storage, - * usually should be done in hal_bsp_init(). - * Shall be *only* called before LL is initialized, i.e. before sysinit stage. - */ -int ble_ll_set_public_addr(const uint8_t *addr); - -/* Set random address */ -int ble_ll_set_random_addr(const uint8_t *cmdbuf, uint8_t len, bool hci_adv_ext); - -/* Wait for response timer expiration callback */ -void ble_ll_wfr_timer_exp(void *arg); - -/* Read set of features supported by the Link Layer */ -uint64_t ble_ll_read_supp_features(void); - -/* Set host supported features */ -int ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len); - -/* Read set of states supported by the Link Layer */ -uint64_t ble_ll_read_supp_states(void); - -/* Check if octets and time are valid. Returns 0 if not valid */ -int ble_ll_chk_txrx_octets(uint16_t octets); -int ble_ll_chk_txrx_time(uint16_t time); - -/* Random numbers */ -int ble_ll_rand_init(void); -void ble_ll_rand_sample(uint8_t rnum); -int ble_ll_rand_data_get(uint8_t *buf, uint8_t len); -void ble_ll_rand_prand_get(uint8_t *prand); -int ble_ll_rand_start(void); -uint32_t ble_ll_rand(void); - -static inline int -ble_ll_get_addr_type(uint8_t txrxflag) -{ - if (txrxflag) { - return BLE_HCI_ADV_OWN_ADDR_RANDOM; - } - return BLE_HCI_ADV_OWN_ADDR_PUBLIC; -} - -/* Convert usecs to ticks and round up to nearest tick */ -static inline uint32_t -ble_ll_usecs_to_ticks_round_up(uint32_t usecs) -{ - return os_cputime_usecs_to_ticks(usecs + 30); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/* LTK 0x4C68384139F574D836BCF34E9DFB01BF */ -extern const uint8_t g_bletest_LTK[]; -extern uint16_t g_bletest_EDIV; -extern uint64_t g_bletest_RAND; -extern uint64_t g_bletest_SKDm; -extern uint64_t g_bletest_SKDs; -extern uint32_t g_bletest_IVm; -extern uint32_t g_bletest_IVs; -#endif - -#if MYNEWT_VAL(BLE_LL_DTM) -void ble_ll_dtm_init(void); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* H_LL_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_adv.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_adv.h deleted file mode 100644 index eee07cbf0..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_adv.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_ADV_ -#define H_BLE_LL_ADV_ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * ADV event timing - * T_advEvent = advInterval + advDelay - * - * advInterval: increments of 625 usecs - * advDelay: RAND[0, 10] msecs - * - */ -#define BLE_LL_ADV_ITVL (625) /* usecs */ -#define BLE_LL_ADV_ITVL_MIN (32) /* units */ -#define BLE_LL_ADV_ITVL_MAX (16384) /* units */ -#define BLE_LL_ADV_ITVL_MS_MIN (20) /* msecs */ -#define BLE_LL_ADV_ITVL_MS_MAX (10240) /* msecs */ -#define BLE_LL_ADV_ITVL_SCAN_MIN (160) /* units */ -#define BLE_LL_ADV_ITVL_SCAN_MS_MIN (100) /* msecs */ -#define BLE_LL_ADV_ITVL_NONCONN_MS_MIN (100) /* msecs */ -#define BLE_LL_ADV_DELAY_MS_MIN (0) /* msecs */ -#define BLE_LL_ADV_DELAY_MS_MAX (10) /* msecs */ -#define BLE_LL_ADV_PDU_ITVL_LD_MS_MAX (10) /* msecs */ -#define BLE_LL_ADV_PDU_ITVL_HD_MS_MAX (3750) /* usecs */ -#define BLE_LL_ADV_STATE_HD_MAX (1280) /* msecs */ -#define BLE_LL_ADV_PERIODIC_ITVL (1250) /* usecs */ - -/* Maximum advertisement data length */ -#define BLE_ADV_LEGACY_DATA_MAX_LEN (31) -#define BLE_ADV_LEGACY_MAX_PKT_LEN (37) - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#define BLE_ADV_DATA_MAX_LEN MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) -#else -#define BLE_ADV_DATA_MAX_LEN BLE_ADV_LEGACY_DATA_MAX_LEN -#endif - -/* - * ADV_IND - * -> AdvA (6 bytes) - * -> AdvData (0 - 31 bytes) - * - * The advertising address (AdvA) is a public address (TxAdd=0) or random - * address (TxAdd = 1) - */ -#define BLE_ADV_IND_MIN_LEN (6) -#define BLE_ADV_IND_MAX_LEN (37) - -/* - * ADV_DIRECT_IND - * -> AdvA (6 bytes) - * -> InitA (6 bytes) - * - * AdvA is the advertisers public address (TxAdd=0) or random address - * (TxAdd = 1). - * - * InitA is the initiators public or random address. This is the address - * to which this packet is addressed. - * - */ -#define BLE_ADV_DIRECT_IND_LEN (12) - -/* - * ADV_NONCONN_IND - * -> AdvA (6 bytes) - * -> AdvData (0 - 31 bytes) - * - * The advertising address (AdvA) is a public address (TxAdd=0) or random - * address (TxAdd = 1) - * - */ -#define BLE_ADV_NONCONN_IND_MIN_LEN (6) -#define BLE_ADV_NONCONN_IND_MAX_LEN (37) - -/* - * ADV_SCAN_IND - * -> AdvA (6 bytes) - * -> AdvData (0 - 31 bytes) - * - * The advertising address (AdvA) is a public address (TxAdd=0) or random - * address (TxAdd = 1) - * - */ -#define BLE_ADV_SCAN_IND_MIN_LEN (6) -#define BLE_ADV_SCAN_IND_MAX_LEN (37) - -/*---- HCI ----*/ -struct ble_ll_adv_sm; -struct ble_ll_conn_sm; - -/* Start an advertiser */ -int ble_ll_adv_start_req(uint8_t adv_chanmask, uint8_t adv_type, - uint8_t *init_addr, uint16_t adv_itvl, void *handle); - -/* Start or stop advertising */ -int ble_ll_hci_adv_set_enable(const uint8_t *cmdbuf, uint8_t len); - -/* Set legacy advertising data */ -int ble_ll_hci_set_adv_data(const uint8_t *cmdbuf, uint8_t len); - -/* Set scan response data */ -int ble_ll_hci_set_scan_rsp_data(const uint8_t *cmd, uint8_t cmd_len); - -/* Set advertising parameters */ -int ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len); - -/* Read advertising channel power */ -int ble_ll_adv_read_txpwr(uint8_t *rspbuf, uint8_t *rsplen); - -/*---- API used by BLE LL ----*/ -/* Send the connection complete event */ -void ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm, - struct ble_mbuf_hdr *rxhdr); - -/* Returns local resolvable private address */ -uint8_t *ble_ll_adv_get_local_rpa(struct ble_ll_adv_sm *advsm); - -/* Returns peer resolvable private address */ -uint8_t *ble_ll_adv_get_peer_rpa(struct ble_ll_adv_sm *advsm); - -/* Called to initialize advertising functionality. */ -void ble_ll_adv_init(void); - -/* Called when LL wait for response timer expires in advertising state */ -void ble_ll_adv_wfr_timer_exp(void); - -/* Called to reset the advertiser. */ -void ble_ll_adv_reset(void); - -/* Called on rx pdu start when in advertising state */ -int ble_ll_adv_rx_isr_start(uint8_t pdu_type); - -/* Called on rx pdu end when in advertising state */ -int ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok); - -/* Processes received packets at the link layer task */ -void ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, - struct ble_mbuf_hdr *hdr); - -/* Boolean function denoting whether or not the whitelist can be changed */ -int ble_ll_adv_can_chg_whitelist(void); - -/* - * Called when an advertising event has been removed from the scheduler - * without being run. - */ -void ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm *advsm); - -/* - * Called when a periodic event has been removed from the scheduler - * without being run. - */ -void ble_ll_adv_periodic_rmvd_from_sched(struct ble_ll_adv_sm *advsm); - -/* Called to halt currently running advertising event */ -void ble_ll_adv_halt(void); - -/* Called to determine if advertising is enabled */ -uint8_t ble_ll_adv_enabled(void); - -int ble_ll_adv_hci_set_random_addr(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_adv_set_random_addr(const uint8_t *addr, uint8_t instance); -int ble_ll_adv_remove(const uint8_t *addr, uint8_t len); -int ble_ll_adv_clear_all(void); -int ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_adv_ext_set_adv_data(const uint8_t *cmdbuf, uint8_t cmdlen); -int ble_ll_adv_ext_set_scan_rsp(const uint8_t *cmdbuf, uint8_t cmdlen); -int ble_ll_adv_ext_set_enable(const uint8_t *cmdbuf, uint8_t len); - -int ble_ll_adv_periodic_set_param(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_adv_periodic_set_data(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_adv_periodic_enable(const uint8_t *cmdbuf, uint8_t len); - -int ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); - -/* Called to notify adv code about RPA rotation */ -void ble_ll_adv_rpa_timeout(void); - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_LL_ADV_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_conn.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_conn.h deleted file mode 100644 index 34512a1a4..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_conn.h +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_CONN_ -#define H_BLE_LL_CONN_ - -#include "nimble/porting/nimble/include/os/os.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "nimble/nimble/include/nimble/nimble_npl.h" -#include "ble_ll_sched.h" -#include "ble_ll_ctrl.h" -#include "ble_phy.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Roles */ -#define BLE_LL_CONN_ROLE_NONE (0) -#define BLE_LL_CONN_ROLE_MASTER (1) -#define BLE_LL_CONN_ROLE_SLAVE (2) - -/* Connection states */ -#define BLE_LL_CONN_STATE_IDLE (0) -#define BLE_LL_CONN_STATE_CREATED (1) -#define BLE_LL_CONN_STATE_ESTABLISHED (2) - -/* Channel map size */ -#define BLE_LL_CONN_CHMAP_LEN (5) - -/* Definitions for source clock accuracy */ -#define BLE_MASTER_SCA_251_500_PPM (0) -#define BLE_MASTER_SCA_151_250_PPM (1) -#define BLE_MASTER_SCA_101_150_PPM (2) -#define BLE_MASTER_SCA_76_100_PPM (3) -#define BLE_MASTER_SCA_51_75_PPM (4) -#define BLE_MASTER_SCA_31_50_PPM (5) -#define BLE_MASTER_SCA_21_30_PPM (6) -#define BLE_MASTER_SCA_0_20_PPM (7) - -/* Definition for RSSI when the RSSI is unknown */ -#define BLE_LL_CONN_UNKNOWN_RSSI (127) - -#define BLE_LL_CONN_HANDLE_ISO_OFFSET (0x0100) - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/* - * Encryption states for a connection - * - * NOTE: the states are ordered so that we can check to see if the state - * is greater than ENCRYPTED. If so, it means that the start or pause - * encryption procedure is running and we should not send data pdu's. - */ -enum conn_enc_state { - CONN_ENC_S_UNENCRYPTED = 1, - CONN_ENC_S_ENCRYPTED, - CONN_ENC_S_ENC_RSP_TO_BE_SENT, - CONN_ENC_S_ENC_RSP_WAIT, - CONN_ENC_S_PAUSE_ENC_RSP_WAIT, - CONN_ENC_S_PAUSED, - CONN_ENC_S_START_ENC_REQ_WAIT, - CONN_ENC_S_START_ENC_RSP_WAIT, - CONN_ENC_S_LTK_REQ_WAIT, - CONN_ENC_S_LTK_NEG_REPLY -}; - -/* - * Note that the LTK is the key, the SDK is the plain text, and the - * session key is the cipher text portion of the encryption block. - * - * NOTE: we have intentionally violated the specification by making the - * transmit and receive packet counters 32-bits as opposed to 39 (as per the - * specification). We do this to save code space, ram and calculation time. The - * only drawback is that any encrypted connection that sends more than 2^32 - * packets will suffer a MIC failure and thus be disconnected. - */ -struct ble_ll_conn_enc_data -{ - uint8_t enc_state; - uint8_t tx_encrypted; - uint16_t enc_div; - uint32_t tx_pkt_cntr; - uint32_t rx_pkt_cntr; - uint64_t host_rand_num; - uint8_t iv[8]; - struct ble_encryption_block enc_block; -}; -#endif - -/* Connection state machine flags. */ -union ble_ll_conn_sm_flags { - struct { - uint32_t pkt_rxd:1; - uint32_t terminate_ind_txd:1; - uint32_t terminate_ind_rxd:1; - uint32_t terminate_ind_rxd_acked:1; - uint32_t allow_slave_latency:1; - uint32_t slave_set_last_anchor:1; - uint32_t awaiting_host_reply:1; - uint32_t terminate_started:1; - uint32_t conn_update_sched:1; - uint32_t host_expects_upd_event:1; - uint32_t version_ind_sent:1; - uint32_t rxd_version_ind:1; - uint32_t chanmap_update_scheduled:1; - uint32_t conn_empty_pdu_txd:1; - uint32_t last_txd_md:1; - uint32_t conn_req_txd:1; - uint32_t send_ltk_req:1; - uint32_t encrypted:1; - uint32_t encrypt_chg_sent:1; - uint32_t le_ping_supp:1; - uint32_t csa2_supp:1; - uint32_t host_phy_update: 1; - uint32_t phy_update_sched: 1; - uint32_t ctrlr_phy_update: 1; - uint32_t phy_update_event: 1; - uint32_t peer_phy_update: 1; /* XXX:combine with ctrlr udpate bit? */ - uint32_t aux_conn_req: 1; - uint32_t rxd_features:1; - uint32_t pending_hci_rd_features:1; - uint32_t pending_initiate_dle:1; - } cfbit; - uint32_t conn_flags; -} __attribute__((packed)); - -/** - * Structure used for PHY data inside a connection. - * - * NOTE: the new phy's are the phys we will change to when a phy update - * procedure is ongoing and the event counter hits the instant. - * - * tx_phy_mode: chip specific phy mode for tx - * rx_phy_mode: chip specific phy mode for rx - * cur_tx_phy: value denoting current tx_phy (not a bitmask!) - * cur_rx_phy: value denoting current rx phy (not a bitmask!) - * new_tx_phy: value denoting new tx_phy (not a bitmask!) - * new_rx_phy: value denoting new rx phy (not a bitmask!) - * req_pref_tx_phy: tx phy sent in a phy request (may be different than host) - * req_pref_rx_phy: rx phy sent in a phy request (may be different than host) - * host_pref_tx_phys: bitmask of preferred transmit PHYs sent by host - * host_pref_rx_phys: bitmask of preferred receive PHYs sent by host - * phy_options: preferred phy options for coded phy - */ -struct ble_ll_conn_phy_data -{ - uint32_t tx_phy_mode: 2; - uint32_t rx_phy_mode: 2; - uint32_t cur_tx_phy: 2; - uint32_t cur_rx_phy: 2; - uint32_t new_tx_phy: 2; - uint32_t new_rx_phy: 2; - uint32_t host_pref_tx_phys_mask: 3; - uint32_t host_pref_rx_phys_mask: 3; - uint32_t req_pref_tx_phys_mask: 3; - uint32_t req_pref_rx_phys_mask: 3; - uint32_t phy_options: 2; -} __attribute__((packed)); - -#define CONN_CUR_TX_PHY_MASK(csm) (1 << ((csm)->phy_data.cur_tx_phy - 1)) -#define CONN_CUR_RX_PHY_MASK(csm) (1 << ((csm)->phy_data.cur_rx_phy - 1)) - -struct hci_conn_update -{ - uint16_t handle; - uint16_t conn_itvl_min; - uint16_t conn_itvl_max; - uint16_t conn_latency; - uint16_t supervision_timeout; - uint16_t min_ce_len; - uint16_t max_ce_len; -}; - -struct hci_ext_conn_params -{ - uint16_t scan_itvl; - uint16_t scan_window; - uint16_t conn_itvl_min; - uint16_t conn_itvl_max; - uint16_t conn_latency; - uint16_t supervision_timeout; - uint16_t min_ce_len; - uint16_t max_ce_len; -}; - -struct hci_ext_create_conn -{ - uint8_t filter_policy; - uint8_t own_addr_type; - uint8_t peer_addr_type; - uint8_t peer_addr[BLE_DEV_ADDR_LEN]; - uint8_t init_phy_mask; - struct hci_ext_conn_params params[3]; -}; - -/* Connection state machine */ -struct ble_ll_conn_sm -{ - /* Connection state machine flags */ - union ble_ll_conn_sm_flags csmflags; - - /* Current connection handle, state and role */ - uint16_t conn_handle; - uint8_t conn_state; - uint8_t conn_role; /* Can possibly be 1 bit */ - - /* RSSI */ - int8_t conn_rssi; - - /* For privacy */ - int8_t rpa_index; - - /* Connection data length management */ - uint8_t max_tx_octets; - uint8_t max_rx_octets; - uint8_t rem_max_tx_octets; - uint8_t rem_max_rx_octets; - uint8_t eff_max_tx_octets; - uint8_t eff_max_rx_octets; - uint16_t max_tx_time; - uint16_t max_rx_time; - uint16_t rem_max_tx_time; - uint16_t rem_max_rx_time; - uint16_t eff_max_tx_time; - uint16_t eff_max_rx_time; - uint8_t max_tx_octets_phy_mode[BLE_PHY_NUM_MODE]; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - uint16_t host_req_max_tx_time; -#endif - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - struct ble_ll_conn_phy_data phy_data; - uint16_t phy_instant; - uint8_t phy_tx_transition; -#endif - - /* Used to calculate data channel index for connection */ - uint8_t chanmap[BLE_LL_CONN_CHMAP_LEN]; - uint8_t req_chanmap[BLE_LL_CONN_CHMAP_LEN]; - uint16_t chanmap_instant; - uint16_t channel_id; /* TODO could be union with hop and last chan used */ - uint8_t hop_inc; - uint8_t data_chan_index; - uint8_t last_unmapped_chan; - uint8_t num_used_chans; - -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) - uint8_t period_occ_mask; /* mask: period 0 = 0x01, period 3 = 0x08 */ -#endif - - /* Ack/Flow Control */ - uint8_t tx_seqnum; /* note: can be 1 bit */ - uint8_t next_exp_seqnum; /* note: can be 1 bit */ - uint8_t cons_rxd_bad_crc; /* note: can be 1 bit */ - uint8_t last_rxd_sn; /* note: cant be 1 bit given current code */ - uint8_t last_rxd_hdr_byte; /* note: possibly can make 1 bit since we - only use the MD bit now */ - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) - uint16_t cth_flow_pending; -#endif - - /* connection event mgmt */ - uint8_t reject_reason; - uint8_t host_reply_opcode; - uint8_t master_sca; - uint8_t tx_win_size; - uint8_t cur_ctrl_proc; - uint8_t disconnect_reason; - uint8_t rxd_disconnect_reason; - uint8_t vers_nr; - uint8_t conn_features; - uint8_t remote_features[7]; - uint16_t pending_ctrl_procs; - uint16_t event_cntr; - uint16_t completed_pkts; - uint16_t comp_id; - uint16_t sub_vers_nr; - uint16_t auth_pyld_tmo; /* could be ifdef'd. 10 msec units */ - - uint32_t access_addr; - uint32_t crcinit; /* only low 24 bits used */ - /* XXX: do we need ce_end_time? Cant this be sched end time? */ - uint32_t ce_end_time; /* cputime at which connection event should end */ - uint32_t terminate_timeout; - uint32_t last_scheduled; - - /* Connection timing */ - uint16_t conn_itvl; - uint16_t slave_latency; - uint16_t supervision_tmo; - uint16_t min_ce_len; - uint16_t max_ce_len; - uint16_t tx_win_off; - uint32_t anchor_point; - uint8_t anchor_point_usecs; /* XXX: can this be uint8_t ?*/ - uint8_t conn_itvl_usecs; - uint32_t conn_itvl_ticks; - uint32_t last_anchor_point; /* Slave only */ - uint32_t slave_cur_tx_win_usecs; - uint32_t slave_cur_window_widening; - uint32_t last_rxd_pdu_cputime; /* Used exclusively for supervision timer */ - - /* - * Used to mark that identity address was used as InitA - */ - uint8_t inita_identity_used; - - /* address information */ - uint8_t own_addr_type; - uint8_t peer_addr_type; - uint8_t peer_addr[BLE_DEV_ADDR_LEN]; - - /* - * XXX: TODO. Could save memory. Have single event at LL and put these - * on a singly linked list. Only would need list pointer here. - */ - /* Connection end event */ - struct ble_npl_event conn_ev_end; - - /* Packet transmit queue */ - struct os_mbuf *cur_tx_pdu; - STAILQ_HEAD(conn_txq_head, os_mbuf_pkthdr) conn_txq; - - /* List entry for active/free connection pools */ - union { - SLIST_ENTRY(ble_ll_conn_sm) act_sle; - STAILQ_ENTRY(ble_ll_conn_sm) free_stqe; - }; - - /* LL control procedure response timer */ - struct ble_npl_callout ctrl_proc_rsp_timer; - - /* For scheduling connections */ - struct ble_ll_sched_item conn_sch; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) - struct ble_npl_callout auth_pyld_timer; -#endif - - /* - * XXX: a note on all these structures for control procedures. First off, - * all of these need to be ifdef'd to save memory. Another thing to - * consider is this: since most control procedures can only run when no - * others are running, can I use just one structure (a union)? Should I - * allocate these from a pool? Not sure what to do. For now, I just use - * a large chunk of memory per connection. - */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - struct ble_ll_conn_enc_data enc_data; -#endif - /* - * For connection update procedure. XXX: can make this a pointer and - * malloc it if we want to save space. - */ - struct hci_conn_update conn_param_req; - - /* For connection update procedure */ - struct ble_ll_conn_upd_req conn_update_req; - - /* XXX: for now, just store them all */ - struct ble_ll_conn_params conn_cp; - - struct ble_ll_scan_sm *scansm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct hci_ext_create_conn initial_params; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - uint8_t sync_transfer_mode; - uint16_t sync_transfer_skip; - uint32_t sync_transfer_sync_timeout; -#endif -}; - -/* Flags */ -#define CONN_F_UPDATE_SCHED(csm) ((csm)->csmflags.cfbit.conn_update_sched) -#define CONN_F_EMPTY_PDU_TXD(csm) ((csm)->csmflags.cfbit.conn_empty_pdu_txd) -#define CONN_F_LAST_TXD_MD(csm) ((csm)->csmflags.cfbit.last_txd_md) -#define CONN_F_CONN_REQ_TXD(csm) ((csm)->csmflags.cfbit.conn_req_txd) -#define CONN_F_ENCRYPTED(csm) ((csm)->csmflags.cfbit.encrypted) -#define CONN_F_ENC_CHANGE_SENT(csm) ((csm)->csmflags.cfbit.encrypt_chg_sent) -#define CONN_F_LE_PING_SUPP(csm) ((csm)->csmflags.cfbit.le_ping_supp) -#define CONN_F_TERMINATE_STARTED(csm) ((csm)->csmflags.cfbit.terminate_started) -#define CONN_F_CSA2_SUPP(csm) ((csm)->csmflags.cfbit.csa2_supp) -#define CONN_F_HOST_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.host_phy_update) -#define CONN_F_PHY_UPDATE_SCHED(csm) ((csm)->csmflags.cfbit.phy_update_sched) -#define CONN_F_CTRLR_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.ctrlr_phy_update) -#define CONN_F_PHY_UPDATE_EVENT(csm) ((csm)->csmflags.cfbit.phy_update_event) -#define CONN_F_PEER_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.peer_phy_update) -#define CONN_F_AUX_CONN_REQ(csm) ((csm)->csmflags.cfbit.aux_conn_req) - -/* Role */ -#define CONN_IS_MASTER(csm) (csm->conn_role == BLE_LL_CONN_ROLE_MASTER) -#define CONN_IS_SLAVE(csm) (csm->conn_role == BLE_LL_CONN_ROLE_SLAVE) - -/* - * Given a handle, returns an active connection state machine (or NULL if the - * handle does not exist - * - */ -struct ble_ll_conn_sm *ble_ll_conn_find_active_conn(uint16_t handle); - -/* required for unit testing */ -uint8_t ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn, uint16_t latency); - -/* used to get anchor point for connection event specified */ -void ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event, - uint32_t *anchor, uint8_t *anchor_usecs); - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_LL_CONN_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_ctrl.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_ctrl.h deleted file mode 100644 index 15a45b2a0..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_ctrl.h +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_CTRL_ -#define H_BLE_LL_CTRL_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * LL control procedures. This "enumeration" is not in the specification; - * It is used to determine which LL control procedure is currently running - * in a connection and which ones may be pending. - */ -#define BLE_LL_CTRL_PROC_CONN_UPDATE (0) -#define BLE_LL_CTRL_PROC_CHAN_MAP_UPD (1) -#define BLE_LL_CTRL_PROC_ENCRYPT (2) -#define BLE_LL_CTRL_PROC_FEATURE_XCHG (3) -#define BLE_LL_CTRL_PROC_VERSION_XCHG (4) -#define BLE_LL_CTRL_PROC_TERMINATE (5) -#define BLE_LL_CTRL_PROC_CONN_PARAM_REQ (6) -#define BLE_LL_CTRL_PROC_LE_PING (7) -#define BLE_LL_CTRL_PROC_DATA_LEN_UPD (8) -#define BLE_LL_CTRL_PROC_PHY_UPDATE (9) -#define BLE_LL_CTRL_PROC_SCA_UPDATE (10) -#define BLE_LL_CTRL_PROC_CIS_CREATE (11) -#define BLE_LL_CTRL_PROC_NUM (12) -#define BLE_LL_CTRL_PROC_IDLE (255) - -/* Checks if a particular control procedure is running */ -#define IS_PENDING_CTRL_PROC(sm, proc) (sm->pending_ctrl_procs & (1 << proc)) -#define CLR_PENDING_CTRL_PROC(sm, proc) (sm->pending_ctrl_procs &= ~(1 << proc)) - -/* LL control procedure timeout */ -#define BLE_LL_CTRL_PROC_TIMEOUT_MS (40000) /* ms */ - -/* - * LL CTRL PDU format - * -> Opcode (1 byte) - * -> Data (0 - 26 bytes) - */ -#define BLE_LL_CTRL_CONN_UPDATE_IND (0x00) -#define BLE_LL_CTRL_CHANNEL_MAP_REQ (0x01) -#define BLE_LL_CTRL_TERMINATE_IND (0x02) -#define BLE_LL_CTRL_ENC_REQ (0x03) -#define BLE_LL_CTRL_ENC_RSP (0x04) -#define BLE_LL_CTRL_START_ENC_REQ (0x05) -#define BLE_LL_CTRL_START_ENC_RSP (0x06) -#define BLE_LL_CTRL_UNKNOWN_RSP (0x07) -#define BLE_LL_CTRL_FEATURE_REQ (0x08) -#define BLE_LL_CTRL_FEATURE_RSP (0x09) -#define BLE_LL_CTRL_PAUSE_ENC_REQ (0x0A) -#define BLE_LL_CTRL_PAUSE_ENC_RSP (0x0B) -#define BLE_LL_CTRL_VERSION_IND (0x0C) -#define BLE_LL_CTRL_REJECT_IND (0x0D) -#define BLE_LL_CTRL_SLAVE_FEATURE_REQ (0x0E) -#define BLE_LL_CTRL_CONN_PARM_REQ (0x0F) -#define BLE_LL_CTRL_CONN_PARM_RSP (0x10) -#define BLE_LL_CTRL_REJECT_IND_EXT (0x11) -#define BLE_LL_CTRL_PING_REQ (0x12) -#define BLE_LL_CTRL_PING_RSP (0x13) -#define BLE_LL_CTRL_LENGTH_REQ (0x14) -#define BLE_LL_CTRL_LENGTH_RSP (0x15) -#define BLE_LL_CTRL_PHY_REQ (0x16) -#define BLE_LL_CTRL_PHY_RSP (0x17) -#define BLE_LL_CTRL_PHY_UPDATE_IND (0x18) -#define BLE_LL_CTRL_MIN_USED_CHAN_IND (0x19) -#define BLE_LL_CTRL_CTE_REQ (0x1A) -#define BLE_LL_CTRL_CTE_RSP (0x1B) -#define BLE_LL_CTRL_PERIODIC_SYNC_IND (0x1C) -#define BLE_LL_CTRL_CLOCK_ACCURACY_REQ (0x1D) -#define BLE_LL_CTRL_CLOCK_ACCURACY_RSP (0x1E) -#define BLE_LL_CTRL_CIS_REQ (0x1F) -#define BLE_LL_CTRL_CIS_RSP (0x20) -#define BLE_LL_CTRL_CIS_IND (0x21) -#define BLE_LL_CTRL_CIS_TERMINATE_IND (0x22) - -/* Maximum opcode value */ -#define BLE_LL_CTRL_OPCODES (BLE_LL_CTRL_CIS_TERMINATE_IND + 1) - -extern const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES]; - -/* Maximum LL control PDU size */ -#if MYNEWT_VAL(BLE_ISO) -#define BLE_LL_CTRL_MAX_PDU_LEN (42) -#elif MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -#define BLE_LL_CTRL_MAX_PDU_LEN (35) -#else -#define BLE_LL_CTRL_MAX_PDU_LEN (27) -#endif - -/* LL control connection update request */ -struct ble_ll_conn_upd_req -{ - uint8_t winsize; - uint16_t winoffset; - uint16_t interval; - uint16_t latency; - uint16_t timeout; - uint16_t instant; -}; -#define BLE_LL_CTRL_CONN_UPD_REQ_LEN (11) - -/* LL control channel map request */ -struct ble_ll_chan_map_req -{ - uint8_t chmap[5]; - uint16_t instant; -}; -#define BLE_LL_CTRL_CHAN_MAP_LEN (7) - -/* - * LL control terminate ind - * -> error code (1 byte) - */ -#define BLE_LL_CTRL_TERMINATE_IND_LEN (1) - -/* LL control enc req */ -struct ble_ll_enc_req -{ - uint8_t rand[8]; - uint16_t ediv; - uint8_t skdm[8]; - uint32_t ivm; -}; - -#define BLE_LL_CTRL_ENC_REQ_LEN (22) - -/* LL control enc rsp */ -struct ble_ll_enc_rsp -{ - uint8_t skds[8]; - uint32_t ivs; -}; - -#define BLE_LL_CTRL_ENC_RSP_LEN (12) - -/* LL control start/pause enc request and response */ -#define BLE_LL_CTRL_START_ENC_REQ_LEN (0) -#define BLE_LL_CTRL_START_ENC_RSP_LEN (0) -#define BLE_LL_CTRL_PAUSE_ENC_REQ_LEN (0) -#define BLE_LL_CTRL_PAUSE_ENC_RSP_LEN (0) - -/* - * LL control unknown response - * -> 1 byte which contains the unknown or un-supported opcode. - */ -#define BLE_LL_CTRL_UNK_RSP_LEN (1) - -/* - * LL control feature req and LL control feature rsp - * -> 8 bytes of data containing features supported by device. - */ -#define BLE_LL_CTRL_FEATURE_LEN (8) - -/* - * LL control version ind - * -> version (1 byte): - * Contains the version number of the bluetooth controller specification. - * -> comp_id (2 bytes) - * Contains the company identifier of the manufacturer of the controller. - * -> sub_ver_num: Contains a unique value for implementation or revision of - * the bluetooth controller. - */ -struct ble_ll_version_ind -{ - uint8_t ble_ctrlr_ver; - uint16_t company_id; - uint16_t sub_ver_num; -}; - -#define BLE_LL_CTRL_VERSION_IND_LEN (5) - -/* - * LL control reject ind - * -> error code (1 byte): contains reason why request was rejected. - */ -#define BLE_LL_CTRL_REJ_IND_LEN (1) - -/* - * LL control slave feature req - * -> 8 bytes of data containing features supported by device. - */ -#define BLE_LL_CTRL_SLAVE_FEATURE_REQ_LEN (8) - -/* LL control connection param req and connection param rsp */ -struct ble_ll_conn_params -{ - uint16_t interval_min; - uint16_t interval_max; - uint16_t latency; - uint16_t timeout; - uint8_t pref_periodicity; - uint16_t ref_conn_event_cnt; - uint16_t offset0; - uint16_t offset1; - uint16_t offset2; - uint16_t offset3; - uint16_t offset4; - uint16_t offset5; -}; - -#define BLE_LL_CTRL_CONN_PARAMS_LEN (23) - -/* LL control reject ind ext */ -struct ble_ll_reject_ind_ext -{ - uint8_t reject_opcode; - uint8_t err_code; -}; - -#define BLE_LL_CTRL_REJECT_IND_EXT_LEN (2) - -/* LL control ping req and ping rsp (contain no data) */ -#define BLE_LL_CTRL_PING_LEN (0) - -/* - * LL control length req and length rsp - * -> max_rx_bytes (2 bytes): defines connMaxRxOctets. Range 27 to 251 - * -> max_rx_time (2 bytes): defines connMaxRxTime. Range 328 to 2120 usecs. - * -> max_tx_bytes (2 bytes): defines connMaxTxOctets. Range 27 to 251 - * -> max_tx_time (2 bytes): defines connMaxTxTime. Range 328 to 2120 usecs. - */ -struct ble_ll_len_req -{ - uint16_t max_rx_bytes; - uint16_t max_rx_time; - uint16_t max_tx_bytes; - uint16_t max_tx_time; -}; - -#define BLE_LL_CTRL_LENGTH_REQ_LEN (8) - -/* PHY request/response */ -#define BLE_LL_CTRL_PHY_REQ_LEN (2) -#define BLE_LL_CTRL_PHY_RSP_LEN (2) -#define BLE_LL_CTRL_PHY_UPD_IND_LEN (4) - -/* Min used channels */ -#define BLE_LL_CTRL_MIN_USED_CHAN_LEN (2) - -/* CTE REQ */ -#define BLE_LL_CTRL_CTE_REQ_LEN (1) - -/* CTE RSP (contains no data) */ -#define BLE_LL_CTRL_CTE_RSP_LEN (0) - -/* Periodic Sync Transfer IND */ -#define BLE_LL_CTRL_PERIODIC_SYNC_IND_LEN (34) - -/* Clock accuracy request/response */ -#define BLE_LL_CTRL_CLOCK_ACCURACY_REQ_LEN (1) -#define BLE_LL_CTRL_CLOCK_ACCURACY_RSP_LEN (1) - -/* BLE ISO */ -#define BLE_LL_CTRL_CIS_REQ_LEN (42) -#define BLE_LL_CTRL_CIS_RSP_LEN (8) -#define BLE_LL_CTRL_CIS_IND_LEN (15) -#define BLE_LL_CTRL_CIS_TERMINATE_LEN (3) - -/* API */ -struct ble_ll_conn_sm; -void ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc); -void ble_ll_ctrl_proc_stop(struct ble_ll_conn_sm *connsm, int ctrl_proc); -int ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om); -void ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm); -void ble_ll_ctrl_terminate_start(struct ble_ll_conn_sm *connsm); -int ble_ll_ctrl_is_terminate_ind(uint8_t hdr, uint8_t opcode); -uint8_t ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm, - uint8_t *rsp, - struct ble_ll_conn_params *req); -int ble_ll_ctrl_reject_ind_send(struct ble_ll_conn_sm *connsm, - uint8_t rej_opcode, uint8_t err); -int ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm); -int ble_ll_ctrl_enc_allowed_pdu_rx(struct os_mbuf *rxpdu); -int ble_ll_ctrl_enc_allowed_pdu_tx(struct os_mbuf_pkthdr *pkthdr); -int ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm); -int ble_ll_ctrl_is_start_enc_rsp(struct os_mbuf *txpdu); - -void ble_ll_hci_ev_datalen_chg(struct ble_ll_conn_sm *connsm); -void ble_ll_hci_ev_rem_conn_parm_req(struct ble_ll_conn_sm *connsm, - struct ble_ll_conn_params *cp); -void ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status); -void ble_ll_hci_ev_rd_rem_used_feat(struct ble_ll_conn_sm *connsm, - uint8_t status); -void ble_ll_hci_ev_rd_rem_ver(struct ble_ll_conn_sm *connsm, uint8_t status); -void ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status); -int ble_ll_hci_ev_ltk_req(struct ble_ll_conn_sm *connsm); -int ble_ll_hci_ev_hw_err(uint8_t hw_err); -void ble_ll_hci_ev_databuf_overflow(void); -void ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm); -void ble_ll_hci_ev_send_scan_req_recv(uint8_t adv_handle, const uint8_t *peer, - uint8_t peer_addr_type); -void ble_ll_hci_ev_send_scan_timeout(void); -void ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle, - uint16_t conn_handle, uint8_t events); -int ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status); -void ble_ll_calc_session_key(struct ble_ll_conn_sm *connsm); -void ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm); -void ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm); -void ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line); - -uint8_t ble_ll_ctrl_phy_tx_transition_get(uint8_t phy_mask); -uint8_t ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) -void ble_ll_hci_ev_sca_update(struct ble_ll_conn_sm *connsm, - uint8_t status, uint8_t peer_sca); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_LL_CTRL_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_hci.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_hci.h deleted file mode 100644 index 9f51edf7a..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_hci.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_HCI_ -#define H_BLE_LL_HCI_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "nimble/nimble/include/nimble/hci_common.h" - -/* For supported commands */ -#define BLE_LL_SUPP_CMD_LEN (45) -extern const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN]; - -/* The largest event the controller will send. */ -#define BLE_LL_MAX_EVT_LEN MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE) - -/* - * This determines the number of outstanding commands allowed from the - * host to the controller. NOTE: you cannot change this without modifying - * other portions of the code as we currently use a global os event for - * the command; you would need to allocate a pool of these. - */ -#define BLE_LL_CFG_NUM_HCI_CMD_PKTS (1) - -typedef void (*ble_ll_hci_post_cmd_complete_cb)(void); - -/* Initialize LL HCI */ -void ble_ll_hci_init(void); - -/* Used to determine if the LE event is enabled/disabled */ -bool ble_ll_hci_is_le_event_enabled(unsigned int subev); - -/* Used to determine if event is enabled/disabled */ -bool ble_ll_hci_is_event_enabled(unsigned int evcode); - -/* Send event from controller to host */ -int ble_ll_hci_event_send(struct ble_hci_ev *hci_ev); - -/* Sends a command complete with a no-op opcode to host */ -void ble_ll_hci_send_noop(void); - -/* Checks the preferref phy masks from set default phy and set phy commands */ -int ble_ll_hci_chk_phy_masks(uint8_t all_phys, uint8_t tx_phys, uint8_t rx_phys, - uint8_t *txphy, uint8_t *rxphy); - -/* Returns true if Extended Advertising HCI commands are in use */ -bool ble_ll_hci_adv_mode_ext(void); - -/* Get TX power compensation rounded to integer dB */ -int8_t ble_ll_get_tx_pwr_compensation(void); - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_LL_HCI_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_iso.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_iso.h deleted file mode 100644 index 2944b0747..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_iso.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_ISO -#define H_BLE_LL_ISO - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -int ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_set_cig_param(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_iso_set_cig_param_test(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_iso_create_cis(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd); -int ble_ll_iso_remove_cig(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_iso_accept_cis_req(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_reject_cis_req(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_create_big(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_create_big_test(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_terminate_big(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_big_create_sync(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_big_terminate_sync(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_transmit_test(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_receive_test(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_read_counters_test(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_resolv.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_resolv.h deleted file mode 100644 index 228e0a370..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_resolv.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_RESOLV_ -#define H_BLE_LL_RESOLV_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * An entry in the resolving list. - * The identity address is stored in little endian format. - * The local rpa is stored in little endian format. - * The IRKs are stored in big endian format. - * - * Note: - * rl_local_irk and rl_peer_irk need to be word aligned - */ -struct ble_ll_resolv_entry -{ - uint8_t rl_addr_type; - uint8_t rl_priv_mode; - uint8_t rl_has_local; - uint8_t rl_has_peer; - uint8_t rl_local_irk[16]; - uint8_t rl_peer_irk[16]; - uint8_t rl_identity_addr[BLE_DEV_ADDR_LEN]; - uint8_t rl_local_rpa[BLE_DEV_ADDR_LEN]; - uint8_t rl_peer_rpa[BLE_DEV_ADDR_LEN]; -}; - -extern struct ble_ll_resolv_entry g_ble_ll_resolv_list[]; - -/* Clear the resolving list */ -int ble_ll_resolv_list_clr(void); - -/* Read the size of the resolving list */ -int ble_ll_resolv_list_read_size(uint8_t *rspbuf, uint8_t *rsplen); - -/* Add a device to the resolving list */ -int ble_ll_resolv_list_add(const uint8_t *cmdbuf, uint8_t len); - -/* Remove a device from the resolving list */ -int ble_ll_resolv_list_rmv(const uint8_t *cmdbuf, uint8_t len); - -/* Address resolution enable command */ -int ble_ll_resolv_enable_cmd(const uint8_t *cmdbuf, uint8_t len); - -int ble_ll_resolv_peer_addr_rd(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_resolv_local_addr_rd(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); - -/* Finds 'addr' in resolving list. Doesnt check if address resolution enabled */ -struct ble_ll_resolv_entry * -ble_ll_resolv_list_find(const uint8_t *addr, uint8_t addr_type); - -/* Returns true if address resolution is enabled */ -uint8_t ble_ll_resolv_enabled(void); - -/* Reset private address resolution */ -void ble_ll_resolv_list_reset(void); - -/* Generate local or peer RPA. It is up to caller to make sure required IRK - * is present on RL - */ -void ble_ll_resolv_get_priv_addr(struct ble_ll_resolv_entry *rl, int local, - uint8_t *addr); - -void ble_ll_resolv_set_peer_rpa(int index, uint8_t *rpa); -void ble_ll_resolv_set_local_rpa(int index, uint8_t *rpa); - -/* Generate a resolvable private address. */ -int ble_ll_resolv_gen_rpa(uint8_t *addr, uint8_t addr_type, uint8_t *rpa, - int local); - -/* Set the resolvable private address timeout */ -int ble_ll_resolv_set_rpa_tmo(const uint8_t *cmdbuf, uint8_t len); - -/* Set the privacy mode */ -int ble_ll_resolve_set_priv_mode(const uint8_t *cmdbuf, uint8_t len); - -/* Get the RPA timeout, in seconds */ -uint32_t ble_ll_resolv_get_rpa_tmo(void); - -/* Resolve a resolvable private address */ -int ble_ll_resolv_rpa(const uint8_t *rpa, const uint8_t *irk); - -/* Try to resolve peer RPA and return index on RL if matched */ -int ble_ll_resolv_peer_rpa_any(const uint8_t *rpa); - -/* Initialize resolv*/ -void ble_ll_resolv_init(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h deleted file mode 100644 index 37b81a88b..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_RFMGMT_ -#define H_BLE_LL_RFMGMT_ - -#ifdef __cplusplus -extern "C" { -#endif - -void ble_ll_rfmgmt_init(void); - -#if MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME) > 0 - -void ble_ll_rfmgmt_reset(void); - -/* Notify rfmgmt that scan window has changed (only called from ble_ll_scan) */ -void ble_ll_rfmgmt_scan_changed(bool enabled, uint32_t next_window); - -/* Notify rfmgmt that 1st scheduled item has changed (only called from ble_ll_sched) */ -void ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *first); - -/* Notify rfmgmt that RF is no longer needed by current event */ -void ble_ll_rfmgmt_release(void); - -/* Enables RF immediately and returns tick at which RF will be fully enabled */ -uint32_t ble_ll_rfmgmt_enable_now(void); - -/* Returns true only if RF is currently fully enabled (i.e. not off or enabling) */ -bool ble_ll_rfmgmt_is_enabled(void); - -#else - -static inline void ble_ll_rfmgmt_reset(void) { } -static inline void ble_ll_rfmgmt_scan_changed(bool e, uint32_t n) { } -static inline void ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *f) { } -static inline void ble_ll_rfmgmt_release(void) { } -static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return 0; } -static inline bool ble_ll_rfmgmt_is_enabled(void) { return true; } - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_LL_RFMGMT_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_scan.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_scan.h deleted file mode 100644 index ca50824d0..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_scan.h +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_SCAN_ -#define H_BLE_LL_SCAN_ - -#include "ble_ll_sched.h" -#include "nimble/porting/nimble/include/hal/hal_timer.h" -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/nimble/include/nimble/nimble_npl.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * SCAN_REQ - * -> ScanA (6 bytes) - * -> AdvA (6 bytes) - * - * ScanA is the scanners public (TxAdd=0) or random (TxAdd = 1) address - * AdvaA is the advertisers public (RxAdd=0) or random (RxAdd=1) address. - * - * Sent by the LL in the Scanning state; received by the LL in the advertising - * state. The advertising address is the intended recipient of this frame. - */ -#define BLE_SCAN_REQ_LEN (12) - -/* - * SCAN_RSP - * -> AdvA (6 bytes) - * -> ScanRspData (0 - 31 bytes) - * - * AdvaA is the advertisers public (TxAdd=0) or random (TxAdd=1) address. - * ScanRspData may contain any data from the advertisers host. - * - * Sent by the LL in the advertising state; received by the LL in the - * scanning state. - */ -#define BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN (31) -#define BLE_SCAN_LEGACY_MAX_PKT_LEN (37) - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#define BLE_SCAN_RSP_DATA_MAX_LEN MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) - -/* For Bluetooth 5.0 we need state machine for two PHYs*/ -#define BLE_LL_SCAN_PHY_NUMBER (2) -#else -#define BLE_LL_SCAN_PHY_NUMBER (1) -#define BLE_SCAN_RSP_DATA_MAX_LEN BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN -#endif - -#define PHY_UNCODED (0) -#define PHY_CODED (1) - -#define BLE_LL_EXT_ADV_MODE_NON_CONN (0x00) -#define BLE_LL_EXT_ADV_MODE_CONN (0x01) -#define BLE_LL_EXT_ADV_MODE_SCAN (0x02) - -/* All values are stored as ticks */ -struct ble_ll_scan_timing { - uint32_t interval; - uint32_t window; - uint32_t start_time; -}; - -struct ble_ll_scan_params -{ - uint8_t phy; - uint8_t own_addr_type; - uint8_t scan_filt_policy; - uint8_t configured; - uint8_t scan_type; - uint8_t scan_chan; - struct ble_ll_scan_timing timing; -}; - -#define BLE_LL_AUX_HAS_ADVA 0x01 -#define BLE_LL_AUX_HAS_TARGETA 0x02 -#define BLE_LL_AUX_HAS_ADI 0x04 -#define BLE_LL_AUX_IS_MATCHED 0x08 -#define BLE_LL_AUX_IS_TARGETA_RESOLVED 0x10 - -#define BLE_LL_AUX_FLAG_HCI_SENT_ANY 0x02 -#define BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED 0x04 -#define BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED 0x08 -#define BLE_LL_AUX_FLAG_SCAN_COMPLETE 0x10 -#define BLE_LL_AUX_FLAG_SCAN_ERROR 0x20 -#define BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED 0x40 -#define BLE_LL_AUX_FLAG_AUX_CHAIN_RECEIVED 0x80 - -struct ble_ll_aux_data { - uint8_t flags; - - /* - * Since aux_data can be accessed from ISR and LL, we have separate copies - * of flags to make sure that ISR does not modify flags while LL uses them. - * ISR updates 'flags_isr' and LL adds these to 'flags_ll' which it then - * uses for further processing allowing to update 'flags_isr' if another - * scan for given 'aux_data' is scheduled. Note that flags must not be unset - * while aux_data is valid. - */ - uint8_t flags_isr; - uint8_t flags_ll; - - uint8_t ref_cnt; - uint8_t chan; - uint8_t aux_phy; - uint8_t aux_primary_phy; - uint8_t mode; - uint8_t scanning; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - int8_t rpa_index; -#endif - uint16_t adi; - uint32_t offset; - uint8_t offset_units; - uint8_t adva[6]; - uint8_t adva_type; - uint8_t targeta[6]; - uint8_t targeta_type; - uint16_t evt_type; - struct ble_ll_sched_item sch; - struct ble_hci_ev *evt; - struct ble_npl_event ev; -}; - -struct ble_ll_scan_pdu_data { - uint8_t hdr_byte; - /* ScanA for SCAN_REQ and InitA for CONNECT_IND */ - union { - uint8_t scana[BLE_DEV_ADDR_LEN]; - uint8_t inita[BLE_DEV_ADDR_LEN]; - }; - uint8_t adva[BLE_DEV_ADDR_LEN]; -}; - -struct ble_ll_scan_sm -{ - uint8_t scan_enabled; - uint8_t own_addr_type; - uint8_t scan_filt_dups; - uint8_t scan_rsp_pending; - uint8_t scan_rsp_cons_fails; - uint8_t scan_rsp_cons_ok; - uint8_t scan_peer_rpa[BLE_DEV_ADDR_LEN]; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - ble_npl_time_t scan_nrpa_timer; - uint8_t scan_nrpa[BLE_DEV_ADDR_LEN]; -#endif - struct ble_ll_scan_pdu_data pdu_data; - - /* XXX: Shall we count backoff per phy? */ - uint16_t upper_limit; - uint16_t backoff_count; - uint32_t scan_win_start_time; - struct ble_npl_event scan_sched_ev; - struct hal_timer scan_timer; - struct ble_npl_event scan_interrupted_ev; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct hal_timer duration_timer; - struct hal_timer period_timer; - uint32_t duration_ticks; - uint32_t period_ticks; - uint8_t ext_scanning; -#endif - - uint8_t restart_timer_needed; - struct ble_ll_aux_data *cur_aux_data; - - struct ble_ll_scan_params *scanp; - struct ble_ll_scan_params *scanp_next; - struct ble_ll_scan_params scanp_phys[BLE_LL_SCAN_PHY_NUMBER]; -}; - -/* Scan types */ -#define BLE_SCAN_TYPE_PASSIVE (BLE_HCI_SCAN_TYPE_PASSIVE) -#define BLE_SCAN_TYPE_ACTIVE (BLE_HCI_SCAN_TYPE_ACTIVE) -#define BLE_SCAN_TYPE_INITIATE (2) - -/*---- HCI ----*/ -/* Set scanning parameters */ -int ble_ll_scan_set_scan_params(const uint8_t *cmdbuf, uint8_t len); - -/* Turn scanning on/off */ -int ble_ll_hci_scan_set_enable(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_hci_ext_scan_set_enable(const uint8_t *cmdbuf, uint8_t len); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len); -#endif - -/*--- Controller Internal API ---*/ -/* Initialize the scanner */ -void ble_ll_scan_init(void); - -/* Reset the scanner */ -void ble_ll_scan_reset(void); - -/* Called when Link Layer starts to receive a PDU and is in scanning state */ -int ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint16_t *rxflags); - -/* Called when Link Layer has finished receiving a PDU while scanning */ -int ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok); - -/* Process a scan response PDU */ -void ble_ll_scan_rx_pkt_in(uint8_t pdu_type, struct os_mbuf *om, - struct ble_mbuf_hdr *hdr); - -/* Boolean function denoting whether or not the whitelist can be changed */ -int ble_ll_scan_can_chg_whitelist(void); - -/* Boolean function returning true if scanning enabled */ -int ble_ll_scan_enabled(void); - -/* Boolean function returns true if whitelist is enabled for scanning */ -int ble_ll_scan_whitelist_enabled(void); - -/* Initialize the scanner when we start initiating */ -struct hci_create_conn; -int ble_ll_scan_initiator_start(struct hci_create_conn *hcc, - struct ble_ll_scan_sm **sm); - -/* Returns storage for PDU data (for SCAN_REQ or CONNECT_IND) */ -struct ble_ll_scan_pdu_data *ble_ll_scan_get_pdu_data(void); - -/* Called to set the resolvable private address of the last connected peer */ -void ble_ll_scan_set_peer_rpa(uint8_t *rpa); - -/* Returns peer RPA of last connection made */ -uint8_t *ble_ll_scan_get_peer_rpa(void); - -/* Returns the local RPA used by the scanner/initiator */ -uint8_t *ble_ll_scan_get_local_rpa(void); - -/* Stop the scanning state machine */ -void ble_ll_scan_sm_stop(int chk_disable); - -/* Resume scanning */ -void ble_ll_scan_chk_resume(void); - -/* Called when wait for response timer expires in scanning mode */ -void ble_ll_scan_wfr_timer_exp(void); - -/* Called when scan could be interrupted */ -void ble_ll_scan_interrupted(struct ble_ll_scan_sm *scansm); - -int ble_ll_scan_adv_decode_addr(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *ble_hdr, - uint8_t **addr, uint8_t *addr_type, - uint8_t **inita, uint8_t *init_addr_type, - int *ext_mode); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int ble_ll_scan_update_aux_data(struct ble_mbuf_hdr *ble_hdr, uint8_t *rxbuf, - bool *adva_present); - -/* Initialize the extended scanner when we start initiating */ -struct hci_ext_create_conn; -int ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn *hcc, - struct ble_ll_scan_sm **sm); - -/* Called to parse extended advertising*/ -struct ble_ll_aux_data *ble_ll_scan_aux_data_ref(struct ble_ll_aux_data *aux_scan); -void ble_ll_scan_aux_data_unref(struct ble_ll_aux_data *aux_scan); -void ble_ll_scan_end_adv_evt(struct ble_ll_aux_data *aux_data); -#endif - -/* Called to halt currently running scan */ -void ble_ll_scan_halt(void); - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_LL_SCAN_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_sched.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_sched.h deleted file mode 100644 index a614cf090..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_sched.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_SCHED_ -#define H_BLE_LL_SCHED_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Time per BLE scheduler slot */ -#define BLE_LL_SCHED_USECS_PER_SLOT (1250) -#define BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT (41) /* 1 tick = 30.517 usecs */ - -/* - * Worst case time needed for scheduled advertising item. This is the longest - * possible time to receive a scan request and send a scan response (with the - * appropriate IFS time between them). This number is calculated using the - * following formula: IFS + SCAN_REQ + IFS + SCAN_RSP = 150 + 176 + 150 + 376. - * Note: worst case time to tx adv, rx scan req and send scan rsp is 1228 usecs. - * This assumes maximum sized advertising PDU and scan response PDU. - * - * For connectable advertising events no scan request is allowed. In this case - * we just need to receive a connect request PDU: IFS + CONNECT_REQ = 150 + 352. - * Note: worst-case is 376 + 150 + 352 = 878 usecs - * - * NOTE: The advertising PDU transmit time is NOT included here since we know - * how long that will take (worst-case is 376 usecs). - */ -#define BLE_LL_SCHED_ADV_MAX_USECS (852) -#define BLE_LL_SCHED_DIRECT_ADV_MAX_USECS (502) -#define BLE_LL_SCHED_MAX_ADV_PDU_USECS (376) - -/* - * This is the offset from the start of the scheduled item until the actual - * tx/rx should occur, in ticks. - */ -extern uint8_t g_ble_ll_sched_offset_ticks; - -/* - * This is the number of slots needed to transmit and receive a maximum - * size PDU, including an IFS time before each. The actual time is - * 2120 usecs for tx/rx and 150 for IFS = 4540 usecs. - */ -#define BLE_LL_SCHED_MAX_TXRX_SLOT (4 * BLE_LL_SCHED_USECS_PER_SLOT) - -/* BLE scheduler errors */ -#define BLE_LL_SCHED_ERR_OVERLAP (1) - -/* Types of scheduler events */ -#define BLE_LL_SCHED_TYPE_ADV (1) -#define BLE_LL_SCHED_TYPE_SCAN (2) -#define BLE_LL_SCHED_TYPE_CONN (3) -#define BLE_LL_SCHED_TYPE_AUX_SCAN (4) -#define BLE_LL_SCHED_TYPE_DTM (5) -#define BLE_LL_SCHED_TYPE_PERIODIC (6) -#define BLE_LL_SCHED_TYPE_SYNC (7) - -/* Return values for schedule callback. */ -#define BLE_LL_SCHED_STATE_RUNNING (0) -#define BLE_LL_SCHED_STATE_DONE (1) - -/* Callback function */ -struct ble_ll_sched_item; -typedef int (*sched_cb_func)(struct ble_ll_sched_item *sch); -typedef void (*sched_remove_cb_func)(struct ble_ll_sched_item *sch); -/* - * Strict connection scheduling (for the master) is different than how - * connections are normally scheduled. With strict connection scheduling we - * introduce the concept of a "period". A period is a collection of slots. Each - * slot is 1.25 msecs in length. The number of slots in a period is determined - * by the syscfg value BLE_LL_CONN_INIT_SLOTS. A collection of periods is called - * an epoch. The length of an epoch is determined by the number of connections - * (BLE_MAX_CONNECTIONS plus BLE_LL_ADD_STRICT_SCHED_PERIODS). Connections - * will be scheduled at period boundaries. Any scanning/initiating/advertising - * will be done in unused periods, if possible. - */ -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) -#define BLE_LL_SCHED_PERIODS (MYNEWT_VAL(BLE_MAX_CONNECTIONS) + \ - MYNEWT_VAL(BLE_LL_ADD_STRICT_SCHED_PERIODS)) - -struct ble_ll_sched_obj -{ - uint8_t sch_num_occ_periods; - uint32_t sch_occ_period_mask; - uint32_t sch_ticks_per_period; - uint32_t sch_ticks_per_epoch; - uint32_t sch_epoch_start; -}; - -extern struct ble_ll_sched_obj g_ble_ll_sched_data; - -/* - * XXX: TODO: - * -> How do we know epoch start is up to date? Not wrapped? - * -> for now, only do this with no more than 32 connections. - * -> Do not let initiating occur if no empty sched slots - */ -#endif - -/* - * Schedule item - * sched_type: This is the type of the schedule item. - * enqueued: Flag denoting if item is on the scheduler list. 0: no, 1:yes - * remainder: # of usecs from offset till tx/rx should occur - * txrx_offset: Number of ticks from start time until tx/rx should occur. - * - */ -struct ble_ll_sched_item -{ - uint8_t sched_type; - uint8_t enqueued; - uint8_t remainder; - uint32_t start_time; - uint32_t end_time; - void *cb_arg; - sched_cb_func sched_cb; - TAILQ_ENTRY(ble_ll_sched_item) link; -}; - -/* Initialize the scheduler */ -int ble_ll_sched_init(void); - -/* Remove item(s) from schedule */ -int ble_ll_sched_rmv_elem(struct ble_ll_sched_item *sch); - -void ble_ll_sched_rmv_elem_type(uint8_t type, sched_remove_cb_func remove_cb); - -/* Schedule a new master connection */ -struct ble_ll_conn_sm; -int ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, - struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len); - -/* Schedule a new slave connection */ -int ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm); - -struct ble_ll_adv_sm; -typedef void ble_ll_sched_adv_new_cb(struct ble_ll_adv_sm *advsm, - uint32_t sch_start, void *arg); - -/* Schedule a new advertising event */ -int ble_ll_sched_adv_new(struct ble_ll_sched_item *sch, - ble_ll_sched_adv_new_cb cb, void *arg); - -/* Schedule periodic advertising event */ -int ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, uint32_t *start, - bool after_overlap); - -int ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, - uint32_t anchor_point, - uint8_t anchor_point_usecs, - uint32_t window_widening, int8_t phy_mode); -int ble_ll_sched_sync(struct ble_ll_sched_item *sch, - uint32_t beg_cputime, uint32_t rem_usecs, uint32_t offset, - int8_t phy_mode); - -/* Reschedule an advertising event */ -int ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start, - uint32_t max_delay_ticks); - -/* Reschedule and advertising pdu */ -int ble_ll_sched_adv_resched_pdu(struct ble_ll_sched_item *sch); - -/* Reschedule a connection that had previously been scheduled or that is over */ -int ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm * connsm); - -/** - * Called to determine when the next scheduled event will occur. - * - * If there are not scheduled events this function returns 0; otherwise it - * returns 1 and *next_event_time is set to the start time of the next event. - * - * @param next_event_time cputime at which next scheduled event will occur - * - * @return int 0: No events are scheduled 1: there is an upcoming event - */ -int ble_ll_sched_next_time(uint32_t *next_event_time); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -struct ble_ll_scan_sm; -struct ble_ll_aux_data; -int ble_ll_sched_aux_scan(struct ble_mbuf_hdr *ble_hdr, - struct ble_ll_scan_sm *scansm, - struct ble_ll_aux_data *aux_scan); - -int ble_ll_sched_scan_req_over_aux_ptr(uint32_t chan, uint8_t phy_mode); -#endif - -/* Stop the scheduler */ -void ble_ll_sched_stop(void); - -#if MYNEWT_VAL(BLE_LL_DTM) -int ble_ll_sched_dtm(struct ble_ll_sched_item *sch); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* H_LL_SCHED_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_sync.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_sync.h deleted file mode 100644 index 96c52a92a..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_sync.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_SYNC_ -#define H_BLE_LL_SYNC_ - -#include - -#include "nimble/nimble/include/nimble/ble.h" -#include "ble_ll_hci.h" -#include "ble_ll_conn.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct ble_ll_sync_sm; - -int ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb); -int ble_ll_sync_terminate(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_sync_list_add(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_sync_list_clear(void); -int ble_ll_sync_list_size(uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_sync_receive_enable(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_sync_transfer(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); - -void ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, - const uint8_t *sync_ind, bool reports_disabled, - uint16_t max_skip, uint32_t sync_timeout); -void ble_ll_sync_transfer_disconnected(struct ble_ll_conn_sm *connsm); - -void ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, - int rpa_index, uint8_t sid, - struct ble_mbuf_hdr *rxhdr, - const uint8_t *syncinfo); - -int ble_ll_sync_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr); -int ble_ll_sync_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr); -void ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr); -void ble_ll_sync_wfr_timer_exp(void); -void ble_ll_sync_halt(void); -void ble_ll_sync_rmvd_from_sched(struct ble_ll_sync_sm *sm); - -uint32_t ble_ll_sync_get_event_end_time(void); - -bool ble_ll_sync_enabled(void); - -void ble_ll_sync_reset(void); -void ble_ll_sync_init(void); - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_LL_SYNC_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_test.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_test.h deleted file mode 100644 index 32984c6b3..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_test.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_LL_TEST_ -#define H_LL_TEST_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -int ble_ll_csa2_test_all(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_trace.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_trace.h deleted file mode 100644 index f0af4de50..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_trace.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_TRACE_ -#define H_BLE_LL_TRACE_ - -#include "nimble/porting/nimble/include/os/os_trace_api.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define BLE_LL_TRACE_ID_SCHED 0 -#define BLE_LL_TRACE_ID_RX_START 1 -#define BLE_LL_TRACE_ID_RX_END 2 -#define BLE_LL_TRACE_ID_WFR_EXP 3 -#define BLE_LL_TRACE_ID_CTRL_RX 4 -#define BLE_LL_TRACE_ID_CONN_EV_START 5 -#define BLE_LL_TRACE_ID_CONN_EV_END 6 -#define BLE_LL_TRACE_ID_CONN_END 7 -#define BLE_LL_TRACE_ID_CONN_TX 8 -#define BLE_LL_TRACE_ID_CONN_RX 9 -#define BLE_LL_TRACE_ID_ADV_TXDONE 10 -#define BLE_LL_TRACE_ID_ADV_HALT 11 -#define BLE_LL_TRACE_ID_AUX_REF 12 -#define BLE_LL_TRACE_ID_AUX_UNREF 13 - -#if MYNEWT_VAL(BLE_LL_SYSVIEW) - -extern uint32_t ble_ll_trace_off; - -void ble_ll_trace_init(void); - -static inline void -ble_ll_trace_u32(unsigned id, uint32_t p1) -{ - os_trace_api_u32(ble_ll_trace_off + id, p1); -} - -static inline void -ble_ll_trace_u32x2(unsigned id, uint32_t p1, uint32_t p2) -{ - os_trace_api_u32x2(ble_ll_trace_off + id, p1, p2); -} - -static inline void -ble_ll_trace_u32x3(unsigned id, uint32_t p1, uint32_t p2, uint32_t p3) -{ - os_trace_api_u32x3(ble_ll_trace_off + id, p1, p2, p3); -} - -#else - -static inline void -ble_ll_trace_init(void) -{ -} - -static inline void -ble_ll_trace_u32(unsigned id, uint32_t p1) -{ -} - -static inline void -ble_ll_trace_u32x2(unsigned id, uint32_t p1, uint32_t p2) -{ -} - -static inline void -ble_ll_trace_u32x3(unsigned id, uint32_t p1, uint32_t p2, uint32_t p3) -{ -} - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_LL_TRACE_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_utils.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_utils.h deleted file mode 100644 index 248309009..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_utils.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include - -uint32_t ble_ll_utils_calc_access_addr(void); -uint8_t ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap); -uint8_t ble_ll_utils_calc_dci_csa2(uint16_t event_cntr, uint16_t channel_id, - uint8_t num_used_chans, const uint8_t *chanmap); -uint8_t ble_ll_utils_calc_num_used_chans(const uint8_t *chanmap); -uint32_t ble_ll_utils_calc_window_widening(uint32_t anchor_point, - uint32_t last_anchor_point, - uint8_t master_sca); diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_whitelist.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_whitelist.h deleted file mode 100644 index 2d3b6c5dd..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_ll_whitelist.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_WHITELIST_ -#define H_BLE_LL_WHITELIST_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Clear the whitelist */ -int ble_ll_whitelist_clear(void); - -/* Read the size of the whitelist */ -int ble_ll_whitelist_read_size(uint8_t *rspbuf, uint8_t *rsplen); - -/* Add a device to the whitelist */ -int ble_ll_whitelist_add(const uint8_t *cmdbuf, uint8_t len); - -/* Remove a device fromthe whitelist */ -int ble_ll_whitelist_rmv(const uint8_t *cmdbuf, uint8_t len); - -/* Enable whitelisting */ -void ble_ll_whitelist_enable(void); - -/* Disable whitelisting */ -void ble_ll_whitelist_disable(void); - -/* Boolean function returning true if address matches a whitelist entry */ -int ble_ll_whitelist_match(uint8_t *addr, uint8_t addr_type, int is_ident); - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_LL_WHITELIST_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_phy.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_phy.h deleted file mode 100644 index 49bb14ad4..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_phy.h +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_PHY_ -#define H_BLE_PHY_ - -#include "nimble/nimble/include/nimble/hci_common.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Forward declarations */ -struct os_mbuf; - -/* Channel/Frequency defintions */ -#define BLE_PHY_NUM_CHANS (40) -#define BLE_PHY_NUM_DATA_CHANS (37) -#define BLE_PHY_CHAN0_FREQ_MHZ (2402) -#define BLE_PHY_DATA_CHAN0_FREQ_MHZ (2404) -#define BLE_PHY_CHAN_SPACING_MHZ (2) -#define BLE_PHY_NUM_ADV_CHANS (3) -#define BLE_PHY_ADV_CHAN_START (37) - -/* Power */ -#define BLE_PHY_MAX_PWR_DBM (10) - -/* Deviation */ -#define BLE_PHY_DEV_KHZ (185) -#define BLE_PHY_BINARY_ZERO (-BLE_PHY_DEV) -#define BLE_PHY_BINARY_ONE (BLE_PHY_DEV) - -/* Max. clock drift */ -#define BLE_PHY_MAX_DRIFT_PPM (50) - -/* Data rate */ -#define BLE_PHY_BIT_RATE_BPS (1000000) - -/* Macros */ -#define BLE_IS_ADV_CHAN(chan) (chan >= BLE_PHY_ADV_CHAN_START) -#define BLE_IS_DATA_CHAN(chan) (chan < BLE_PHY_ADV_CHAN_START) - -/* PHY states */ -#define BLE_PHY_STATE_IDLE (0) -#define BLE_PHY_STATE_RX (1) -#define BLE_PHY_STATE_TX (2) - -/* BLE PHY transitions */ -#define BLE_PHY_TRANSITION_NONE (0) -#define BLE_PHY_TRANSITION_RX_TX (1) -#define BLE_PHY_TRANSITION_TX_RX (2) - -/* PHY error codes */ -#define BLE_PHY_ERR_RADIO_STATE (1) -#define BLE_PHY_ERR_INIT (2) -#define BLE_PHY_ERR_INV_PARAM (3) -#define BLE_PHY_ERR_NO_BUFS (4) -#define BLE_PHY_ERR_TX_LATE (5) -#define BLE_PHY_ERR_RX_LATE (6) - -/* Maximun PDU length. Includes LL header of 2 bytes and 255 bytes payload. */ -#define BLE_PHY_MAX_PDU_LEN (257) - -/* Wait for response timer */ -typedef void (*ble_phy_tx_end_func)(void *arg); - -/* Initialize the PHY */ -int ble_phy_init(void); - -/* Reset the PHY */ -int ble_phy_reset(void); - -/* Set the PHY channel */ -int ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit); - -/* Set transmit start time */ -int ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs); - -/* Set receive start time */ -int ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs); - -/* Set the transmit end callback and argument */ -void ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg); - -typedef uint8_t (*ble_phy_tx_pducb_t)(uint8_t *dptr, void *pducb_arg, - uint8_t *hdr_byte); - -/* Place the PHY into transmit mode */ -int ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans); - -/* Place the PHY into receive mode */ -int ble_phy_rx(void); - -/* Copies the received PHY buffer into the allocated pdu */ -void ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu); - -/* Set the transmit power */ -int ble_phy_txpwr_set(int dbm); - -/* Get highest allowed power from range */ -int ble_phy_txpower_round(int dbm); - -/* Get the transmit power */ -int ble_phy_txpwr_get(void); - -/* Set RX path power compensation value rounded to integer dB */ -void ble_phy_set_rx_pwr_compensation(int8_t compensation); - -/* Disable the PHY */ -void ble_phy_disable(void); - -#define BLE_PHY_WFR_ENABLE_RX (0) -#define BLE_PHY_WFR_ENABLE_TXRX (1) - -void ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs); - -/* Starts rf clock */ -void ble_phy_rfclk_enable(void); - -/* Stops rf clock */ -void ble_phy_rfclk_disable(void); - -/* - * Used to restart reception on same channel after wfr timer expiration or - * frame received. - */ -void ble_phy_restart_rx(void); - -/* Gets the current state of the PHY */ -int ble_phy_state_get(void); - -/* Gets current state of transceiver */ -uint8_t ble_phy_xcvr_state_get(void); - -/* Returns 'true' if a reception has started */ -int ble_phy_rx_started(void); - -/* - * Returns the maximum supported tx/rx PDU payload size, in bytes, for data - * channel PDUs (this does not apply to advertising channel PDUs). Note - * that the data channel PDU is composed of a 2-byte header, the payload, and - * an optional MIC. The maximum payload is 251 bytes. - */ -uint8_t ble_phy_max_data_pdu_pyld(void); - -/* Gets the current access address */ -uint32_t ble_phy_access_addr_get(void); - -/* Enable encryption */ -void ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_master); - -/* Disable encryption */ -void ble_phy_encrypt_disable(void); - -/* Set the packet counters and dir used by LE encyption */ -void ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir); - -/* Enable phy resolving list */ -void ble_phy_resolv_list_enable(void); - -/* Disable phy resolving list */ -void ble_phy_resolv_list_disable(void); - -/* - * PHY mode values for 1M, 2M and Coded S=8 are the same as corresponding values - * of PHY. This makes conversion between 'phy' and 'phy_mode' easier and it also - * means that default coding for Coded will be S=8, unless explicitly translated - * to S=2. - */ -#define BLE_PHY_MODE_CODED_500KBPS (0) -#define BLE_PHY_MODE_1M (1) -#define BLE_PHY_MODE_2M (2) -#define BLE_PHY_MODE_CODED_125KBPS (3) - -/* The number of different modes */ -#define BLE_PHY_NUM_MODE (4) - -/* PHY numbers (compatible with HCI) */ -#define BLE_PHY_1M (BLE_HCI_LE_PHY_1M) -#define BLE_PHY_2M (BLE_HCI_LE_PHY_2M) -#define BLE_PHY_CODED (BLE_HCI_LE_PHY_CODED) - -/* PHY bitmasks (compatible with HCI) */ -#define BLE_PHY_MASK_1M (BLE_HCI_LE_PHY_1M_PREF_MASK) -#define BLE_PHY_MASK_2M (BLE_HCI_LE_PHY_2M_PREF_MASK) -#define BLE_PHY_MASK_CODED (BLE_HCI_LE_PHY_CODED_PREF_MASK) - -#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)) -uint32_t ble_phy_mode_pdu_start_off(int phy); -void ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode); -#else -#define ble_phy_mode_pdu_start_off(phy) (40) - -#endif - -int ble_phy_get_cur_phy(void); -static inline int ble_ll_phy_to_phy_mode(int phy, int phy_options) -{ - int phy_mode; - - /* - * 'phy' value can be used as 'phy_mode' value unless S=2 coding is explicitly - * required. By default we'll use S=2 for Coded. - */ - phy_mode = phy; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - if (phy == BLE_PHY_CODED && phy_options == BLE_HCI_LE_PHY_CODED_S2_PREF) { - phy_mode = BLE_PHY_MODE_CODED_500KBPS; - } -#else - (void)phy_options; -#endif - - return phy_mode; -} - -#if MYNEWT_VAL(BLE_LL_DTM) -void ble_phy_enable_dtm(void); -void ble_phy_disable_dtm(void); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_PHY_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_phy_trace.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_phy_trace.h deleted file mode 100644 index c0dca7a0f..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/include/controller/ble_phy_trace.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_PHY_TRACE_ -#define H_BLE_PHY_TRACE_ - -#include "nimble/porting/nimble/include/os/os_trace_api.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define BLE_PHY_TRACE_ID_START_TX 0 -#define BLE_PHY_TRACE_ID_START_RX 1 -#define BLE_PHY_TRACE_ID_DISABLE 2 - -#if MYNEWT_VAL(BLE_PHY_SYSVIEW) - -extern uint32_t ble_phy_trace_off; - -void ble_phy_trace_init(void); - -static inline void -ble_phy_trace_void(unsigned id) -{ - os_trace_api_void(ble_phy_trace_off + id); -} - -static inline void -ble_phy_trace_u32(unsigned id, uint32_t p1) -{ - os_trace_api_u32(ble_phy_trace_off + id, p1); -} - -static inline void -ble_phy_trace_u32x2(unsigned id, uint32_t p1, uint32_t p2) -{ - os_trace_api_u32x2(ble_phy_trace_off + id, p1, p2); -} - -static inline void -ble_phy_trace_u32x3(unsigned id, uint32_t p1, uint32_t p2, uint32_t p3) -{ - os_trace_api_u32x3(ble_phy_trace_off + id, p1, p2, p3); -} - -#else - -static inline void -ble_phy_trace_init(void) -{ -} - -static inline void -ble_phy_trace_void(unsigned id) -{ -} - -static inline void -ble_phy_trace_u32(unsigned id, uint32_t p1) -{ -} - -static inline void -ble_phy_trace_u32x2(unsigned id, uint32_t p1, uint32_t p2) -{ -} - -static inline void -ble_phy_trace_u32x3(unsigned id, uint32_t p1, uint32_t p2, uint32_t p3) -{ -} - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_PHY_TRACE_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll.c deleted file mode 100644 index 9e4cf41c2..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll.c +++ /dev/null @@ -1,1725 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include -#include -#include -#include "nimble/porting/nimble/include/sysinit/sysinit.h" -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os.h" -#include "nimble/porting/nimble/include/os/os_cputime.h" -#include "nimble/porting/nimble/include/stats/stats.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "nimble/nimble/include/nimble/ble_hci_trans.h" -#include "../include/controller/ble_hw.h" -#include "../include/controller/ble_phy.h" -#include "../include/controller/ble_phy_trace.h" -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_adv.h" -#include "../include/controller/ble_ll_sched.h" -#include "../include/controller/ble_ll_scan.h" -#include "../include/controller/ble_ll_hci.h" -#include "../include/controller/ble_ll_whitelist.h" -#include "../include/controller/ble_ll_resolv.h" -#include "../include/controller/ble_ll_rfmgmt.h" -#include "../include/controller/ble_ll_trace.h" -#include "../include/controller/ble_ll_sync.h" -#include "ble_ll_conn_priv.h" - -#if MYNEWT_VAL(BLE_LL_DTM) -#include "ble_ll_dtm_priv.h" -#endif - -/* XXX: - * - * 1) use the sanity task! - * 2) Need to figure out what to do with packets that we hand up that did - * not pass the filter policy for the given state. Currently I count all - * packets I think. Need to figure out what to do with this. - * 3) For the features defined, we need to conditionally compile code. - * 4) Should look into always disabled the wfr interrupt if we receive the - * start of a frame. Need to look at the various states to see if this is the - * right thing to do. - */ - -/* Supported states */ -#define BLE_LL_S_NCA (0x00000000001) -#define BLE_LL_S_SA (0x00000000002) -#define BLE_LL_S_CA (0x00000000004) -#define BLE_LL_S_HDCA (0x00000000008) -#define BLE_LL_S_PS (0x00000000010) -#define BLE_LL_S_AS (0x00000000020) -#define BLE_LL_S_INIT (0x00000000040) -#define BLE_LL_S_SLAVE (0x00000000080) -#define BLE_LL_S_NCA_PS (0x00000000100) -#define BLE_LL_S_SA_PS (0x00000000200) -#define BLE_LL_S_CA_PS (0x00000000400) -#define BLE_LL_S_HDCA_PS (0x00000000800) -#define BLE_LL_S_NCA_AS (0x00000001000) -#define BLE_LL_S_SA_AS (0x00000002000) -#define BLE_LL_S_CA_AS (0x00000004000) -#define BLE_LL_S_HDCA_AS (0x00000008000) -#define BLE_LL_S_NCA_INIT (0x00000010000) -#define BLE_LL_S_SA_INIT (0x00000020000) -#define BLE_LL_S_NCA_MASTER (0x00000040000) -#define BLE_LL_S_SA_MASTER (0x00000080000) -#define BLE_LL_S_NCA_SLAVE (0x00000100000) -#define BLE_LL_S_SA_SLAVE (0x00000200000) -#define BLE_LL_S_PS_INIT (0x00000400000) -#define BLE_LL_S_AS_INIT (0x00000800000) -#define BLE_LL_S_PS_MASTER (0x00001000000) -#define BLE_LL_S_AS_MASTER (0x00002000000) -#define BLE_LL_S_PS_SLAVE (0x00004000000) -#define BLE_LL_S_AS_SLAVE (0x00008000000) -#define BLE_LL_S_INIT_MASTER (0x00010000000) -#define BLE_LL_S_LDCA (0x00020000000) -#define BLE_LL_S_LDCA_PS (0x00040000000) -#define BLE_LL_S_LDCA_AS (0x00080000000) -#define BLE_LL_S_CA_INIT (0x00100000000) -#define BLE_LL_S_HDCA_INIT (0x00200000000) -#define BLE_LL_S_LDCA_INIT (0x00400000000) -#define BLE_LL_S_CA_MASTER (0x00800000000) -#define BLE_LL_S_HDCA_MASTER (0x01000000000) -#define BLE_LL_S_LDCA_MASTER (0x02000000000) -#define BLE_LL_S_CA_SLAVE (0x04000000000) -#define BLE_LL_S_HDCA_SLAVE (0x08000000000) -#define BLE_LL_S_LDCA_SLAVE (0x10000000000) -#define BLE_LL_S_INIT_SLAVE (0x20000000000) - -#define BLE_LL_SUPPORTED_STATES \ -( \ - BLE_LL_S_NCA | \ - BLE_LL_S_SA | \ - BLE_LL_S_CA | \ - BLE_LL_S_HDCA | \ - BLE_LL_S_PS | \ - BLE_LL_S_AS | \ - BLE_LL_S_INIT | \ - BLE_LL_S_SLAVE | \ - BLE_LL_S_NCA_PS | \ - BLE_LL_S_SA_PS | \ - BLE_LL_S_CA_PS | \ - BLE_LL_S_HDCA_PS | \ - BLE_LL_S_NCA_AS | \ - BLE_LL_S_SA_AS | \ - BLE_LL_S_CA_AS | \ - BLE_LL_S_HDCA_AS | \ - BLE_LL_S_NCA_INIT | \ - BLE_LL_S_SA_INIT | \ - BLE_LL_S_NCA_MASTER | \ - BLE_LL_S_SA_MASTER | \ - BLE_LL_S_NCA_SLAVE | \ - BLE_LL_S_SA_SLAVE | \ - BLE_LL_S_PS_INIT | \ - BLE_LL_S_AS_INIT | \ - BLE_LL_S_PS_MASTER | \ - BLE_LL_S_AS_MASTER | \ - BLE_LL_S_PS_SLAVE | \ - BLE_LL_S_AS_SLAVE | \ - BLE_LL_S_INIT_MASTER | \ - BLE_LL_S_LDCA | \ - BLE_LL_S_LDCA_PS | \ - BLE_LL_S_LDCA_AS | \ - BLE_LL_S_CA_INIT | \ - BLE_LL_S_HDCA_INIT | \ - BLE_LL_S_LDCA_INIT | \ - BLE_LL_S_CA_MASTER | \ - BLE_LL_S_HDCA_MASTER | \ - BLE_LL_S_LDCA_MASTER | \ - BLE_LL_S_CA_SLAVE | \ - BLE_LL_S_HDCA_SLAVE | \ - BLE_LL_S_LDCA_SLAVE | \ - BLE_LL_S_INIT_SLAVE) - -/* The global BLE LL data object */ -struct ble_ll_obj g_ble_ll_data; - -/* Global link layer statistics */ -STATS_SECT_DECL(ble_ll_stats) ble_ll_stats; -STATS_NAME_START(ble_ll_stats) - STATS_NAME(ble_ll_stats, hci_cmds) - STATS_NAME(ble_ll_stats, hci_cmd_errs) - STATS_NAME(ble_ll_stats, hci_events_sent) - STATS_NAME(ble_ll_stats, bad_ll_state) - STATS_NAME(ble_ll_stats, bad_acl_hdr) - STATS_NAME(ble_ll_stats, no_bufs) - STATS_NAME(ble_ll_stats, rx_adv_pdu_crc_ok) - STATS_NAME(ble_ll_stats, rx_adv_pdu_crc_err) - STATS_NAME(ble_ll_stats, rx_adv_bytes_crc_ok) - STATS_NAME(ble_ll_stats, rx_adv_bytes_crc_err) - STATS_NAME(ble_ll_stats, rx_data_pdu_crc_ok) - STATS_NAME(ble_ll_stats, rx_data_pdu_crc_err) - STATS_NAME(ble_ll_stats, rx_data_bytes_crc_ok) - STATS_NAME(ble_ll_stats, rx_data_bytes_crc_err) - STATS_NAME(ble_ll_stats, rx_adv_malformed_pkts) - STATS_NAME(ble_ll_stats, rx_adv_ind) - STATS_NAME(ble_ll_stats, rx_adv_direct_ind) - STATS_NAME(ble_ll_stats, rx_adv_nonconn_ind) - STATS_NAME(ble_ll_stats, rx_adv_ext_ind) - STATS_NAME(ble_ll_stats, rx_scan_reqs) - STATS_NAME(ble_ll_stats, rx_scan_rsps) - STATS_NAME(ble_ll_stats, rx_connect_reqs) - STATS_NAME(ble_ll_stats, rx_scan_ind) - STATS_NAME(ble_ll_stats, rx_aux_connect_rsp) - STATS_NAME(ble_ll_stats, adv_txg) - STATS_NAME(ble_ll_stats, adv_late_starts) - STATS_NAME(ble_ll_stats, adv_resched_pdu_fail) - STATS_NAME(ble_ll_stats, adv_drop_event) - STATS_NAME(ble_ll_stats, sched_state_conn_errs) - STATS_NAME(ble_ll_stats, sched_state_adv_errs) - STATS_NAME(ble_ll_stats, scan_starts) - STATS_NAME(ble_ll_stats, scan_stops) - STATS_NAME(ble_ll_stats, scan_req_txf) - STATS_NAME(ble_ll_stats, scan_req_txg) - STATS_NAME(ble_ll_stats, scan_rsp_txg) - STATS_NAME(ble_ll_stats, aux_missed_adv) - STATS_NAME(ble_ll_stats, aux_scheduled) - STATS_NAME(ble_ll_stats, aux_received) - STATS_NAME(ble_ll_stats, aux_fired_for_read) - STATS_NAME(ble_ll_stats, aux_allocated) - STATS_NAME(ble_ll_stats, aux_freed) - STATS_NAME(ble_ll_stats, aux_sched_cb) - STATS_NAME(ble_ll_stats, aux_conn_req_tx) - STATS_NAME(ble_ll_stats, aux_conn_rsp_tx) - STATS_NAME(ble_ll_stats, aux_conn_rsp_err) - STATS_NAME(ble_ll_stats, aux_scan_req_tx) - STATS_NAME(ble_ll_stats, aux_scan_rsp_err) - STATS_NAME(ble_ll_stats, aux_chain_cnt) - STATS_NAME(ble_ll_stats, aux_chain_err) - STATS_NAME(ble_ll_stats, aux_scan_drop) - STATS_NAME(ble_ll_stats, adv_evt_dropped) - STATS_NAME(ble_ll_stats, scan_timer_stopped) - STATS_NAME(ble_ll_stats, scan_timer_restarted) - STATS_NAME(ble_ll_stats, periodic_adv_drop_event) - STATS_NAME(ble_ll_stats, periodic_chain_drop_event) - STATS_NAME(ble_ll_stats, sync_event_failed) - STATS_NAME(ble_ll_stats, sync_received) - STATS_NAME(ble_ll_stats, sync_chain_failed) - STATS_NAME(ble_ll_stats, sync_missed_err) - STATS_NAME(ble_ll_stats, sync_crc_err) - STATS_NAME(ble_ll_stats, sync_rx_buf_err) - STATS_NAME(ble_ll_stats, sync_scheduled) - STATS_NAME(ble_ll_stats, sched_state_sync_errs) - STATS_NAME(ble_ll_stats, sched_invalid_pdu) -STATS_NAME_END(ble_ll_stats) - -static void ble_ll_event_rx_pkt(struct ble_npl_event *ev); -static void ble_ll_event_tx_pkt(struct ble_npl_event *ev); -static void ble_ll_event_dbuf_overflow(struct ble_npl_event *ev); - -#if MYNEWT - -/* The BLE LL task data structure */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#define BLE_LL_STACK_SIZE (120) -#else -#define BLE_LL_STACK_SIZE (90) -#endif - -struct os_task g_ble_ll_task; - -OS_TASK_STACK_DEFINE(g_ble_ll_stack, BLE_LL_STACK_SIZE); - -#endif /* MYNEWT */ - -/** Our global device address (public) */ -uint8_t g_dev_addr[BLE_DEV_ADDR_LEN]; - -/** Our random address */ -uint8_t g_random_addr[BLE_DEV_ADDR_LEN]; - -static const uint16_t g_ble_ll_pdu_header_tx_time[BLE_PHY_NUM_MODE] = -{ - [BLE_PHY_MODE_1M] = - (BLE_LL_PREAMBLE_LEN + BLE_LL_ACC_ADDR_LEN + BLE_LL_CRC_LEN + - BLE_LL_PDU_HDR_LEN) << 3, - [BLE_PHY_MODE_2M] = - (BLE_LL_PREAMBLE_LEN * 2 + BLE_LL_ACC_ADDR_LEN + BLE_LL_CRC_LEN + - BLE_LL_PDU_HDR_LEN) << 2, - /* For Coded PHY we have exact TX times provided by specification: - * - Preamble, Access Address, CI, TERM1 (always coded as S=8) - * - PDU, CRC, TERM2 (coded as S=2 or S=8) - * (Vol 6, Part B, 2.2). - */ - [BLE_PHY_MODE_CODED_125KBPS] = - (80 + 256 + 16 + 24 + 8 * (BLE_LL_PDU_HDR_LEN * 8 + 24 + 3)), - [BLE_PHY_MODE_CODED_500KBPS] = - (80 + 256 + 16 + 24 + 2 * (BLE_LL_PDU_HDR_LEN * 8 + 24 + 3)), -}; - -/** - * Counts the number of advertising PDU's received, by type. For advertising - * PDU's that contain a destination address, we still count these packets even - * if they are not for us. - * - * @param pdu_type - */ -static void -ble_ll_count_rx_adv_pdus(uint8_t pdu_type) -{ - /* Count received packet types */ - switch (pdu_type) { - case BLE_ADV_PDU_TYPE_ADV_EXT_IND: - STATS_INC(ble_ll_stats, rx_adv_ext_ind); - break; - case BLE_ADV_PDU_TYPE_ADV_IND: - STATS_INC(ble_ll_stats, rx_adv_ind); - break; - case BLE_ADV_PDU_TYPE_ADV_DIRECT_IND: - STATS_INC(ble_ll_stats, rx_adv_direct_ind); - break; - case BLE_ADV_PDU_TYPE_ADV_NONCONN_IND: - STATS_INC(ble_ll_stats, rx_adv_nonconn_ind); - break; - case BLE_ADV_PDU_TYPE_SCAN_REQ: - STATS_INC(ble_ll_stats, rx_scan_reqs); - break; - case BLE_ADV_PDU_TYPE_SCAN_RSP: - STATS_INC(ble_ll_stats, rx_scan_rsps); - break; - case BLE_ADV_PDU_TYPE_CONNECT_IND: - STATS_INC(ble_ll_stats, rx_connect_reqs); - break; - case BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP: - STATS_INC(ble_ll_stats, rx_aux_connect_rsp); - break; - case BLE_ADV_PDU_TYPE_ADV_SCAN_IND: - STATS_INC(ble_ll_stats, rx_scan_ind); - break; - default: - break; - } -} - -struct os_mbuf * -ble_ll_rxpdu_alloc(uint16_t len) -{ - struct os_mbuf *om_ret; - struct os_mbuf *om_next; - struct os_mbuf *om; - struct os_mbuf_pkthdr *pkthdr; - uint16_t databuf_len; - int rem_len; - - /* - * Make sure that data in mbuf are word-aligned with and without packet - * header. This is essential for proper and quick copying of received PDUs - * into mbufs. - */ - _Static_assert((offsetof(struct os_mbuf, om_data) & 3) == 0, - "Unaligned om_data"); - _Static_assert(((offsetof(struct os_mbuf, om_data) + - sizeof(struct os_mbuf_pkthdr) + - sizeof(struct ble_mbuf_hdr)) & 3) == 0, - "Unaligned data trailing packet header"); - - om_ret = os_msys_get_pkthdr(len, sizeof(struct ble_mbuf_hdr)); - if (!om_ret) { - goto rxpdu_alloc_fail; - } - - /* Set complete PDU length in packet header */ - pkthdr = OS_MBUF_PKTHDR(om_ret); - pkthdr->omp_len = len; - - rem_len = len; - - /* - * Calculate length of data in memory block. We assume length is rounded - * down to word size so PHY can do word-size aligned data copy to mbufs - * (except for last one) and leave remainder unused. - * - * Note that there likely won't be any remainder here since all pools have - * block size aligned to word size anyway. - */ - databuf_len = om_ret->om_omp->omp_databuf_len & ~3; - - /* - * First mbuf can store less data due to packet header. Also we reserve one - * word for leading space to prepend header when necessary (like for data - * PDU before handing over to HCI) - */ - om_ret->om_data += 4; - rem_len -= databuf_len - om_ret->om_pkthdr_len - 4; - - /* Allocate and chain mbufs until there's enough space to store complete PDU */ - om = om_ret; - while (rem_len > 0) { - om_next = os_msys_get(rem_len, 0); - if (!om_next) { - os_mbuf_free_chain(om_ret); - goto rxpdu_alloc_fail; - } - - SLIST_NEXT(om, om_next) = om_next; - om = om_next; - - rem_len -= databuf_len; - } - - return om_ret; - -rxpdu_alloc_fail: - STATS_INC(ble_ll_stats, no_bufs); - return NULL; -} - -int -ble_ll_chk_txrx_octets(uint16_t octets) -{ - int rc; - - if ((octets < BLE_LL_CONN_SUPP_BYTES_MIN) || - (octets > BLE_LL_CONN_SUPP_BYTES_MAX)) { - rc = 0; - } else { - rc = 1; - } - - return rc; -} - -int -ble_ll_chk_txrx_time(uint16_t time) -{ - int rc; - - if ((time < BLE_LL_CONN_SUPP_TIME_MIN) || - (time > BLE_LL_CONN_SUPP_TIME_MAX)) { - rc = 0; - } else { - rc = 1; - } - - return rc; -} - -/** - * Checks to see if the address is a resolvable private address. - * - * NOTE: the addr_type parameter will be 0 if the address is public; - * any other value is random (all non-zero values). - * - * @param addr - * @param addr_type Public (zero) or Random (non-zero) address - * - * @return int - */ -int -ble_ll_is_rpa(const uint8_t *addr, uint8_t addr_type) -{ - int rc; - - if (addr_type && ((addr[5] & 0xc0) == 0x40)) { - rc = 1; - } else { - rc = 0; - } - return rc; -} - -int -ble_ll_addr_is_id(uint8_t *addr, uint8_t addr_type) -{ - return !addr_type || ((addr[5] & 0xc0) == 0xc0); -} - -int -ble_ll_addr_subtype(const uint8_t *addr, uint8_t addr_type) -{ - if (!addr_type) { - return BLE_LL_ADDR_SUBTYPE_IDENTITY; - } - - switch (addr[5] >> 6) { - case 0: - return BLE_LL_ADDR_SUBTYPE_NRPA; /* NRPA */ - case 1: - return BLE_LL_ADDR_SUBTYPE_RPA; /* RPA */ - default: - return BLE_LL_ADDR_SUBTYPE_IDENTITY; /* static random */ - } -} - -int -ble_ll_is_valid_public_addr(const uint8_t *addr) -{ - int i; - - for (i = 0; i < BLE_DEV_ADDR_LEN; ++i) { - if (addr[i]) { - return 1; - } - } - - return 0; -} - -/* Checks to see that the device is a valid random address */ -int -ble_ll_is_valid_random_addr(const uint8_t *addr) -{ - int i; - int rc; - uint16_t sum; - uint8_t addr_type; - - /* Make sure all bits are neither one nor zero */ - sum = 0; - for (i = 0; i < (BLE_DEV_ADDR_LEN -1); ++i) { - sum += addr[i]; - } - sum += addr[5] & 0x3f; - - if ((sum == 0) || (sum == ((5*255) + 0x3f))) { - return 0; - } - - /* Get the upper two bits of the address */ - rc = 1; - addr_type = addr[5] & 0xc0; - if (addr_type == 0xc0) { - /* Static random address. No other checks needed */ - } else if (addr_type == 0x40) { - /* Resolvable */ - sum = addr[3] + addr[4] + (addr[5] & 0x3f); - if ((sum == 0) || (sum == (255 + 255 + 0x3f))) { - rc = 0; - } - } else if (addr_type == 0) { - /* non-resolvable. Cant be equal to public */ - if (!memcmp(g_dev_addr, addr, BLE_DEV_ADDR_LEN)) { - rc = 0; - } - } else { - /* Invalid upper two bits */ - rc = 0; - } - - return rc; -} -int -ble_ll_is_valid_own_addr_type(uint8_t own_addr_type, const uint8_t *random_addr) -{ - int rc; - - switch (own_addr_type) { - case BLE_HCI_ADV_OWN_ADDR_PUBLIC: -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - case BLE_HCI_ADV_OWN_ADDR_PRIV_PUB: -#endif - rc = ble_ll_is_valid_public_addr(g_dev_addr); - break; - case BLE_HCI_ADV_OWN_ADDR_RANDOM: -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - case BLE_HCI_ADV_OWN_ADDR_PRIV_RAND: -#endif - rc = ble_ll_is_valid_random_addr(random_addr); - break; - default: - rc = 0; - break; - } - - return rc; -} - -int -ble_ll_set_public_addr(const uint8_t *addr) -{ - memcpy(g_dev_addr, addr, BLE_DEV_ADDR_LEN); - - return BLE_ERR_SUCCESS; -} - -/** - * Called from the HCI command parser when the set random address command - * is received. - * - * Context: Link Layer task (HCI command parser) - * - * @param addr Pointer to address - * - * @return int 0: success - */ -int -ble_ll_set_random_addr(const uint8_t *cmdbuf, uint8_t len, bool hci_adv_ext) -{ - const struct ble_hci_le_set_rand_addr_cp *cmd = (const void *) cmdbuf; - - if (len < sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* If the Host issues this command when scanning or legacy advertising is - * enabled, the Controller shall return the error code Command Disallowed. - * - * Test specification extends this also to initiating. - */ - - if (g_ble_ll_conn_create_sm || ble_ll_scan_enabled() || - (!hci_adv_ext && ble_ll_adv_enabled())) { - return BLE_ERR_CMD_DISALLOWED; - } - - if (!ble_ll_is_valid_random_addr(cmd->addr)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - memcpy(g_random_addr, cmd->addr, BLE_DEV_ADDR_LEN); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* For instance 0 we need same address if legacy advertising might be - * used. If extended advertising is in use than this command doesn't - * affect instance 0. - */ - if (!hci_adv_ext) - ble_ll_adv_set_random_addr(cmd->addr, 0); -#endif - - return BLE_ERR_SUCCESS; -} - -/** - * Checks to see if an address is our device address (either public or - * random) - * - * @param addr - * @param addr_type - * - * @return int 0: not our device address. 1: is our device address - */ -int -ble_ll_is_our_devaddr(uint8_t *addr, int addr_type) -{ - int rc; - uint8_t *our_addr; - - if (addr_type) { - our_addr = g_random_addr; - } else { - our_addr = g_dev_addr; - } - - rc = 0; - if (!memcmp(our_addr, addr, BLE_DEV_ADDR_LEN)) { - rc = 1; - } - - return rc; -} - -/** - * Get identity address - * - * @param addr_type Random (1). Public(0) - * - * @return pointer to identity address of given type. - */ -uint8_t* -ble_ll_get_our_devaddr(uint8_t addr_type) -{ - if (addr_type) { - return g_random_addr; - } - - return g_dev_addr; -} - -/** - * Wait for response timeout function - * - * Context: interrupt (ble scheduler) - * - * @param arg - */ -void -ble_ll_wfr_timer_exp(void *arg) -{ - int rx_start; - uint8_t lls; - - rx_start = ble_phy_rx_started(); - lls = g_ble_ll_data.ll_state; - - ble_ll_trace_u32x3(BLE_LL_TRACE_ID_WFR_EXP, lls, ble_phy_xcvr_state_get(), - (uint32_t)rx_start); - - /* If we have started a reception, there is nothing to do here */ - if (!rx_start) { - switch (lls) { - case BLE_LL_STATE_ADV: - ble_ll_adv_wfr_timer_exp(); - break; - case BLE_LL_STATE_CONNECTION: - ble_ll_conn_wfr_timer_exp(); - break; - case BLE_LL_STATE_SCANNING: - ble_ll_scan_wfr_timer_exp(); - break; - case BLE_LL_STATE_INITIATING: - ble_ll_conn_init_wfr_timer_exp(); - break; -#if MYNEWT_VAL(BLE_LL_DTM) - case BLE_LL_STATE_DTM: - ble_ll_dtm_wfr_timer_exp(); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - case BLE_LL_STATE_SYNC: - ble_ll_sync_wfr_timer_exp(); - break; -#endif - default: - break; - } - } -} - -/** - * ll tx pkt in proc - * - * Process ACL data packet input from host - * - * Context: Link layer task - * - */ -static void -ble_ll_tx_pkt_in(void) -{ - uint16_t handle; - uint16_t length; - uint16_t pb; - struct os_mbuf_pkthdr *pkthdr; - struct os_mbuf *om; - os_sr_t sr; - - /* Drain all packets off the queue */ - while (STAILQ_FIRST(&g_ble_ll_data.ll_tx_pkt_q)) { - /* Get mbuf pointer from packet header pointer */ - pkthdr = STAILQ_FIRST(&g_ble_ll_data.ll_tx_pkt_q); - om = (struct os_mbuf *)((uint8_t *)pkthdr - sizeof(struct os_mbuf)); - - /* Remove from queue */ - OS_ENTER_CRITICAL(sr); - STAILQ_REMOVE_HEAD(&g_ble_ll_data.ll_tx_pkt_q, omp_next); - OS_EXIT_CRITICAL(sr); - - /* Strip HCI ACL header to get handle and length */ - handle = get_le16(om->om_data); - length = get_le16(om->om_data + 2); - os_mbuf_adj(om, sizeof(struct hci_data_hdr)); - - /* Do some basic error checking */ - pb = handle & 0x3000; - if ((pkthdr->omp_len != length) || (pb > 0x1000) || (length == 0)) { - /* This is a bad ACL packet. Count a stat and free it */ - STATS_INC(ble_ll_stats, bad_acl_hdr); - os_mbuf_free_chain(om); - continue; - } - - /* Hand to connection state machine */ - ble_ll_conn_tx_pkt_in(om, handle, length); - } -} - -/** - * Count Link Layer statistics for received PDUs - * - * Context: Link layer task - * - * @param hdr - * @param len - */ -static void -ble_ll_count_rx_stats(struct ble_mbuf_hdr *hdr, uint16_t len, uint8_t pdu_type) -{ - uint8_t crcok; - bool connection_data; - - crcok = BLE_MBUF_HDR_CRC_OK(hdr); - connection_data = (BLE_MBUF_HDR_RX_STATE(hdr) == BLE_LL_STATE_CONNECTION); - -#if MYNEWT_VAL(BLE_LL_DTM) - /* Reuse connection stats for DTM */ - if (!connection_data) { - connection_data = (BLE_MBUF_HDR_RX_STATE(hdr) == BLE_LL_STATE_DTM); - } -#endif - - if (crcok) { - if (connection_data) { - STATS_INC(ble_ll_stats, rx_data_pdu_crc_ok); - STATS_INCN(ble_ll_stats, rx_data_bytes_crc_ok, len); - } else { - STATS_INC(ble_ll_stats, rx_adv_pdu_crc_ok); - STATS_INCN(ble_ll_stats, rx_adv_bytes_crc_ok, len); - ble_ll_count_rx_adv_pdus(pdu_type); - } - } else { - if (connection_data) { - STATS_INC(ble_ll_stats, rx_data_pdu_crc_err); - STATS_INCN(ble_ll_stats, rx_data_bytes_crc_err, len); - } else { - STATS_INC(ble_ll_stats, rx_adv_pdu_crc_err); - STATS_INCN(ble_ll_stats, rx_adv_bytes_crc_err, len); - } - } -} - -/** - * ll rx pkt in - * - * Process received packet from PHY. - * - * Context: Link layer task - * - */ -static void -ble_ll_rx_pkt_in(void) -{ - os_sr_t sr; - uint8_t pdu_type; - uint8_t *rxbuf; - struct os_mbuf_pkthdr *pkthdr; - struct ble_mbuf_hdr *ble_hdr; - struct os_mbuf *m; - - /* Drain all packets off the queue */ - while (STAILQ_FIRST(&g_ble_ll_data.ll_rx_pkt_q)) { - /* Get mbuf pointer from packet header pointer */ - pkthdr = STAILQ_FIRST(&g_ble_ll_data.ll_rx_pkt_q); - m = (struct os_mbuf *)((uint8_t *)pkthdr - sizeof(struct os_mbuf)); - - /* Remove from queue */ - OS_ENTER_CRITICAL(sr); - STAILQ_REMOVE_HEAD(&g_ble_ll_data.ll_rx_pkt_q, omp_next); - OS_EXIT_CRITICAL(sr); - - /* Note: pdu type wont get used unless this is an advertising pdu */ - ble_hdr = BLE_MBUF_HDR_PTR(m); - rxbuf = m->om_data; - pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK; - ble_ll_count_rx_stats(ble_hdr, pkthdr->omp_len, pdu_type); - - /* Process the data or advertising pdu */ - /* Process the PDU */ - switch (BLE_MBUF_HDR_RX_STATE(ble_hdr)) { - case BLE_LL_STATE_CONNECTION: - ble_ll_conn_rx_data_pdu(m, ble_hdr); - /* m is going to be free by function above */ - m = NULL; - break; - case BLE_LL_STATE_ADV: - ble_ll_adv_rx_pkt_in(pdu_type, rxbuf, ble_hdr); - break; - case BLE_LL_STATE_SCANNING: - ble_ll_scan_rx_pkt_in(pdu_type, m, ble_hdr); - break; - case BLE_LL_STATE_INITIATING: - ble_ll_init_rx_pkt_in(pdu_type, rxbuf, ble_hdr); - break; -#if MYNEWT_VAL(BLE_LL_DTM) - case BLE_LL_STATE_DTM: - ble_ll_dtm_rx_pkt_in(m, ble_hdr); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - case BLE_LL_STATE_SYNC: - ble_ll_sync_rx_pkt_in(m, ble_hdr); - break; -#endif - default: - /* Any other state should never occur */ - STATS_INC(ble_ll_stats, bad_ll_state); - break; - } - if (m) { - /* Free the packet buffer */ - os_mbuf_free_chain(m); - } - } -} - -/** - * Called to put a packet on the Link Layer receive packet queue. - * - * @param rxpdu Pointer to received PDU - */ -void -ble_ll_rx_pdu_in(struct os_mbuf *rxpdu) -{ - struct os_mbuf_pkthdr *pkthdr; - - pkthdr = OS_MBUF_PKTHDR(rxpdu); - STAILQ_INSERT_TAIL(&g_ble_ll_data.ll_rx_pkt_q, pkthdr, omp_next); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_data.ll_rx_pkt_ev); -} - -/** - * Called to put a packet on the Link Layer transmit packet queue. - * - * @param txpdu Pointer to transmit packet - */ -void -ble_ll_acl_data_in(struct os_mbuf *txpkt) -{ - os_sr_t sr; - struct os_mbuf_pkthdr *pkthdr; - - pkthdr = OS_MBUF_PKTHDR(txpkt); - OS_ENTER_CRITICAL(sr); - STAILQ_INSERT_TAIL(&g_ble_ll_data.ll_tx_pkt_q, pkthdr, omp_next); - OS_EXIT_CRITICAL(sr); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_data.ll_tx_pkt_ev); -} - -/** - * Called to post event to Link Layer when a data buffer overflow has - * occurred. - * - * Context: Interrupt - * - */ -void -ble_ll_data_buffer_overflow(void) -{ - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_data.ll_dbuf_overflow_ev); -} - -/** - * Called when a HW error occurs. - * - * Context: Interrupt - */ -void -ble_ll_hw_error(void) -{ - ble_npl_callout_reset(&g_ble_ll_data.ll_hw_err_timer, 0); -} - -/** - * Called when the HW error timer expires. - * - * @param arg - */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -static void -ble_ll_hw_err_timer_cb(struct ble_npl_event *ev) -{ - if (ble_ll_hci_ev_hw_err(BLE_HW_ERR_HCI_SYNC_LOSS)) { - /* - * Restart callout if failed to allocate event. Try to allocate an - * event every 50 milliseconds (or each OS tick if a tick is longer - * than 100 msecs). - */ - ble_npl_callout_reset(&g_ble_ll_data.ll_hw_err_timer, - ble_npl_time_ms_to_ticks32(50)); - } -} -#pragma GCC diagnostic pop - -/** - * Called upon start of received PDU - * - * Context: Interrupt - * - * @param rxpdu - * chan - * - * @return int - * < 0: A frame we dont want to receive. - * = 0: Continue to receive frame. Dont go from rx to tx - * > 0: Continue to receive frame and go from rx to tx when done - */ -int -ble_ll_rx_start(uint8_t *rxbuf, uint8_t chan, struct ble_mbuf_hdr *rxhdr) -{ - int rc; - uint8_t pdu_type; - - /* Advertising channel PDU */ - pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK; - - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_RX_START, g_ble_ll_data.ll_state, - pdu_type); - - switch (g_ble_ll_data.ll_state) { - case BLE_LL_STATE_CONNECTION: - rc = ble_ll_conn_rx_isr_start(rxhdr, ble_phy_access_addr_get()); - break; - case BLE_LL_STATE_ADV: - rc = ble_ll_adv_rx_isr_start(pdu_type); - break; - case BLE_LL_STATE_INITIATING: - rc = ble_ll_init_rx_isr_start(pdu_type, rxhdr); - break; - case BLE_LL_STATE_SCANNING: - rc = ble_ll_scan_rx_isr_start(pdu_type, &rxhdr->rxinfo.flags); - break; -#if MYNEWT_VAL(BLE_LL_DTM) - case BLE_LL_STATE_DTM: - rc = ble_ll_dtm_rx_isr_start(rxhdr, ble_phy_access_addr_get()); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - case BLE_LL_STATE_SYNC: - rc = ble_ll_sync_rx_isr_start(pdu_type, rxhdr); - break; -#endif - default: - /* Should not be in this state! */ - rc = -1; - STATS_INC(ble_ll_stats, bad_ll_state); - break; - } - - return rc; -} - -/** - * Called by the PHY when a receive packet has ended. - * - * NOTE: Called from interrupt context! - * - * @param rxbuf Pointer to received PDU data - * rxhdr Pointer to BLE header of received mbuf - * - * @return int - * < 0: Disable the phy after reception. - * == 0: Success. Do not disable the PHY. - * > 0: Do not disable PHY as that has already been done. - */ -int -ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) -{ - int rc; - int badpkt; - uint8_t pdu_type; - uint8_t len; - uint8_t crcok; - struct os_mbuf *rxpdu; - - /* Get CRC status from BLE header */ - crcok = BLE_MBUF_HDR_CRC_OK(rxhdr); - - /* Get advertising PDU type and length */ - pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK; - len = rxbuf[1]; - - ble_ll_trace_u32x3(BLE_LL_TRACE_ID_RX_END, pdu_type, len, - rxhdr->rxinfo.flags); - -#if MYNEWT_VAL(BLE_LL_DTM) - if (BLE_MBUF_HDR_RX_STATE(rxhdr) == BLE_LL_STATE_DTM) { - rc = ble_ll_dtm_rx_isr_end(rxbuf, rxhdr); - return rc; - } -#endif - - if (BLE_MBUF_HDR_RX_STATE(rxhdr) == BLE_LL_STATE_CONNECTION) { - rc = ble_ll_conn_rx_isr_end(rxbuf, rxhdr); - return rc; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - if (BLE_MBUF_HDR_RX_STATE(rxhdr) == BLE_LL_STATE_SYNC) { - rc = ble_ll_sync_rx_isr_end(rxbuf, rxhdr); - return rc; - } -#endif - - /* If the CRC checks, make sure lengths check! */ - badpkt = 0; - if (crcok) { - switch (pdu_type) { - case BLE_ADV_PDU_TYPE_SCAN_REQ: - case BLE_ADV_PDU_TYPE_ADV_DIRECT_IND: - if (len != BLE_SCAN_REQ_LEN) { - badpkt = 1; - } - break; - case BLE_ADV_PDU_TYPE_SCAN_RSP: - case BLE_ADV_PDU_TYPE_ADV_IND: - case BLE_ADV_PDU_TYPE_ADV_SCAN_IND: - case BLE_ADV_PDU_TYPE_ADV_NONCONN_IND: - if ((len < BLE_DEV_ADDR_LEN) || (len > BLE_ADV_SCAN_IND_MAX_LEN)) { - badpkt = 1; - } - break; - case BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP: - break; - case BLE_ADV_PDU_TYPE_ADV_EXT_IND: - break; - case BLE_ADV_PDU_TYPE_CONNECT_IND: - if (len != BLE_CONNECT_REQ_LEN) { - badpkt = 1; - } - break; - default: - badpkt = 1; - break; - } - - /* If this is a malformed packet, just kill it here */ - if (badpkt) { - STATS_INC(ble_ll_stats, rx_adv_malformed_pkts); - } - } - - /* Hand packet to the appropriate state machine (if crc ok) */ - rxpdu = NULL; - switch (BLE_MBUF_HDR_RX_STATE(rxhdr)) { - case BLE_LL_STATE_ADV: - if (!badpkt) { - rxpdu = ble_ll_rxpdu_alloc(len + BLE_LL_PDU_HDR_LEN); - if (rxpdu) { - ble_phy_rxpdu_copy(rxbuf, rxpdu); - } - } - rc = ble_ll_adv_rx_isr_end(pdu_type, rxpdu, crcok); - break; - case BLE_LL_STATE_SCANNING: - if (!badpkt) { - rxpdu = ble_ll_rxpdu_alloc(len + BLE_LL_PDU_HDR_LEN); - if (rxpdu) { - ble_phy_rxpdu_copy(rxbuf, rxpdu); - } - } - rc = ble_ll_scan_rx_isr_end(rxpdu, crcok); - break; - case BLE_LL_STATE_INITIATING: - rc = ble_ll_init_rx_isr_end(rxbuf, crcok, rxhdr); - break; - default: - rc = -1; - STATS_INC(ble_ll_stats, bad_ll_state); - break; - } - - /* Hand packet up to higher layer (regardless of CRC failure) */ - if (rxpdu) { - ble_ll_rx_pdu_in(rxpdu); - } - - return rc; -} - -uint8_t -ble_ll_tx_mbuf_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) -{ - struct os_mbuf *txpdu; - struct ble_mbuf_hdr *ble_hdr; - - txpdu = pducb_arg; - BLE_LL_ASSERT(txpdu); - ble_hdr = BLE_MBUF_HDR_PTR(txpdu); - - os_mbuf_copydata(txpdu, ble_hdr->txinfo.offset, ble_hdr->txinfo.pyld_len, - dptr); - - *hdr_byte = ble_hdr->txinfo.hdr_byte; - - return ble_hdr->txinfo.pyld_len; -} - -uint8_t -ble_ll_tx_flat_mbuf_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) -{ - struct os_mbuf *txpdu; - struct ble_mbuf_hdr *ble_hdr; - - txpdu = pducb_arg; - BLE_LL_ASSERT(txpdu); - ble_hdr = BLE_MBUF_HDR_PTR(txpdu); - - memcpy(dptr, txpdu->om_data, ble_hdr->txinfo.pyld_len); - - *hdr_byte = ble_hdr->txinfo.hdr_byte; - - return ble_hdr->txinfo.pyld_len; -} - -static void -ble_ll_event_rx_pkt(struct ble_npl_event *ev) -{ - ble_ll_rx_pkt_in(); -} - -static void -ble_ll_event_tx_pkt(struct ble_npl_event *ev) -{ - ble_ll_tx_pkt_in(); -} - -static void -ble_ll_event_dbuf_overflow(struct ble_npl_event *ev) -{ - ble_ll_hci_ev_databuf_overflow(); -} - -static void -ble_ll_event_comp_pkts(struct ble_npl_event *ev) -{ - ble_ll_conn_num_comp_pkts_event_send(NULL); -} - -/** - * Link Layer task. - * - * This is the task that runs the Link Layer. - * - * @param arg - */ -void -ble_ll_task(void *arg) -{ - struct ble_npl_event *ev; - - /* Init ble phy */ - ble_phy_init(); - - /* Set output power to 1mW (0 dBm) */ - ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM)); - - /* Register callback for transport */ - ble_hci_trans_cfg_ll(ble_ll_hci_cmd_rx, NULL, ble_ll_hci_acl_rx, NULL); - - /* Tell the host that we are ready to receive packets */ - ble_ll_hci_send_noop(); - - while (1) { - ev = ble_npl_eventq_get(&g_ble_ll_data.ll_evq, BLE_NPL_TIME_FOREVER); - assert(ev); - ble_npl_event_run(ev); - } -} - -/** - * ble ll state set - * - * Called to set the current link layer state. - * - * Context: Interrupt and Link Layer task - * - * @param ll_state - */ -void -ble_ll_state_set(uint8_t ll_state) -{ - g_ble_ll_data.ll_state = ll_state; -} - -/** - * ble ll state get - * - * Called to get the current link layer state. - * - * Context: Link Layer task (can be called from interrupt context though). - * - * @return ll_state - */ -uint8_t -ble_ll_state_get(void) -{ - return g_ble_ll_data.ll_state; -} - -/** - * ble ll event send - * - * Send an event to the Link Layer task - * - * @param ev Event to add to the Link Layer event queue. - */ -void -ble_ll_event_send(struct ble_npl_event *ev) -{ - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, ev); -} - -/** - * Returns the features supported by the link layer - * - * @return uint8_t bitmask of supported features. - */ -uint64_t -ble_ll_read_supp_states(void) -{ - return BLE_LL_SUPPORTED_STATES; -} - -/** - * Returns the features supported by the link layer - * - * @return uint64_t bitmask of supported features. - */ -uint64_t -ble_ll_read_supp_features(void) -{ - return g_ble_ll_data.ll_supp_features; -} - -/** - * Sets the features controlled by the host. - * - * @return HCI command status - */ -int -ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_host_feat_cp *cmd = (const void *) cmdbuf; - uint64_t mask; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (!SLIST_EMPTY(&g_ble_ll_conn_active_list)) { - return BLE_ERR_CMD_DISALLOWED; - } - - if ((cmd->bit_num > 0x3F) || (cmd->val > 1)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - mask = (uint64_t)1 << (cmd->bit_num); - if (!(mask & BLE_LL_HOST_CONTROLLED_FEATURES)) { - return BLE_ERR_UNSUPPORTED; - } - - if (cmd->val == 0) { - g_ble_ll_data.ll_supp_features &= ~(mask); - } else { - g_ble_ll_data.ll_supp_features |= mask; - } - - return BLE_ERR_SUCCESS; -} -/** - * Flush a link layer packet queue. - * - * @param pktq - */ -static void -ble_ll_flush_pkt_queue(struct ble_ll_pkt_q *pktq) -{ - struct os_mbuf_pkthdr *pkthdr; - struct os_mbuf *om; - - /* FLush all packets from Link layer queues */ - while (STAILQ_FIRST(pktq)) { - /* Get mbuf pointer from packet header pointer */ - pkthdr = STAILQ_FIRST(pktq); - om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); - - /* Remove from queue and free the mbuf */ - STAILQ_REMOVE_HEAD(pktq, omp_next); - os_mbuf_free_chain(om); - } -} - -/** - * Called to initialize a mbuf used by the controller - * - * NOTE: this is only used when the mbuf is created by the controller; - * it should not be used for data packets (ACL data packets) that come from - * the host. This routine assumes that the entire pdu length can fit in - * one mbuf contiguously. - * - * @param m - * @param pdulen - * @param hdr - */ -void -ble_ll_mbuf_init(struct os_mbuf *m, uint8_t pdulen, uint8_t hdr) -{ - struct ble_mbuf_hdr *ble_hdr; - - /* Set mbuf length and packet length */ - m->om_len = pdulen; - OS_MBUF_PKTHDR(m)->omp_len = pdulen; - - /* Set BLE transmit header */ - ble_hdr = BLE_MBUF_HDR_PTR(m); - ble_hdr->txinfo.flags = 0; - ble_hdr->txinfo.offset = 0; - ble_hdr->txinfo.pyld_len = pdulen; - ble_hdr->txinfo.hdr_byte = hdr; -} - -static void -ble_ll_validate_task(void) -{ -#ifdef MYNEWT -#ifndef NDEBUG - struct os_task_info oti; - - os_task_info_get(&g_ble_ll_task, &oti); - - BLE_LL_ASSERT(oti.oti_stkusage < oti.oti_stksize); -#endif -#endif -} - -/** - * Called to reset the controller. This performs a "software reset" of the link - * layer; it does not perform a HW reset of the controller nor does it reset - * the HCI interface. - * - * Context: Link Layer task (HCI command) - * - * @return int The ble error code to place in the command complete event that - * is returned when this command is issued. - */ -int -ble_ll_reset(void) -{ - int rc; - os_sr_t sr; - - /* do sanity check on LL task stack */ - ble_ll_validate_task(); - - OS_ENTER_CRITICAL(sr); - ble_phy_disable(); - ble_ll_sched_stop(); - ble_ll_scan_reset(); - ble_ll_rfmgmt_reset(); - OS_EXIT_CRITICAL(sr); - - /* Stop any advertising */ - ble_ll_adv_reset(); - -#if MYNEWT_VAL(BLE_LL_DTM) - ble_ll_dtm_reset(); -#endif - - /* Stop sync */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - ble_ll_sync_reset(); -#endif - - /* FLush all packets from Link layer queues */ - ble_ll_flush_pkt_queue(&g_ble_ll_data.ll_tx_pkt_q); - ble_ll_flush_pkt_queue(&g_ble_ll_data.ll_rx_pkt_q); - - /* Reset LL stats */ - STATS_RESET(ble_ll_stats); - - /* Reset any preferred PHYs */ - g_ble_ll_data.ll_pref_tx_phys = 0; - g_ble_ll_data.ll_pref_rx_phys = 0; - - /* Reset connection module */ - ble_ll_conn_module_reset(); - - /* All this does is re-initialize the event masks so call the hci init */ - ble_ll_hci_init(); - - /* Reset scheduler */ - ble_ll_sched_init(); - - /* Set state to standby */ - ble_ll_state_set(BLE_LL_STATE_STANDBY); - - /* Reset our random address */ - memset(g_random_addr, 0, BLE_DEV_ADDR_LEN); - - /* Clear the whitelist */ - ble_ll_whitelist_clear(); - - /* Reset resolving list */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - ble_ll_resolv_list_reset(); -#endif - - /* Re-initialize the PHY */ - rc = ble_phy_init(); - - return rc; -} - -uint32_t -ble_ll_pdu_tx_time_get(uint16_t payload_len, int phy_mode) -{ - uint32_t usecs; - -#if (BLE_LL_BT5_PHY_SUPPORTED) - if (phy_mode == BLE_PHY_MODE_1M) { - /* 8 usecs per byte */ - usecs = payload_len << 3; - } else if (phy_mode == BLE_PHY_MODE_2M) { - /* 4 usecs per byte */ - usecs = payload_len << 2; - } else if (phy_mode == BLE_PHY_MODE_CODED_125KBPS) { - /* S=8 => 8 * 8 = 64 usecs per byte */ - usecs = payload_len << 6; - } else if (phy_mode == BLE_PHY_MODE_CODED_500KBPS) { - /* S=2 => 2 * 8 = 16 usecs per byte */ - usecs = payload_len << 4; - } else { - BLE_LL_ASSERT(0); - } - - usecs += g_ble_ll_pdu_header_tx_time[phy_mode]; -#else - usecs = (((payload_len) + BLE_LL_PDU_HDR_LEN + BLE_LL_ACC_ADDR_LEN - + BLE_LL_PREAMBLE_LEN + BLE_LL_CRC_LEN) << 3); -#endif - - return usecs; -} - -uint16_t -ble_ll_pdu_max_tx_octets_get(uint32_t usecs, int phy_mode) -{ - uint32_t header_tx_time; - uint16_t octets = 0; - - BLE_LL_ASSERT(phy_mode < BLE_PHY_NUM_MODE); - - header_tx_time = g_ble_ll_pdu_header_tx_time[phy_mode]; - - /* - * Current conn max tx time can be too short to even send a packet header - * and this can happen if we changed connection form uncoded to coded phy. - * However, the lower bound for conn max tx time (all of them) depends on - * current phy (uncoded/coded) but it always allows to send at least 27 - * bytes of payload thus we alwyas return at least 27 from here. - * - * Reference: - * Core v5.0, Vol 6, Part B, section 4.5.10 - * see connEffectiveMaxTxTime and connEffectiveMaxRxTime definitions - */ - - if (usecs < header_tx_time) { - return 27; - } - - usecs -= header_tx_time; - - if (phy_mode == BLE_PHY_MODE_1M) { - /* 8 usecs per byte */ - octets = usecs >> 3; - } else if (phy_mode == BLE_PHY_MODE_2M) { - /* 4 usecs per byte */ - octets = usecs >> 2; - } else if (phy_mode == BLE_PHY_MODE_CODED_125KBPS) { - /* S=8 => 8 * 8 = 64 usecs per byte */ - octets = usecs >> 6; - } else if (phy_mode == BLE_PHY_MODE_CODED_500KBPS) { - /* S=2 => 2 * 8 = 16 usecs per byte */ - octets = usecs >> 4; - } else { - BLE_LL_ASSERT(0); - } - - /* see comment at the beginning */ - return max(27, octets); -} - -static inline bool -ble_ll_is_addr_empty(const uint8_t *addr) -{ - return memcmp(addr, BLE_ADDR_ANY, BLE_DEV_ADDR_LEN) == 0; -} - -/** - * Initialize the Link Layer. Should be called only once - * - * @return int - */ -void -ble_ll_init(void) -{ - int rc; - uint64_t features; - ble_addr_t addr; - struct ble_ll_obj *lldata; - - /* Ensure this function only gets called by sysinit. */ - SYSINIT_ASSERT_ACTIVE(); - - ble_ll_trace_init(); - ble_phy_trace_init(); - - /* Set public device address if not already set */ - if (ble_ll_is_addr_empty(g_dev_addr)) { - /* Use sycfg address if configured, otherwise try to read from HW */ - if (!ble_ll_is_addr_empty(MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR))) { - memcpy(g_dev_addr, MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), BLE_DEV_ADDR_LEN); - } else { - rc = ble_hw_get_public_addr(&addr); - if (!rc) { - memcpy(g_dev_addr, &addr.val[0], BLE_DEV_ADDR_LEN); - } - } - } - - ble_ll_rfmgmt_init(); - - /* Get pointer to global data object */ - lldata = &g_ble_ll_data; - - /* Set acl pkt size and number */ - lldata->ll_num_acl_pkts = MYNEWT_VAL(BLE_ACL_BUF_COUNT); - lldata->ll_acl_pkt_size = MYNEWT_VAL(BLE_ACL_BUF_SIZE); - - /* Initialize eventq */ - ble_npl_eventq_init(&lldata->ll_evq); - - /* Initialize the transmit (from host) and receive (from phy) queues */ - STAILQ_INIT(&lldata->ll_tx_pkt_q); - STAILQ_INIT(&lldata->ll_rx_pkt_q); - - /* Initialize transmit (from host) and receive packet (from phy) event */ - ble_npl_event_init(&lldata->ll_rx_pkt_ev, ble_ll_event_rx_pkt, NULL); - ble_npl_event_init(&lldata->ll_tx_pkt_ev, ble_ll_event_tx_pkt, NULL); - - /* Initialize data buffer overflow event and completed packets */ - ble_npl_event_init(&lldata->ll_dbuf_overflow_ev, ble_ll_event_dbuf_overflow, NULL); - ble_npl_event_init(&lldata->ll_comp_pkt_ev, ble_ll_event_comp_pkts, NULL); - - /* Initialize the HW error timer */ - /* NOT USED WITH RAM HCI - * Commented out to prevent creating an unnecessary timer - ble_npl_callout_init(&g_ble_ll_data.ll_hw_err_timer, - &g_ble_ll_data.ll_evq, - ble_ll_hw_err_timer_cb, - NULL); - */ - - /* Initialize LL HCI */ - ble_ll_hci_init(); - - /* Init the scheduler */ - ble_ll_sched_init(); - - /* Initialize advertiser */ - ble_ll_adv_init(); - - /* Initialize a scanner */ - ble_ll_scan_init(); - - /* Initialize the connection module */ - ble_ll_conn_module_init(); - - /* Set the supported features. NOTE: we always support extended reject. */ - features = BLE_LL_FEAT_EXTENDED_REJ; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) - features |= BLE_LL_FEAT_DATA_LEN_EXT; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CONN_PARAM_REQ) - features |= BLE_LL_FEAT_CONN_PARM_REQ; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG) - features |= BLE_LL_FEAT_SLAVE_INIT; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - features |= BLE_LL_FEAT_LE_ENCRYPTION; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - features |= (BLE_LL_FEAT_LL_PRIVACY | BLE_LL_FEAT_EXT_SCAN_FILT); - ble_ll_resolv_init(); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) - features |= BLE_LL_FEAT_LE_PING; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - features |= BLE_LL_FEAT_EXT_ADV; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - /* CSA2 */ - features |= BLE_LL_FEAT_CSA2; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - features |= BLE_LL_FEAT_LE_2M_PHY; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - features |= BLE_LL_FEAT_LE_CODED_PHY; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - features |= BLE_LL_FEAT_PERIODIC_ADV; - ble_ll_sync_init(); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - features |= BLE_LL_FEAT_SYNC_TRANS_RECV; - features |= BLE_LL_FEAT_SYNC_TRANS_SEND; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) - features |= BLE_LL_FEAT_SCA_UPDATE; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) - features |= BLE_LL_FEAT_CIS_MASTER; - features |= BLE_LL_FEAT_CIS_SLAVE; - features |= BLE_LL_FEAT_ISO_BROADCASTER; - features |= BLE_LL_FEAT_ISO_HOST_SUPPORT; -#endif - - lldata->ll_supp_features = features; - - /* Initialize random number generation */ - ble_ll_rand_init(); - /* Start the random number generator */ - ble_ll_rand_start(); - - rc = stats_init_and_reg(STATS_HDR(ble_ll_stats), - STATS_SIZE_INIT_PARMS(ble_ll_stats, STATS_SIZE_32), - STATS_NAME_INIT_PARMS(ble_ll_stats), - "ble_ll"); - SYSINIT_PANIC_ASSERT(rc == 0); - -#if MYNEWT_VAL(BLE_LL_DTM) - ble_ll_dtm_init(); -#endif - -#if MYNEWT - /* Initialize the LL task */ - os_task_init(&g_ble_ll_task, "ble_ll", ble_ll_task, NULL, - MYNEWT_VAL(BLE_LL_PRIO), OS_WAIT_FOREVER, g_ble_ll_stack, - BLE_LL_STACK_SIZE); -#else - -/* - * For non-Mynewt OS it is required that OS creates task for LL and run LL - * routine which is wrapped by nimble_port_ll_task_func(). - */ - -#endif -} - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_adv.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_adv.c deleted file mode 100644 index 4e1b74887..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_adv.c +++ /dev/null @@ -1,5151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os.h" -#include "nimble/porting/nimble/include/os/os_cputime.h" - -#if defined(ARDUINO_ARCH_NRF5) && defined(NRF51) -#include "nimble/nimble/drivers/nrf51/include/ble/xcvr.h" -#elif defined(ARDUINO_ARCH_NRF5) && defined(NRF52_SERIES) -#include "nimble/nimble/drivers/nrf52/include/ble/xcvr.h" -#endif - -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "nimble/nimble/include/nimble/ble_hci_trans.h" -#include "../include/controller/ble_phy.h" -#include "../include/controller/ble_hw.h" -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_hci.h" -#include "../include/controller/ble_ll_adv.h" -#include "../include/controller/ble_ll_sched.h" -#include "../include/controller/ble_ll_scan.h" -#include "../include/controller/ble_ll_whitelist.h" -#include "../include/controller/ble_ll_resolv.h" -#include "../include/controller/ble_ll_trace.h" -#include "../include/controller/ble_ll_utils.h" -#include "../include/controller/ble_ll_rfmgmt.h" -#include "ble_ll_conn_priv.h" - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(array) \ - (sizeof(array) / sizeof((array)[0])) -#endif - -/* XXX: TODO - * 1) Need to look at advertising and scan request PDUs. Do I allocate these - * once? Do I use a different pool for smaller ones? Do I statically declare - * them? - * 3) How do features get supported? What happens if device does not support - * advertising? (for example) - * 4) How to determine the advertising interval we will actually use. As of - * now, we set it to max. - */ - -/* Scheduling data for secondary channel */ -struct ble_ll_adv_aux { - struct ble_ll_sched_item sch; - uint32_t start_time; - uint16_t aux_data_offset; - uint8_t chan; - uint8_t ext_hdr; - uint8_t aux_data_len; - uint8_t payload_len; -}; - -/* Scheduling data for sync PDUs */ -struct ble_ll_adv_sync { - struct ble_ll_sched_item sch; - uint32_t start_time; - uint16_t sync_data_offset; - uint8_t chan; - uint8_t ext_hdr; - uint8_t sync_data_len; - uint8_t payload_len; -}; - -/* - * Advertising state machine - * - * The advertising state machine data structure. - * - * adv_pdu_len - * The length of the advertising PDU that will be sent. This does not - * include the preamble, access address and CRC. - * - * initiator_addr: - * This is the address that we send in directed advertisements (the - * INITA field). If we are using Privacy this is a RPA that we need to - * generate. We reserve space in the advsm to save time when creating - * the ADV_DIRECT_IND. If own address type is not 2 or 3, this is simply - * the peer address from the set advertising parameters. - */ -struct ble_ll_adv_sm -{ - uint8_t adv_enabled; - uint8_t adv_instance; - uint8_t adv_chanmask; - uint8_t adv_filter_policy; - uint8_t own_addr_type; - uint8_t peer_addr_type; - uint8_t adv_chan; - uint8_t adv_pdu_len; - int8_t adv_rpa_index; - int8_t adv_txpwr; - uint16_t flags; - uint16_t props; - uint16_t adv_itvl_min; - uint16_t adv_itvl_max; - uint32_t adv_itvl_usecs; - uint32_t adv_event_start_time; - uint32_t adv_pdu_start_time; - uint32_t adv_end_time; - uint32_t adv_rpa_timer; - uint8_t adva[BLE_DEV_ADDR_LEN]; - uint8_t adv_rpa[BLE_DEV_ADDR_LEN]; - uint8_t peer_addr[BLE_DEV_ADDR_LEN]; - uint8_t initiator_addr[BLE_DEV_ADDR_LEN]; - struct os_mbuf *adv_data; - struct os_mbuf *new_adv_data; - struct os_mbuf *scan_rsp_data; - struct os_mbuf *new_scan_rsp_data; - uint8_t *conn_comp_ev; - struct ble_npl_event adv_txdone_ev; - struct ble_ll_sched_item adv_sch; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - uint16_t channel_id; - uint16_t event_cntr; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - uint8_t aux_active : 1; - uint8_t aux_index : 1; - uint8_t aux_first_pdu : 1; - uint8_t aux_not_scanned : 1; - uint8_t aux_dropped : 1; - struct ble_mbuf_hdr *rx_ble_hdr; - struct os_mbuf **aux_data; - struct ble_ll_adv_aux aux[2]; - struct ble_npl_event adv_sec_txdone_ev; - uint16_t duration; - uint16_t adi; - uint8_t adv_random_addr[BLE_DEV_ADDR_LEN]; - uint8_t events_max; - uint8_t events; - uint8_t pri_phy; - uint8_t sec_phy; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - struct os_mbuf *periodic_adv_data; - struct os_mbuf *periodic_new_data; - uint32_t periodic_crcinit; /* only 3 bytes are used */ - uint32_t periodic_access_addr; - uint16_t periodic_adv_itvl_min; - uint16_t periodic_adv_itvl_max; - uint16_t periodic_adv_props; - uint16_t periodic_channel_id; - uint16_t periodic_event_cntr; - uint16_t periodic_chain_event_cntr; - uint8_t periodic_adv_enabled : 1; - uint8_t periodic_adv_active : 1; - uint8_t periodic_sync_active : 1; - uint8_t periodic_sync_index : 1; - uint8_t periodic_num_used_chans; - uint8_t periodic_chanmap[BLE_LL_CONN_CHMAP_LEN]; - uint32_t periodic_adv_itvl_ticks; - uint8_t periodic_adv_itvl_rem_usec; - uint8_t periodic_adv_event_start_time_remainder; - uint32_t periodic_adv_event_start_time; - struct ble_ll_adv_sync periodic_sync[2]; - struct ble_npl_event adv_periodic_txdone_ev; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - uint16_t periodic_event_cntr_last_sent; -#endif -#endif -#endif -}; - -#define BLE_LL_ADV_SM_FLAG_TX_ADD 0x0001 -#define BLE_LL_ADV_SM_FLAG_RX_ADD 0x0002 -#define BLE_LL_ADV_SM_FLAG_SCAN_REQ_NOTIF 0x0004 -#define BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD 0x0008 -#define BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK 0x0030 /* use helpers! */ -#define BLE_LL_ADV_SM_FLAG_ADV_DATA_INCOMPLETE 0x0040 -#define BLE_LL_ADV_SM_FLAG_CONFIGURED 0x0080 -#define BLE_LL_ADV_SM_FLAG_ADV_RPA_TMO 0x0100 -#define BLE_LL_ADV_SM_FLAG_NEW_ADV_DATA 0x0200 -#define BLE_LL_ADV_SM_FLAG_NEW_SCAN_RSP_DATA 0x0400 -#define BLE_LL_ADV_SM_FLAG_PERIODIC_CONFIGURED 0x0800 -#define BLE_LL_ADV_SM_FLAG_PERIODIC_DATA_INCOMPLETE 0x1000 -#define BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING 0x2000 -#define BLE_LL_ADV_SM_FLAG_PERIODIC_NEW_DATA 0x4000 - -#define ADV_DATA_LEN(_advsm) \ - ((_advsm->adv_data) ? OS_MBUF_PKTLEN(advsm->adv_data) : 0) -#define SCAN_RSP_DATA_LEN(_advsm) \ - ((_advsm->scan_rsp_data) ? OS_MBUF_PKTLEN(advsm->scan_rsp_data) : 0) -#define AUX_DATA_LEN(_advsm) \ - (*(_advsm->aux_data) ? OS_MBUF_PKTLEN(*advsm->aux_data) : 0) - -#define AUX_CURRENT(_advsm) (&(_advsm->aux[_advsm->aux_index])) -#define AUX_NEXT(_advsm) (&(_advsm->aux[_advsm->aux_index ^ 1])) - -#define SYNC_CURRENT(_advsm) (&(_advsm->periodic_sync[_advsm->periodic_sync_index])) -#define SYNC_NEXT(_advsm) (&(_advsm->periodic_sync[_advsm->periodic_sync_index ^ 1])) -#define SYNC_DATA_LEN(_advsm) \ - (_advsm->periodic_adv_data ? OS_MBUF_PKTLEN(advsm->periodic_adv_data) : 0) - -/* The advertising state machine global object */ -struct ble_ll_adv_sm g_ble_ll_adv_sm[BLE_ADV_INSTANCES]; -struct ble_ll_adv_sm *g_ble_ll_cur_adv_sm; - -static struct ble_ll_adv_sm * -ble_ll_adv_sm_find_configured(uint8_t instance) -{ - struct ble_ll_adv_sm *advsm; - int i; - - /* in legacy mode we only allow instance 0 */ - if (!ble_ll_hci_adv_mode_ext()) { - BLE_LL_ASSERT(instance == 0); - return &g_ble_ll_adv_sm[0]; - } - - for (i = 0; i < ARRAY_SIZE(g_ble_ll_adv_sm); i++) { - advsm = &g_ble_ll_adv_sm[i]; - - if ((advsm->flags & BLE_LL_ADV_SM_FLAG_CONFIGURED) && - (advsm->adv_instance == instance)) { - return advsm; - } - } - - return NULL; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static int -ble_ll_adv_active_chanset_is_pri(struct ble_ll_adv_sm *advsm) -{ - return (advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK) == 0x10; -} - -static int -ble_ll_adv_active_chanset_is_sec(struct ble_ll_adv_sm *advsm) -{ - return (advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK) == 0x20; -} -#endif - -static void -ble_ll_adv_active_chanset_clear(struct ble_ll_adv_sm *advsm) -{ - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - advsm->flags &= ~BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK; - OS_EXIT_CRITICAL(sr); -} - -static void -ble_ll_adv_active_chanset_set_pri(struct ble_ll_adv_sm *advsm) -{ - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - assert((advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK) == 0); - advsm->flags &= ~BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK; - advsm->flags |= 0x10; - OS_EXIT_CRITICAL(sr); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_adv_active_chanset_set_sec(struct ble_ll_adv_sm *advsm) -{ - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - assert((advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK) == 0); - advsm->flags &= ~BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK; - advsm->flags |= 0x20; - OS_EXIT_CRITICAL(sr); -} -#endif - -static void -ble_ll_adv_flags_set(struct ble_ll_adv_sm *advsm, uint16_t flags) -{ - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - advsm->flags |= flags; - OS_EXIT_CRITICAL(sr); -} - -static void -ble_ll_adv_flags_clear(struct ble_ll_adv_sm *advsm, uint16_t flags) -{ - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - advsm->flags &= ~flags; - OS_EXIT_CRITICAL(sr); -} - -static void ble_ll_adv_make_done(struct ble_ll_adv_sm *advsm, struct ble_mbuf_hdr *hdr); -static void ble_ll_adv_sm_init(struct ble_ll_adv_sm *advsm); -static void ble_ll_adv_sm_stop_timeout(struct ble_ll_adv_sm *advsm); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -static void -ble_ll_adv_rpa_update(struct ble_ll_adv_sm *advsm) -{ - if (ble_ll_resolv_gen_rpa(advsm->peer_addr, advsm->peer_addr_type, - advsm->adva, 1)) { - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_TX_ADD); - } else { - if (advsm->own_addr_type & 1) { - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_TX_ADD); - } else { - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_TX_ADD); - } - } - - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { - if (ble_ll_resolv_gen_rpa(advsm->peer_addr, advsm->peer_addr_type, - advsm->initiator_addr, 0)) { - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_RX_ADD); - } else { - if (advsm->peer_addr_type & 1) { - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_RX_ADD); - } else { - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_RX_ADD); - } - } - } -} - -/** - * Called to change advertisers ADVA and INITA (for directed advertisements) - * as an advertiser needs to adhere to the resolvable private address generation - * timer. - * - * NOTE: the resolvable private address code uses its own timer to regenerate - * local resolvable private addresses. The advertising code uses its own - * timer to reset the INITA (for directed advertisements). This code also sets - * the appropriate txadd and rxadd bits that will go into the advertisement. - * - * Another thing to note: it is possible that an IRK is all zeroes in the - * resolving list. That is why we need to check if the generated address is - * in fact a RPA as a resolving list entry with all zeroes will use the - * identity address (which may be a private address or public). - * - * @param advsm - */ -void -ble_ll_adv_chk_rpa_timeout(struct ble_ll_adv_sm *advsm) -{ - if (advsm->own_addr_type < BLE_HCI_ADV_OWN_ADDR_PRIV_PUB) { - return; - } - - if (advsm->flags & BLE_LL_ADV_SM_FLAG_ADV_RPA_TMO) { - ble_ll_adv_rpa_update(advsm); - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_ADV_RPA_TMO); - } -} - -void -ble_ll_adv_rpa_timeout(void) -{ - struct ble_ll_adv_sm *advsm; - int i; - - for (i = 0; i < BLE_ADV_INSTANCES; i++) { - advsm = &g_ble_ll_adv_sm[i]; - - if (advsm->adv_enabled && - advsm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { - /* Mark RPA as timed out so we get a new RPA */ - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_ADV_RPA_TMO); - } - } -} -#endif - -/** - * Calculate the first channel that we should advertise upon when we start - * an advertising event. - * - * @param advsm - * - * @return uint8_t The number of the first channel usable for advertising. - */ -static uint8_t -ble_ll_adv_first_chan(struct ble_ll_adv_sm *advsm) -{ - uint8_t adv_chan; - - /* Set first advertising channel */ - if (advsm->adv_chanmask & 0x01) { - adv_chan = BLE_PHY_ADV_CHAN_START; - } else if (advsm->adv_chanmask & 0x02) { - adv_chan = BLE_PHY_ADV_CHAN_START + 1; - } else { - adv_chan = BLE_PHY_ADV_CHAN_START + 2; - } - - return adv_chan; -} - -/** - * Calculate the final channel that we should advertise upon when we start - * an advertising event. - * - * @param advsm - * - * @return uint8_t The number of the final channel usable for advertising. - */ -static uint8_t -ble_ll_adv_final_chan(struct ble_ll_adv_sm *advsm) -{ - uint8_t adv_chan; - - if (advsm->adv_chanmask & 0x04) { - adv_chan = BLE_PHY_ADV_CHAN_START + 2; - } else if (advsm->adv_chanmask & 0x02) { - adv_chan = BLE_PHY_ADV_CHAN_START + 1; - } else { - adv_chan = BLE_PHY_ADV_CHAN_START; - } - - return adv_chan; -} - -/** - * Create the advertising legacy PDU - * - * @param advsm Pointer to advertisement state machine - */ -static uint8_t -ble_ll_adv_legacy_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) -{ - struct ble_ll_adv_sm *advsm; - uint8_t adv_data_len; - uint8_t pdulen; - uint8_t pdu_type; - - advsm = pducb_arg; - - /* assume this is not a direct ind */ - adv_data_len = ADV_DATA_LEN(advsm); - pdulen = BLE_DEV_ADDR_LEN + adv_data_len; - - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { - pdu_type = BLE_ADV_PDU_TYPE_ADV_DIRECT_IND; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - pdu_type |= BLE_ADV_PDU_HDR_CHSEL; -#endif - - if (advsm->flags & BLE_LL_ADV_SM_FLAG_RX_ADD) { - pdu_type |= BLE_ADV_PDU_HDR_RXADD_RAND; - } - - adv_data_len = 0; - pdulen = BLE_ADV_DIRECT_IND_LEN; - } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { - pdu_type = BLE_ADV_PDU_TYPE_ADV_IND; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - pdu_type |= BLE_ADV_PDU_HDR_CHSEL; -#endif - } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) { - pdu_type = BLE_ADV_PDU_TYPE_ADV_SCAN_IND; - } else { - pdu_type = BLE_ADV_PDU_TYPE_ADV_NONCONN_IND; - } - - /* An invalid advertising data length indicates a memory overwrite */ - assert(adv_data_len <= BLE_ADV_LEGACY_DATA_MAX_LEN); - - /* Set the PDU length in the state machine (includes header) */ - advsm->adv_pdu_len = pdulen + BLE_LL_PDU_HDR_LEN; - - /* Set TxAdd to random if needed. */ - if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { - pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND; - } - - *hdr_byte = pdu_type; - - /* Construct advertisement */ - memcpy(dptr, advsm->adva, BLE_DEV_ADDR_LEN); - dptr += BLE_DEV_ADDR_LEN; - - /* For ADV_DIRECT_IND add inita */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { - memcpy(dptr, advsm->initiator_addr, BLE_DEV_ADDR_LEN); - } - - /* Copy in advertising data, if any */ - if (adv_data_len != 0) { - os_mbuf_copydata(advsm->adv_data, 0, adv_data_len, dptr); - } - - return pdulen; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_adv_put_aux_ptr(uint8_t chan, uint8_t phy, uint32_t offset, - uint8_t *dptr) -{ - dptr[0] = chan; - - if (offset > 245700) { - dptr[0] |= 0x80; - offset = offset / 300; - } else { - offset = offset / 30; - } - - if (offset > 0x1fff) { - offset = 0; - } - - /* offset is 13bits and PHY 3 bits */ - dptr[1] = (offset & 0x000000ff); - dptr[2] = ((offset >> 8) & 0x0000001f) | (phy - 1) << 5; -} - -/** - * Create the advertising PDU - */ -static uint8_t -ble_ll_adv_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) -{ - struct ble_ll_adv_sm *advsm; - uint8_t pdu_type; - uint8_t adv_mode; - uint8_t ext_hdr_len; - uint8_t ext_hdr_flags; - uint32_t offset; - - advsm = pducb_arg; - - assert(ble_ll_adv_active_chanset_is_pri(advsm)); - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - return ble_ll_adv_legacy_pdu_make(dptr, advsm, hdr_byte); - } - - /* only ADV_EXT_IND goes on primary advertising channels */ - pdu_type = BLE_ADV_PDU_TYPE_ADV_EXT_IND; - - /* Set TxAdd to random if needed. */ - if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { - pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND; - } - - *hdr_byte = pdu_type; - - adv_mode = 0; - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { - adv_mode |= BLE_LL_EXT_ADV_MODE_CONN; - } - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) { - adv_mode |= BLE_LL_EXT_ADV_MODE_SCAN; - } - - ext_hdr_len = BLE_LL_EXT_ADV_FLAGS_SIZE + BLE_LL_EXT_ADV_DATA_INFO_SIZE + - BLE_LL_EXT_ADV_AUX_PTR_SIZE; - ext_hdr_flags = (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT) | - (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT); - - /* ext hdr len and adv mode */ - dptr[0] = ext_hdr_len | (adv_mode << 6); - dptr += 1; - - /* ext hdr flags */ - dptr[0] = ext_hdr_flags; - dptr += 1; - - /* ADI */ - dptr[0] = advsm->adi & 0x00ff; - dptr[1] = advsm->adi >> 8; - dptr += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - - /* AuxPtr */ - if (AUX_CURRENT(advsm)->sch.enqueued) { - offset = os_cputime_ticks_to_usecs(AUX_CURRENT(advsm)->start_time - advsm->adv_pdu_start_time); - } else { - offset = 0; - } - /* Always use channel from 1st AUX */ - ble_ll_adv_put_aux_ptr(AUX_CURRENT(advsm)->chan, advsm->sec_phy, - offset, dptr); - - return BLE_LL_EXT_ADV_HDR_LEN + ext_hdr_len; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) -static void -ble_ll_adv_put_syncinfo(struct ble_ll_adv_sm *advsm, - struct ble_ll_conn_sm *connsm, uint8_t *conn_event_cnt, - uint8_t *dptr) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - uint8_t anchor_usecs; - uint16_t conn_cnt; -#endif - unsigned int event_cnt_off = 0; - uint32_t offset = 0; - uint32_t anchor; - uint8_t units; - - if (connsm) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - anchor = connsm->anchor_point; - anchor_usecs = connsm->anchor_point_usecs; - conn_cnt = connsm->event_cntr; - - /* get anchor for conn event that is before periodic_adv_event_start_time */ - while (CPUTIME_GT(anchor, advsm->periodic_adv_event_start_time)) { - ble_ll_conn_get_anchor(connsm, --conn_cnt, &anchor, &anchor_usecs); - } - - offset = os_cputime_ticks_to_usecs(advsm->periodic_adv_event_start_time - anchor); - offset -= anchor_usecs; - offset += advsm->periodic_adv_event_start_time_remainder; - - /* connEventCount */ - put_le16(conn_event_cnt, conn_cnt); -#endif - } else { - anchor = advsm->periodic_adv_event_start_time; - - /* Get periodic event that is past AUX start time (so that we always - * provide valid offset if it is not too far in future). This can - * happen if advertising event is interleaved with periodic advertising - * event (when chaining). - */ - while (CPUTIME_GT(AUX_CURRENT(advsm)->start_time, anchor)) { - anchor += advsm->periodic_adv_itvl_ticks; - event_cnt_off++; - } - - offset = os_cputime_ticks_to_usecs(anchor - AUX_CURRENT(advsm)->start_time); - offset += advsm->periodic_adv_event_start_time_remainder; - offset += advsm->periodic_adv_itvl_rem_usec; - } - - /* Sync Packet Offset (13 bits), Offset Units (1 bit), Offset Adjust (1 bit), - * RFU (1 bit) - */ - if (offset > 245700) { - units = 0x20; - offset = offset / 300; - - if (offset >= 0x2000) { - if (connsm) { - offset -= 0x2000; - units |= 0x40; - } else { - /* not able to represent time in offset */ - offset = 0; - units = 0x00; - event_cnt_off = 0; - } - } - - } else { - units = 0x00; - offset = offset / 30; - } - - dptr[0] = (offset & 0x000000ff); - dptr[1] = ((offset >> 8) & 0x0000001f) | units; - - /* Interval (2 bytes) */ - put_le16(&dptr[2], advsm->periodic_adv_itvl_max); - - /* Channels Mask (37 bits) */ - dptr[4] = advsm->periodic_chanmap[0]; - dptr[5] = advsm->periodic_chanmap[1]; - dptr[6] = advsm->periodic_chanmap[2]; - dptr[7] = advsm->periodic_chanmap[3]; - dptr[8] = advsm->periodic_chanmap[4] & 0x1f; - - /* SCA (3 bits) */ - dptr[8] |= BLE_LL_SCA_ENUM << 5; - - /* AA (4 bytes) */ - put_le32(&dptr[9], advsm->periodic_access_addr); - - /* CRCInit (3 bytes) */ - dptr[13] = (uint8_t)advsm->periodic_crcinit; - dptr[14] = (uint8_t)(advsm->periodic_crcinit >> 8); - dptr[15] = (uint8_t)(advsm->periodic_crcinit >> 16); - - /* Event Counter (2 bytes) */ - put_le16(&dptr[16], advsm->periodic_event_cntr + event_cnt_off); -} -#endif - -/** - * Create the AUX PDU - */ -static uint8_t -ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) -{ - struct ble_ll_adv_sm *advsm; - struct ble_ll_adv_aux *aux; - uint8_t adv_mode; - uint8_t pdu_type; - uint8_t ext_hdr_len; - uint32_t offset; - - advsm = pducb_arg; - aux = AUX_CURRENT(advsm); - - assert(!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)); - assert(ble_ll_adv_active_chanset_is_sec(advsm)); - - /* It's the same for AUX_ADV_IND and AUX_CHAIN_IND */ - pdu_type = BLE_ADV_PDU_TYPE_AUX_ADV_IND; - - /* We do not create scannable PDUs here - this is handled separately */ - adv_mode = 0; - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { - adv_mode |= BLE_LL_EXT_ADV_MODE_CONN; - } - - ext_hdr_len = aux->payload_len - BLE_LL_EXT_ADV_HDR_LEN - aux->aux_data_len; - dptr[0] = (adv_mode << 6) | ext_hdr_len; - dptr += 1; - - /* only put flags if needed */ - if (aux->ext_hdr) { - dptr[0] = aux->ext_hdr; - dptr += 1; - } - - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - - /* Set TxAdd to random if needed. */ - if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { - pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND; - } - - memcpy(dptr, advsm->adva, BLE_LL_EXT_ADV_ADVA_SIZE); - dptr += BLE_LL_EXT_ADV_ADVA_SIZE; - } - - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - memcpy(dptr, advsm->initiator_addr, BLE_LL_EXT_ADV_TARGETA_SIZE); - dptr += BLE_LL_EXT_ADV_TARGETA_SIZE; - - /* Set RxAdd to random if needed. */ - if (advsm->flags & BLE_LL_ADV_SM_FLAG_RX_ADD) { - pdu_type |= BLE_ADV_PDU_HDR_RXADD_RAND; - } - } - - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { - dptr[0] = advsm->adi & 0x00ff; - dptr[1] = advsm->adi >> 8; - dptr += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - } - - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { - if (!AUX_NEXT(advsm)->sch.enqueued) { - /* - * Trim data here in case we do not have next aux scheduled. This - * can happen if next aux was outside advertising set period and - * was removed from scheduler. - */ - offset = 0; - } else if (advsm->rx_ble_hdr) { - offset = os_cputime_ticks_to_usecs(AUX_NEXT(advsm)->start_time - advsm->rx_ble_hdr->beg_cputime); - offset -= (advsm->rx_ble_hdr->rem_usecs + ble_ll_pdu_tx_time_get(12, advsm->sec_phy) + BLE_LL_IFS); - } else { - offset = os_cputime_ticks_to_usecs(AUX_NEXT(advsm)->start_time - aux->start_time); - } - - ble_ll_adv_put_aux_ptr(AUX_NEXT(advsm)->chan, advsm->sec_phy, - offset, dptr); - - dptr += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { - ble_ll_adv_put_syncinfo(advsm, NULL, NULL, dptr); - dptr += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; - } -#endif - - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { - dptr[0] = advsm->adv_txpwr + ble_ll_get_tx_pwr_compensation(); - dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE; - } - - if (aux->aux_data_len) { - os_mbuf_copydata(*advsm->aux_data, aux->aux_data_offset, - aux->aux_data_len, dptr); - } - - *hdr_byte = pdu_type; - - return aux->payload_len; -} - -static uint8_t -ble_ll_adv_aux_scannable_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) -{ - struct ble_ll_adv_sm *advsm; - uint8_t pdu_type; - uint8_t *ext_hdr_len; - uint8_t *ext_hdr; - uint8_t pdulen; - - advsm = pducb_arg; - - assert(!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)); - assert(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE); - assert(advsm->aux_first_pdu); - assert(ble_ll_adv_active_chanset_is_sec(advsm)); - - pdu_type = BLE_ADV_PDU_TYPE_AUX_ADV_IND; - - ext_hdr_len = &dptr[0]; - ext_hdr = &dptr[1]; - dptr += 2; - - /* Flags always */ - *ext_hdr_len = BLE_LL_EXT_ADV_FLAGS_SIZE; - *ext_hdr = 0; - - /* AdvA when non anonymous */ - if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV)) { - /* Set TxAdd to random if needed. */ - if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { - pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND; - } - - *ext_hdr_len += BLE_LL_EXT_ADV_ADVA_SIZE; - *ext_hdr |= (1 << BLE_LL_EXT_ADV_ADVA_BIT); - memcpy(dptr, advsm->adva, BLE_LL_EXT_ADV_ADVA_SIZE); - dptr += BLE_LL_EXT_ADV_ADVA_SIZE; - } - - /* TargetA only for directed */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { - *ext_hdr_len += BLE_LL_EXT_ADV_TARGETA_SIZE; - *ext_hdr |= (1 << BLE_LL_EXT_ADV_TARGETA_BIT); - memcpy(dptr, advsm->initiator_addr, BLE_LL_EXT_ADV_TARGETA_SIZE); - dptr += BLE_LL_EXT_ADV_TARGETA_SIZE; - - /* Set RxAdd to random if needed. */ - if (advsm->flags & BLE_LL_ADV_SM_FLAG_RX_ADD) { - pdu_type |= BLE_ADV_PDU_HDR_RXADD_RAND; - } - } - - /* ADI always */ - *ext_hdr_len += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - *ext_hdr |= (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT); - dptr[0] = advsm->adi & 0x00ff; - dptr[1] = advsm->adi >> 8; - dptr += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - - /* TxPower if configured */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR) { - *ext_hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; - *ext_hdr |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); - dptr[0] = advsm->adv_txpwr + ble_ll_get_tx_pwr_compensation(); - dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE; - } - - pdulen = BLE_LL_EXT_ADV_HDR_LEN + *ext_hdr_len; - - *hdr_byte = pdu_type; - *ext_hdr_len |= (BLE_LL_EXT_ADV_MODE_SCAN << 6); - - return pdulen; -} -#endif - -static uint8_t -ble_ll_adv_scan_rsp_legacy_pdu_make(uint8_t *dptr, void *pducb_arg, - uint8_t *hdr_byte) -{ - struct ble_ll_adv_sm *advsm; - uint8_t scan_rsp_len; - uint8_t pdulen; - uint8_t hdr; - - advsm = pducb_arg; - - /* Make sure that the length is valid */ - scan_rsp_len = SCAN_RSP_DATA_LEN(advsm); - assert(scan_rsp_len <= BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN); - - /* Set BLE transmit header */ - pdulen = BLE_DEV_ADDR_LEN + scan_rsp_len; - hdr = BLE_ADV_PDU_TYPE_SCAN_RSP; - if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { - hdr |= BLE_ADV_PDU_HDR_TXADD_RAND; - } - - *hdr_byte = hdr; - - /* - * The adva in this packet will be the same one that was being advertised - * and is based on the peer identity address in the set advertising - * parameters. If a different peer sends us a scan request (for some reason) - * we will reply with an adva that was not generated based on the local irk - * of the peer sending the scan request. - */ - - /* Construct scan response */ - memcpy(dptr, advsm->adva, BLE_DEV_ADDR_LEN); - if (scan_rsp_len != 0) { - os_mbuf_copydata(advsm->scan_rsp_data, 0, scan_rsp_len, - dptr + BLE_DEV_ADDR_LEN); - } - - return pdulen; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -/** - * Create a scan response PDU - * - * @param advsm - */ -static uint8_t -ble_ll_adv_scan_rsp_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) -{ - struct ble_ll_adv_sm *advsm; - - advsm = pducb_arg; - - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - return ble_ll_adv_scan_rsp_legacy_pdu_make(dptr, pducb_arg, hdr_byte); - } - - return ble_ll_adv_aux_pdu_make(dptr, pducb_arg, hdr_byte); -} - -struct aux_conn_rsp_data { - struct ble_ll_adv_sm *advsm; - uint8_t *peer; - uint8_t rxadd; -}; - -/** - * Create a AUX connect response PDU - * - * @param advsm - */ -static uint8_t -ble_ll_adv_aux_conn_rsp_pdu_make(uint8_t *dptr, void *pducb_arg, - uint8_t *hdr_byte) -{ - struct aux_conn_rsp_data *rsp_data; - uint8_t pdulen; - uint8_t ext_hdr_len; - uint8_t ext_hdr_flags; - uint8_t hdr; - - rsp_data = pducb_arg; - - /* flags,AdvA and TargetA */ - ext_hdr_len = BLE_LL_EXT_ADV_FLAGS_SIZE + BLE_LL_EXT_ADV_ADVA_SIZE + - BLE_LL_EXT_ADV_TARGETA_SIZE; - ext_hdr_flags = (1 << BLE_LL_EXT_ADV_ADVA_BIT); - ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_TARGETA_BIT); - - pdulen = BLE_LL_EXT_ADV_HDR_LEN + ext_hdr_len; - - /* Set BLE transmit header */ - hdr = BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP; - if (rsp_data->rxadd) { - hdr |= BLE_ADV_PDU_HDR_RXADD_MASK; - } - if (rsp_data->advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { - hdr |= BLE_ADV_PDU_HDR_TXADD_MASK; - } - - *hdr_byte = hdr; - - /* ext hdr len and adv mode (00b) */ - dptr[0] = ext_hdr_len; - dptr += 1; - - /* ext hdr flags */ - dptr[0] = ext_hdr_flags; - dptr += 1; - - memcpy(dptr, rsp_data->advsm->adva, BLE_LL_EXT_ADV_ADVA_SIZE); - dptr += BLE_LL_EXT_ADV_ADVA_SIZE; - - memcpy(dptr, rsp_data->peer, BLE_LL_EXT_ADV_TARGETA_SIZE); - dptr += BLE_LL_EXT_ADV_ADVA_SIZE; - - return pdulen; -} -#endif - -/** - * Called to indicate the advertising event is over. - * - * Context: Interrupt - * - * @param advsm - * - */ -static void -ble_ll_adv_tx_done(void *arg) -{ - struct ble_ll_adv_sm *advsm; - - /* reset power to max after advertising */ - ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM)); - - advsm = (struct ble_ll_adv_sm *)arg; - - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_ADV_TXDONE, advsm->adv_instance, - advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (ble_ll_adv_active_chanset_is_pri(advsm)) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); - } else if (ble_ll_adv_active_chanset_is_sec(advsm)) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); - } else { - assert(0); - } -#else - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); -#endif - - ble_ll_state_set(BLE_LL_STATE_STANDBY); - - ble_ll_adv_active_chanset_clear(advsm); - - /* We no longer have a current state machine */ - g_ble_ll_cur_adv_sm = NULL; -} - -/* - * Called when an advertising event has been removed from the scheduler - * without being run. - */ -void -ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm *advsm) -{ - /* - * Need to set advertising channel to final chan so new event gets - * scheduled. - */ - advsm->adv_chan = ble_ll_adv_final_chan(advsm); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) -/* - * Called when a periodic event has been removed from the scheduler - * without being run. - */ -void -ble_ll_adv_periodic_rmvd_from_sched(struct ble_ll_adv_sm *advsm) -{ - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_periodic_txdone_ev); -} -#endif - -/** - * This is the scheduler callback (called from interrupt context) which - * transmits an advertisement. - * - * Context: Interrupt (scheduler) - * - * @param sch - * - * @return int - */ -static int -ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch) -{ - int rc; - uint8_t end_trans; - uint32_t txstart; - struct ble_ll_adv_sm *advsm; - - /* Get the state machine for the event */ - advsm = (struct ble_ll_adv_sm *)sch->cb_arg; - - /* Set the current advertiser */ - g_ble_ll_cur_adv_sm = advsm; - - ble_ll_adv_active_chanset_set_pri(advsm); - - if ((advsm->flags & BLE_LL_ADV_SM_FLAG_NEW_ADV_DATA) || - (advsm->flags & BLE_LL_ADV_SM_FLAG_NEW_SCAN_RSP_DATA)) { - goto adv_tx_done; - } - - /* Set the power */ - ble_phy_txpwr_set(advsm->adv_txpwr); - - /* Set channel */ - rc = ble_phy_setchan(advsm->adv_chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); - assert(rc == 0); - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - /* Set phy mode */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - ble_phy_mode_set(BLE_PHY_MODE_1M, BLE_PHY_MODE_1M); - } else { - ble_phy_mode_set(advsm->pri_phy, advsm->pri_phy); - } -#else - ble_phy_mode_set(BLE_PHY_MODE_1M, BLE_PHY_MODE_1M); -#endif -#endif - - /* Set transmit start time. */ - txstart = sch->start_time + g_ble_ll_sched_offset_ticks; - rc = ble_phy_tx_set_start_time(txstart, sch->remainder); - if (rc) { - STATS_INC(ble_ll_stats, adv_late_starts); - goto adv_tx_done; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - ble_phy_encrypt_disable(); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - advsm->adv_rpa_index = -1; - if (ble_ll_resolv_enabled()) { - ble_phy_resolv_list_enable(); - } else { - ble_phy_resolv_list_disable(); - } -#endif - - /* We switch to RX after connectable or scannable legacy packets. */ - if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && - ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) || - (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE))) { - end_trans = BLE_PHY_TRANSITION_TX_RX; - ble_phy_set_txend_cb(NULL, NULL); - } else { - end_trans = BLE_PHY_TRANSITION_NONE; - ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm); - } - - /* Transmit advertisement */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - rc = ble_phy_tx(ble_ll_adv_pdu_make, advsm, end_trans); -#else - rc = ble_phy_tx(ble_ll_adv_legacy_pdu_make, advsm, end_trans); -#endif - if (rc) { - goto adv_tx_done; - } - - /* Enable/disable whitelisting based on filter policy */ - if (advsm->adv_filter_policy != BLE_HCI_ADV_FILT_NONE) { - ble_ll_whitelist_enable(); - } else { - ble_ll_whitelist_disable(); - } - - /* Set link layer state to advertising */ - ble_ll_state_set(BLE_LL_STATE_ADV); - - /* Count # of adv. sent */ - STATS_INC(ble_ll_stats, adv_txg); - - return BLE_LL_SCHED_STATE_RUNNING; - -adv_tx_done: - ble_ll_adv_tx_done(advsm); - return BLE_LL_SCHED_STATE_DONE; -} - -static void -ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm) -{ - uint32_t max_usecs; - struct ble_ll_sched_item *sch; - - sch = &advsm->adv_sch; - sch->cb_arg = advsm; - sch->sched_cb = ble_ll_adv_tx_start_cb; - sch->sched_type = BLE_LL_SCHED_TYPE_ADV; - - /* Set end time to maximum time this schedule item may take */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - max_usecs = ble_ll_pdu_tx_time_get(advsm->adv_pdu_len, BLE_PHY_MODE_1M); - - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { - max_usecs += BLE_LL_SCHED_DIRECT_ADV_MAX_USECS; - } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { - max_usecs += BLE_LL_SCHED_ADV_MAX_USECS; - } - } else { - /* - * In ADV_EXT_IND we always set only ADI and AUX so the payload length - * is always 7 bytes. - */ - max_usecs = ble_ll_pdu_tx_time_get(7, advsm->pri_phy); - } -#else - max_usecs = ble_ll_pdu_tx_time_get(advsm->adv_pdu_len, BLE_PHY_MODE_1M); - - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { - max_usecs += BLE_LL_SCHED_DIRECT_ADV_MAX_USECS; - } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { - max_usecs += BLE_LL_SCHED_ADV_MAX_USECS; - } -#endif - - sch->start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks; - sch->remainder = 0; - sch->end_time = advsm->adv_pdu_start_time + - ble_ll_usecs_to_ticks_round_up(max_usecs); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static int -ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item *sch) -{ - int rc; - uint8_t end_trans; - uint32_t txstart; - struct ble_ll_adv_sm *advsm; - ble_phy_tx_pducb_t pducb; - struct ble_ll_adv_aux *aux; - - /* Get the state machine for the event */ - advsm = (struct ble_ll_adv_sm *)sch->cb_arg; - - /* Set the current advertiser */ - g_ble_ll_cur_adv_sm = advsm; - - ble_ll_adv_active_chanset_set_sec(advsm); - - /* Set the power */ - ble_phy_txpwr_set(advsm->adv_txpwr); - - /* Set channel */ - aux = AUX_CURRENT(advsm); - rc = ble_phy_setchan(aux->chan, BLE_ACCESS_ADDR_ADV, - BLE_LL_CRCINIT_ADV); - assert(rc == 0); - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - /* Set phy mode */ - ble_phy_mode_set(advsm->sec_phy, advsm->sec_phy); -#endif - - /* Set transmit start time. */ - txstart = sch->start_time + g_ble_ll_sched_offset_ticks; - rc = ble_phy_tx_set_start_time(txstart, sch->remainder); - if (rc) { - STATS_INC(ble_ll_stats, adv_late_starts); - goto adv_aux_dropped; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - ble_phy_encrypt_disable(); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - advsm->adv_rpa_index = -1; - if (ble_ll_resolv_enabled()) { - ble_phy_resolv_list_enable(); - } else { - ble_phy_resolv_list_disable(); - } -#endif - - /* Set phy mode based on type of advertisement */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { - end_trans = BLE_PHY_TRANSITION_TX_RX; - ble_phy_set_txend_cb(NULL, NULL); - pducb = ble_ll_adv_aux_pdu_make; - } else if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) && - advsm->aux_first_pdu) { - end_trans = BLE_PHY_TRANSITION_TX_RX; - ble_phy_set_txend_cb(NULL, NULL); - pducb = ble_ll_adv_aux_scannable_pdu_make; - } else { - end_trans = BLE_PHY_TRANSITION_NONE; - ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm); - pducb = ble_ll_adv_aux_pdu_make; - } - - /* Transmit advertisement */ - rc = ble_phy_tx(pducb, advsm, end_trans); - if (rc) { - goto adv_aux_dropped; - } - - /* Enable/disable whitelisting based on filter policy */ - if (advsm->adv_filter_policy != BLE_HCI_ADV_FILT_NONE) { - ble_ll_whitelist_enable(); - } else { - ble_ll_whitelist_disable(); - } - - /* Set link layer state to advertising */ - ble_ll_state_set(BLE_LL_STATE_ADV); - - /* Count # of adv. sent */ - STATS_INC(ble_ll_stats, adv_txg); - - return BLE_LL_SCHED_STATE_RUNNING; - -adv_aux_dropped: - advsm->aux_dropped = 1; - ble_ll_adv_tx_done(advsm); - return BLE_LL_SCHED_STATE_DONE; -} - -static uint8_t -ble_ll_adv_aux_scannable_pdu_payload_len(struct ble_ll_adv_sm *advsm) -{ - uint8_t len; - - /* Flags, ADI always */ - len = BLE_LL_EXT_ADV_HDR_LEN + BLE_LL_EXT_ADV_FLAGS_SIZE - + BLE_LL_EXT_ADV_DATA_INFO_SIZE; - - /* AdvA if not anonymous */ - if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV)) { - len += BLE_LL_EXT_ADV_ADVA_SIZE; - } - - /* TargetA only for directed */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { - len += BLE_LL_EXT_ADV_TARGETA_SIZE; - } - - /* TxPower if configured */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR) { - len += BLE_LL_EXT_ADV_TX_POWER_SIZE; - } - - return len; -} - -static void -ble_ll_adv_aux_calculate(struct ble_ll_adv_sm *advsm, - struct ble_ll_adv_aux *aux, uint16_t aux_data_offset) -{ - uint16_t rem_aux_data_len; - uint8_t hdr_len; - bool chainable; - - assert(!aux->sch.enqueued); - assert((AUX_DATA_LEN(advsm) > aux_data_offset) || - (AUX_DATA_LEN(advsm) == 0 && aux_data_offset == 0)); - - aux->aux_data_offset = aux_data_offset; - aux->aux_data_len = 0; - aux->payload_len = 0; - aux->ext_hdr = 0; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - aux->chan = ble_ll_utils_calc_dci_csa2(advsm->event_cntr++, - advsm->channel_id, - g_ble_ll_conn_params.num_used_chans, - g_ble_ll_conn_params.master_chan_map); -#else - aux->chan = ble_ll_utils_remapped_channel(ble_ll_rand() % BLE_PHY_NUM_DATA_CHANS, - g_ble_ll_conn_params.master_chan_map); -#endif - - rem_aux_data_len = AUX_DATA_LEN(advsm) - aux_data_offset; - chainable = !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE); - - hdr_len = BLE_LL_EXT_ADV_HDR_LEN; - - if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { - /* ADI */ - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT); - hdr_len += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - } - - /* AdvA for 1st PDU in chain (i.e. AUX_ADV_IND or AUX_SCAN_RSP) */ - if (aux_data_offset == 0 && - !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV)) { - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_ADVA_BIT); - hdr_len += BLE_LL_EXT_ADV_ADVA_SIZE; - } - - /* Note: this function does not calculate AUX_ADV_IND when advertising is - * scannable. Instead it is calculated in ble_ll_adv_aux_schedule_first(). - * - * However this function calculates length of AUX_SCAN_RSP and according - * to BT 5.0 Vol 6 Part B, 2.3.2.3, TargetA shall not be include there. - * - * This is why TargetA is added to all directed advertising here unless it - * is scannable one. - * - * Note. TargetA shall not be also in AUX_CHAIN_IND - */ - if (aux_data_offset == 0 && - (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) && - !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_TARGETA_BIT); - hdr_len += BLE_LL_EXT_ADV_TARGETA_SIZE; - } - - /* TxPower if configured. - * Note: TxPower should not be be present in AUX_CHAIN_IND - */ - if (aux_data_offset == 0 && - (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR)) { - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); - hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - /* SyncInfo for 1st PDU in chain (i.e. AUX_ADV_IND only) if periodic - * advertising is enabled - */ - if (aux_data_offset == 0 && advsm->periodic_adv_active) { - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT); - hdr_len += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; - } -#endif - - /* if we have any fields in ext header we need to add flags, note that Aux - * PTR is handled later and it will account for flags if needed - */ - if (aux->ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; - } - - /* AdvData always */ - aux->aux_data_len = min(BLE_LL_MAX_PAYLOAD_LEN - hdr_len, rem_aux_data_len); - - /* AuxPtr if there are more AdvData remaining that we can fit here */ - if (chainable && (rem_aux_data_len > aux->aux_data_len)) { - /* adjust for flags that needs to be added if AuxPtr is only field - * in Extended Header - */ - if (!aux->ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; - aux->aux_data_len -= BLE_LL_EXT_ADV_FLAGS_SIZE; - } - - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT); - hdr_len += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - aux->aux_data_len -= BLE_LL_EXT_ADV_AUX_PTR_SIZE; - - /* PDU payload should be full if chained */ - assert(hdr_len + aux->aux_data_len == BLE_LL_MAX_PAYLOAD_LEN); - } - - aux->payload_len = hdr_len + aux->aux_data_len; -} - -static void -ble_ll_adv_aux_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start, - void *arg) -{ - struct ble_ll_adv_aux *aux = arg; - - aux->start_time = sch_start + g_ble_ll_sched_offset_ticks; -} - -static void -ble_ll_adv_aux_schedule_next(struct ble_ll_adv_sm *advsm) -{ - struct ble_ll_adv_aux *aux; - struct ble_ll_adv_aux *aux_next; - struct ble_ll_sched_item *sch; - uint16_t rem_aux_data_len; - uint16_t next_aux_data_offset; - uint32_t max_usecs; - - assert(advsm->aux_active); - - aux = AUX_CURRENT(advsm); - aux_next = AUX_NEXT(advsm); - - assert(!aux_next->sch.enqueued); - - /* - * Do not schedule next aux if current aux is no longer scheduled since we - * do not have reference time for scheduling. - */ - if (!aux->sch.enqueued) { - return; - } - - /* - * Do not schedule next aux if current aux does not have AuxPtr in extended - * header as this means we do not need subsequent ADV_CHAIN_IND to be sent. - */ - if (!(aux->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT))) { - return; - } - - next_aux_data_offset = aux->aux_data_offset + aux->aux_data_len; - - assert(AUX_DATA_LEN(advsm) >= next_aux_data_offset); - - rem_aux_data_len = AUX_DATA_LEN(advsm) - next_aux_data_offset; - assert(rem_aux_data_len > 0); - - ble_ll_adv_aux_calculate(advsm, aux_next, next_aux_data_offset); - max_usecs = ble_ll_pdu_tx_time_get(aux_next->payload_len, advsm->sec_phy); - - aux_next->start_time = aux->sch.end_time + - ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY)); - - sch = &aux_next->sch; - sch->start_time = aux_next->start_time - g_ble_ll_sched_offset_ticks; - sch->remainder = 0; - sch->end_time = aux_next->start_time + - ble_ll_usecs_to_ticks_round_up(max_usecs); - ble_ll_sched_adv_new(&aux_next->sch, ble_ll_adv_aux_scheduled, aux_next); - - /* - * In case duration is set for advertising set we need to check if newly - * scheduled aux will fit inside duration. If not, remove it from scheduler - * so advertising will stop after current aux. - */ - if (advsm->duration && (aux_next->sch.end_time > advsm->adv_end_time)) { - ble_ll_sched_rmv_elem(&aux_next->sch); - } -} - -static void -ble_ll_adv_aux_schedule_first(struct ble_ll_adv_sm *advsm) -{ - struct ble_ll_adv_aux *aux; - struct ble_ll_sched_item *sch; - uint32_t max_usecs; - - assert(!advsm->aux_active); - assert(!advsm->aux[0].sch.enqueued); - assert(!advsm->aux[1].sch.enqueued); - - advsm->aux_active = 1; - advsm->aux_index = 0; - advsm->aux_first_pdu = 1; - advsm->aux_not_scanned = 0; - advsm->aux_dropped = 0; - - aux = AUX_CURRENT(advsm); - ble_ll_adv_aux_calculate(advsm, aux, 0); - - /* Set end time to maximum time this schedule item may take */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { - max_usecs = ble_ll_pdu_tx_time_get(aux->payload_len, advsm->sec_phy) + - BLE_LL_IFS + - /* AUX_CONN_REQ */ - ble_ll_pdu_tx_time_get(34 + 14, advsm->sec_phy) + - BLE_LL_IFS + - /* AUX_CONN_RSP */ - ble_ll_pdu_tx_time_get(14, advsm->sec_phy); - } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) { - /* For scannable advertising we need to calculate how much time we - * need for AUX_ADV_IND along with AUX_SCAN_REQ, AUX_SCAN_RSP and - * IFS in between. - * - * Note: - * 1. aux->payload_len, which calculated by above ble_ll_adv_aux_calulcate(), - * contains AUX_SCAN_RSP length. - * 2. length of AUX_ADV_IND is calculated by special function: - * ble_ll_adv_aux_scannable_pdu_payload_len() - */ - max_usecs = ble_ll_pdu_tx_time_get(ble_ll_adv_aux_scannable_pdu_payload_len(advsm), - advsm->sec_phy) + - BLE_LL_IFS + - /* AUX_SCAN_REQ */ - ble_ll_pdu_tx_time_get(12, advsm->sec_phy) + - BLE_LL_IFS + - /* AUX_SCAN_RSP */ - ble_ll_pdu_tx_time_get(aux->payload_len, advsm->sec_phy); - } else { - max_usecs = ble_ll_pdu_tx_time_get(aux->payload_len, advsm->sec_phy); - } - - sch = &aux->sch; - sch->start_time = aux->start_time - g_ble_ll_sched_offset_ticks; - sch->remainder = 0; - sch->end_time = aux->start_time + ble_ll_usecs_to_ticks_round_up(max_usecs); - ble_ll_sched_adv_new(sch, ble_ll_adv_aux_scheduled, aux); -} - -static void -ble_ll_adv_aux_set_start_time(struct ble_ll_adv_sm *advsm) -{ - static const uint8_t bits[8] = {0, 1, 1, 2, 1, 2, 2, 3}; - struct ble_ll_sched_item *sched = &advsm->adv_sch; - uint32_t adv_pdu_dur; - uint32_t adv_event_dur; - uint8_t chans; - - assert(!advsm->aux_active); - assert(!advsm->aux[0].sch.enqueued); - assert(!advsm->aux[1].sch.enqueued); - - assert(advsm->adv_chanmask > 0 && - advsm->adv_chanmask <= BLE_HCI_ADV_CHANMASK_DEF); - - chans = bits[advsm->adv_chanmask]; - - /* - * We want to schedule auxiliary packet as soon as possible after the end - * of advertising event, but no sooner than T_MAFS. The interval between - * advertising packets is 250 usecs (8.19 ticks) on LE Coded and a bit less - * on 1M, but it can vary a bit due to scheduling which we can't really - * control. Since we round ticks up for both interval and T_MAFS, we still - * have some margin here. The worst thing that can happen is that we skip - * last advertising packet which is not a bit problem so leave it as-is, no - * need to make code more complicated. - */ - - /* - * XXX: this could be improved if phy has TX-TX transition with controlled - * or predefined interval, but since it makes advertising code even - * more complicated let's skip it for now... - */ - - adv_pdu_dur = (int32_t)(sched->end_time - sched->start_time) - - g_ble_ll_sched_offset_ticks; - - /* 9 is 8.19 ticks rounded up - see comment above */ - adv_event_dur = (adv_pdu_dur * chans) + (9 * (chans - 1)); - - advsm->aux[0].start_time = advsm->adv_event_start_time + adv_event_dur + - ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_MAFS_DELAY)); -} - -static void -ble_ll_adv_aux_schedule(struct ble_ll_adv_sm *advsm) -{ - /* - * For secondary channel we always start by scheduling two consecutive - * auxiliary packets at once. Then, after sending one packet we try to - * schedule another one as long as there are some data left to send. This - * is to make sure we can always calculate AuxPtr to subsequent packet - * without need to scheduled it in an interrupt. - */ - - ble_ll_adv_aux_set_start_time(advsm); - ble_ll_adv_aux_schedule_first(advsm); - ble_ll_adv_aux_schedule_next(advsm); - - /* - * In case duration is set for advertising set we need to check if at least - * 1st aux will fit inside duration. If not, stop advertising now so we do - * not start extended advertising event which we cannot finish in time. - */ - if (advsm->duration && - (AUX_CURRENT(advsm)->sch.end_time > advsm->adv_end_time)) { - ble_ll_adv_sm_stop_timeout(advsm); - } -} -#endif - -/** - * Called when advertising need to be halted. This normally should not be called - * and is only called when a scheduled item executes but advertising is still - * running. - * - * Context: Interrupt - */ -void -ble_ll_adv_halt(void) -{ - struct ble_ll_adv_sm *advsm; - - if (g_ble_ll_cur_adv_sm != NULL) { - advsm = g_ble_ll_cur_adv_sm; - - ble_ll_trace_u32(BLE_LL_TRACE_ID_ADV_HALT, advsm->adv_instance); - - ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM)); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - if (advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING) { - ble_ll_adv_flags_clear(advsm, - BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, - &advsm->adv_periodic_txdone_ev); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - g_ble_ll_cur_adv_sm = NULL; - return; - } -#endif - - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); - } -#endif - - ble_ll_state_set(BLE_LL_STATE_STANDBY); - ble_ll_adv_active_chanset_clear(g_ble_ll_cur_adv_sm); - g_ble_ll_cur_adv_sm = NULL; - } else { - ble_ll_trace_u32(BLE_LL_TRACE_ID_ADV_HALT, UINT32_MAX); - } -} - -/** - * Called by the HCI command parser when a set advertising parameters command - * has been received. - * - * Context: Link Layer task (HCI command parser) - * - * @param cmd - * - * @return int - */ -int -ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_adv_params_cp *cmd = (const void *) cmdbuf; - struct ble_ll_adv_sm *advsm; - uint8_t adv_filter_policy; - uint16_t adv_itvl_min; - uint16_t adv_itvl_max; - uint16_t props; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - advsm = &g_ble_ll_adv_sm[0]; - if (advsm->adv_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* Make sure intervals are OK (along with advertising type */ - adv_itvl_min = le16toh(cmd->min_interval); - adv_itvl_max = le16toh(cmd->max_interval); - - /* - * Get the filter policy now since we will ignore it if we are doing - * directed advertising - */ - adv_filter_policy = cmd->filter_policy; - - switch (cmd->type) { - case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD: - adv_filter_policy = BLE_HCI_ADV_FILT_NONE; - memcpy(advsm->peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); - - /* Ignore min/max interval */ - adv_itvl_min = 0; - adv_itvl_max = 0; - - props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_HD_DIR ; - break; - case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD: - adv_filter_policy = BLE_HCI_ADV_FILT_NONE; - memcpy(advsm->peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); - - props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_LD_DIR ; - break; - case BLE_HCI_ADV_TYPE_ADV_IND: - props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND; - break; - case BLE_HCI_ADV_TYPE_ADV_NONCONN_IND: - props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_NONCONN; - break; - case BLE_HCI_ADV_TYPE_ADV_SCAN_IND: - props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_SCAN; - break; - default: - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Make sure intervals values are valid - * (HD directed advertising ignores those parameters) - */ - if (!(props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED)) { - if ((adv_itvl_min > adv_itvl_max) || - (adv_itvl_min < BLE_HCI_ADV_ITVL_MIN) || - (adv_itvl_min > BLE_HCI_ADV_ITVL_MAX) || - (adv_itvl_max < BLE_HCI_ADV_ITVL_MIN) || - (adv_itvl_max > BLE_HCI_ADV_ITVL_MAX)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - } - - if ((cmd->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) || - (cmd->peer_addr_type > BLE_HCI_ADV_PEER_ADDR_MAX)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - advsm->adv_txpwr = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (cmd->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { - /* Copy peer address */ - memcpy(advsm->peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); - } -#else - /* If we dont support privacy some address types wont work */ - if (cmd->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { - return BLE_ERR_UNSUPPORTED; - } -#endif - - /* There are only three adv channels, so check for any outside the range */ - if (((cmd->chan_map & 0xF8) != 0) || (cmd->chan_map == 0)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check for valid filter policy */ - if (adv_filter_policy > BLE_HCI_ADV_FILT_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Fill out rest of advertising state machine */ - advsm->own_addr_type = cmd->own_addr_type; - advsm->peer_addr_type = cmd->peer_addr_type; - advsm->adv_filter_policy = adv_filter_policy; - advsm->adv_chanmask = cmd->chan_map; - advsm->adv_itvl_min = adv_itvl_min; - advsm->adv_itvl_max = adv_itvl_max; - advsm->props = props; - - return 0; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_adv_update_did(struct ble_ll_adv_sm *advsm) -{ - uint16_t old_adi = advsm->adi; - - /* - * The Advertising DID for a given advertising set shall be initialized - * with a randomly chosen value. Whenever the Host provides new advertising - * data or scan response data for a given advertising set (whether it is the - * same as the previous data or not), the Advertising DID shall be updated. - * The new value shall be a randomly chosen value that is not the same as - * the previously used value. - */ - do { - advsm->adi = (advsm->adi & 0xf000) | (ble_ll_rand() & 0x0fff); - } while (old_adi == advsm->adi); -} -#endif - -static void -ble_ll_adv_update_adv_scan_rsp_data(struct ble_ll_adv_sm *advsm) -{ - if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_NEW_ADV_DATA) && - !(advsm->flags & BLE_LL_ADV_SM_FLAG_NEW_SCAN_RSP_DATA)) { - return; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (advsm->aux_active) { - return; - } -#endif - - if (advsm->flags & BLE_LL_ADV_SM_FLAG_NEW_ADV_DATA) { - if (advsm->new_adv_data) { - os_mbuf_free_chain(advsm->adv_data); - advsm->adv_data = advsm->new_adv_data; - advsm->new_adv_data = NULL; - } - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_NEW_ADV_DATA); - } else if (advsm->flags & BLE_LL_ADV_SM_FLAG_NEW_SCAN_RSP_DATA) { - os_mbuf_free_chain(advsm->scan_rsp_data); - advsm->scan_rsp_data = advsm->new_scan_rsp_data; - advsm->new_scan_rsp_data = NULL; - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_NEW_SCAN_RSP_DATA); - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* DID shall be updated when host provides new advertising data */ - ble_ll_adv_update_did(advsm); -#endif -} - -/** - * Stop advertising state machine - * - * Context: Link Layer task. - * - * @param advsm - */ -static void -ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm) -{ - os_sr_t sr; - - if (advsm->adv_enabled) { - ble_ll_rfmgmt_release(); - - /* Remove any scheduled advertising items */ - ble_ll_sched_rmv_elem(&advsm->adv_sch); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - advsm->aux_active = 0; - ble_ll_sched_rmv_elem(&advsm->aux[0].sch); - ble_ll_sched_rmv_elem(&advsm->aux[1].sch); -#endif - - /* Set to standby if we are no longer advertising */ - OS_ENTER_CRITICAL(sr); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if ((g_ble_ll_cur_adv_sm == advsm) && - !(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING)) { - ble_phy_disable(); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - g_ble_ll_cur_adv_sm = NULL; - ble_ll_scan_chk_resume(); - } -#else - if (ble_ll_state_get() == BLE_LL_STATE_ADV) { - ble_phy_disable(); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - g_ble_ll_cur_adv_sm = NULL; - ble_ll_scan_chk_resume(); - } -#endif - OS_EXIT_CRITICAL(sr); - - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); -#endif - - /* If there is an event buf we need to free it */ - if (advsm->conn_comp_ev) { - ble_hci_trans_buf_free(advsm->conn_comp_ev); - advsm->conn_comp_ev = NULL; - } - - ble_ll_adv_active_chanset_clear(advsm); - - /* Disable advertising */ - advsm->adv_enabled = 0; - - /* Check if there is outstanding update */ - ble_ll_adv_update_adv_scan_rsp_data(advsm); - } -} - -static void -ble_ll_adv_sm_stop_timeout(struct ble_ll_adv_sm *advsm) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (ble_ll_hci_adv_mode_ext()) { - ble_ll_hci_ev_send_adv_set_terminated(BLE_ERR_DIR_ADV_TMO, - advsm->adv_instance, 0, - advsm->events); - } -#endif - - /* - * For high duty directed advertising we need to send connection - * complete event with proper status - */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { - ble_ll_conn_comp_event_send(NULL, BLE_ERR_DIR_ADV_TMO, - advsm->conn_comp_ev, advsm); - advsm->conn_comp_ev = NULL; - } - - /* Disable advertising */ - ble_ll_adv_sm_stop(advsm); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_adv_sm_stop_limit_reached(struct ble_ll_adv_sm *advsm) -{ - ble_ll_hci_ev_send_adv_set_terminated(BLE_ERR_LIMIT_REACHED, - advsm->adv_instance, 0, - advsm->events); - - /* - * For high duty directed advertising we need to send connection - * complete event with proper status - * - * Spec is a bit unambiguous here since it doesn't define what code should - * be used if HD directed advertising was terminated before timeout due to - * events count limit. For now just use same code as with duration timeout. - */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { - ble_ll_conn_comp_event_send(NULL, BLE_ERR_DIR_ADV_TMO, - advsm->conn_comp_ev, advsm); - advsm->conn_comp_ev = NULL; - } - - /* Disable advertising */ - ble_ll_adv_sm_stop(advsm); -} -#endif - -static void -ble_ll_adv_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start, void *arg) -{ - /* The event start time is when we start transmission of the adv PDU */ - advsm->adv_event_start_time = sch_start + g_ble_ll_sched_offset_ticks; - advsm->adv_pdu_start_time = advsm->adv_event_start_time; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* this is validated for HD adv so no need to do additional checks here - * duration is in 10ms units - */ - if (advsm->duration) { - advsm->adv_end_time = advsm->adv_event_start_time + - os_cputime_usecs_to_ticks(advsm->duration * 10000); - } -#else - /* Set the time at which we must end directed, high-duty cycle advertising. - */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { - advsm->adv_end_time = advsm->adv_event_start_time + - os_cputime_usecs_to_ticks(BLE_LL_ADV_STATE_HD_MAX * 1000); - } -#endif -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) -static uint8_t -ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) -{ - struct ble_ll_adv_sm *advsm; - struct ble_ll_adv_sync *sync; - uint8_t adv_mode; - uint8_t pdu_type; - uint8_t ext_hdr_len; - uint32_t offset; - - advsm = pducb_arg; - sync = SYNC_CURRENT(advsm); - - assert(!ble_ll_adv_active_chanset_is_sec(advsm)); - assert(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); - - /* It's the same for AUX_SYNC_IND and AUX_CHAIN_IND */ - pdu_type = BLE_ADV_PDU_TYPE_AUX_SYNC_IND; - - /* non-connectable and non-scannable */ - adv_mode = 0; - - ext_hdr_len = sync->payload_len - BLE_LL_EXT_ADV_HDR_LEN - sync->sync_data_len; - dptr[0] = (adv_mode << 6) | ext_hdr_len; - dptr += 1; - - /* only put flags if needed */ - if (sync->ext_hdr) { - dptr[0] = sync->ext_hdr; - dptr += 1; - } - - if (sync->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { - if (!SYNC_NEXT(advsm)->sch.enqueued) { - /* - * Trim data here in case we do not have next sync scheduled. This - * can happen if next sync was outside advertising set period and - * was removed from scheduler. - */ - offset = 0; - } else { - offset = os_cputime_ticks_to_usecs(SYNC_NEXT(advsm)->start_time - sync->start_time); - } - - ble_ll_adv_put_aux_ptr(SYNC_NEXT(advsm)->chan, advsm->sec_phy, - offset, dptr); - - dptr += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - } - - if (sync->ext_hdr & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { - dptr[0] = advsm->adv_txpwr + ble_ll_get_tx_pwr_compensation(); - dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE; - } - - if (sync->sync_data_len) { - os_mbuf_copydata(advsm->periodic_adv_data, sync->sync_data_offset, - sync->sync_data_len, dptr); - } - - *hdr_byte = pdu_type; - - return sync->payload_len; -} - - -static void -ble_ll_adv_sync_tx_done(struct ble_ll_adv_sm *advsm) -{ - /* reset power to max after advertising */ - ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM)); - - /* for sync we trace a no pri nor sec set */ - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_ADV_TXDONE, advsm->adv_instance, 0); - - assert(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); - assert(!ble_ll_adv_active_chanset_is_sec(advsm)); - - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_periodic_txdone_ev); - - ble_ll_state_set(BLE_LL_STATE_STANDBY); - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); - - /* We no longer have a current state machine */ - g_ble_ll_cur_adv_sm = NULL; -} - -/** - * Called to indicate the advertising sync event is over. - * - * Context: Interrupt - * - * @param advsm - * - */ -static void -ble_ll_adv_sync_tx_end(void *arg) -{ - struct ble_ll_adv_sm *advsm = arg; - - ble_ll_adv_sync_tx_done(advsm); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - /* store last sent periodic counter */ - advsm->periodic_event_cntr_last_sent = advsm->periodic_event_cntr; -#endif -} - -static int -ble_ll_adv_sync_tx_start_cb(struct ble_ll_sched_item *sch) -{ - int rc; - uint32_t txstart; - struct ble_ll_adv_sm *advsm; - struct ble_ll_adv_sync *sync; - - /* Get the state machine for the event */ - advsm = (struct ble_ll_adv_sm *)sch->cb_arg; - - /* Set the current advertiser */ - g_ble_ll_cur_adv_sm = advsm; - - ble_ll_adv_active_chanset_clear(advsm); - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); - - /* Set the power */ - ble_phy_txpwr_set(advsm->adv_txpwr); - - /* Set channel */ - sync = SYNC_CURRENT(advsm); - rc = ble_phy_setchan(sync->chan, advsm->periodic_access_addr, - advsm->periodic_crcinit); - - assert(rc == 0); - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - /* Set phy mode */ - ble_phy_mode_set(advsm->sec_phy, advsm->sec_phy); -#endif - - /* Set transmit start time. */ - txstart = sch->start_time + g_ble_ll_sched_offset_ticks; - rc = ble_phy_tx_set_start_time(txstart, sch->remainder); - if (rc) { - STATS_INC(ble_ll_stats, adv_late_starts); - goto adv_tx_done; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - ble_phy_encrypt_disable(); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - ble_phy_resolv_list_disable(); -#endif - - /* Transmit advertisement */ - ble_phy_set_txend_cb(ble_ll_adv_sync_tx_end, advsm); - rc = ble_phy_tx(ble_ll_adv_sync_pdu_make, advsm, BLE_PHY_TRANSITION_NONE); - if (rc) { - goto adv_tx_done; - } - - /* disable whitelisting, we are always non-connectable non-scannable */ - ble_ll_whitelist_disable(); - - /* Set link layer state to advertising */ - ble_ll_state_set(BLE_LL_STATE_ADV); - - /* Count # of adv. sent */ - STATS_INC(ble_ll_stats, adv_txg); - - return BLE_LL_SCHED_STATE_RUNNING; - -adv_tx_done: - ble_ll_adv_sync_tx_done(advsm); - return BLE_LL_SCHED_STATE_DONE; -} - -static void -ble_ll_adv_sync_calculate(struct ble_ll_adv_sm *advsm, - struct ble_ll_adv_sync *sync, - uint16_t sync_data_offset, - uint8_t chan) -{ - uint16_t rem_sync_data_len; - uint8_t hdr_len; - - assert(!sync->sch.enqueued); - assert((SYNC_DATA_LEN(advsm) > sync_data_offset) || - (SYNC_DATA_LEN(advsm) == 0 && sync_data_offset == 0)); - - sync->sync_data_offset = sync_data_offset; - sync->sync_data_len = 0; - sync->payload_len = 0; - sync->ext_hdr = 0; - sync->chan = chan; - - rem_sync_data_len = SYNC_DATA_LEN(advsm) - sync_data_offset; - - hdr_len = BLE_LL_EXT_ADV_HDR_LEN; - - /* TxPower if configured - * Note: TxPower shall not be present in chain PDU for SYNC - */ - if (sync_data_offset == 0 && - (advsm->periodic_adv_props & BLE_HCI_LE_SET_PERIODIC_ADV_PROP_INC_TX_PWR)) { - sync->ext_hdr |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); - hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; - } - - /* if we have any fields in ext header we need to add flags, note that Aux - * PTR is handled later and it will account for flags if needed - * - * This could be handled inside TxPower but lets keep code consistent with - * how Aux calculate works and this also make it easier to add more fields - * into flags if needed in future - */ - if (sync->ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; - } - - /* AdvData always */ - sync->sync_data_len = min(BLE_LL_MAX_PAYLOAD_LEN - hdr_len, rem_sync_data_len); - - /* AuxPtr if there are more AdvData remaining that we can fit here */ - if ((rem_sync_data_len > sync->sync_data_len)) { - /* adjust for flags that needs to be added if AuxPtr is only field - * in Extended Header - */ - if (!sync->ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; - sync->sync_data_len -= BLE_LL_EXT_ADV_FLAGS_SIZE; - } - - sync->ext_hdr |= (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT); - hdr_len += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - sync->sync_data_len -= BLE_LL_EXT_ADV_AUX_PTR_SIZE; - - /* PDU payload should be full if chained */ - assert(hdr_len + sync->sync_data_len == BLE_LL_MAX_PAYLOAD_LEN); - } - - sync->payload_len = hdr_len + sync->sync_data_len; -} - -static void -ble_ll_adv_periodic_schedule_first(struct ble_ll_adv_sm *advsm, - bool first_pdu) -{ - struct ble_ll_adv_sync *sync; - struct ble_ll_sched_item *sch; - uint32_t sch_start; - uint32_t max_usecs; - uint8_t chan; - int rc; - - assert(!advsm->periodic_sync_active); - assert(!advsm->periodic_sync[0].sch.enqueued); - assert(!advsm->periodic_sync[1].sch.enqueued); - - advsm->periodic_sync_active = 1; - advsm->periodic_sync_index = 0; - - sync = SYNC_CURRENT(advsm); - - /* For first SYNC packet in chain we use separate CSA#2 state to maintain - * freq hopping as advertised in SyncInfo - * - * Preincrement event counter as we later send this in PDU so make sure - * same values are used - */ - chan = ble_ll_utils_calc_dci_csa2(++advsm->periodic_event_cntr, - advsm->periodic_channel_id, - advsm->periodic_num_used_chans, - advsm->periodic_chanmap); - - ble_ll_adv_sync_calculate(advsm, sync, 0, chan); - - /* sync is always non-connectable and non-scannable*/ - max_usecs = ble_ll_pdu_tx_time_get(sync->payload_len, advsm->sec_phy); - - sch = &sync->sch; - - advsm->periodic_adv_event_start_time_remainder += advsm->periodic_adv_itvl_rem_usec; - if (advsm->periodic_adv_event_start_time_remainder >= 31) { - advsm->periodic_adv_event_start_time++; - advsm->periodic_adv_event_start_time_remainder -= 31; - } - - sch->start_time = advsm->periodic_adv_event_start_time; - sch->remainder = advsm->periodic_adv_event_start_time_remainder; - sch->end_time = sch->start_time + ble_ll_usecs_to_ticks_round_up(max_usecs); - sch->start_time -= g_ble_ll_sched_offset_ticks; - - rc = ble_ll_sched_periodic_adv(sch, &sch_start, first_pdu); - if (rc) { - STATS_INC(ble_ll_stats, periodic_adv_drop_event); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, - &advsm->adv_periodic_txdone_ev); - return; - } - - sync->start_time = sch_start + g_ble_ll_sched_offset_ticks; - - assert(first_pdu || - (sync->start_time == advsm->periodic_adv_event_start_time)); - - /* The event start time is when we start transmission of the SYNC PDU */ - advsm->periodic_adv_event_start_time = sync->start_time; -} - -static void -ble_ll_adv_sync_next_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start, - void *arg) -{ - struct ble_ll_adv_sync *sync = arg; - - sync->start_time = sch_start + g_ble_ll_sched_offset_ticks; -} - -static void -ble_ll_adv_periodic_schedule_next(struct ble_ll_adv_sm *advsm) -{ - struct ble_ll_adv_sync *sync; - struct ble_ll_adv_sync *sync_next; - struct ble_ll_sched_item *sch; - uint16_t rem_sync_data_len; - uint16_t next_sync_data_offset; - uint32_t max_usecs; - uint8_t chan; - - assert(advsm->periodic_sync_active); - - sync = SYNC_CURRENT(advsm); - sync_next = SYNC_NEXT(advsm); - - assert(!sync_next->sch.enqueued); - - /* - * Do not schedule next sync if current sync is no longer scheduled since we - * do not have reference time for scheduling. - */ - if (!sync->sch.enqueued) { - return; - } - - /* - * Do not schedule next sync if current sync does not have AuxPtr in extended - * header as this means we do not need subsequent ADV_CHAIN_IND to be sent. - */ - if (!(sync->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT))) { - return; - } - - next_sync_data_offset = sync->sync_data_offset + sync->sync_data_len; - - assert(SYNC_DATA_LEN(advsm) >= next_sync_data_offset); - - rem_sync_data_len = SYNC_DATA_LEN(advsm) - next_sync_data_offset; - assert(rem_sync_data_len > 0); - - /* we use separate counter for chaining */ - chan = ble_ll_utils_calc_dci_csa2(advsm->periodic_chain_event_cntr++, - advsm->periodic_channel_id, - advsm->periodic_num_used_chans, - advsm->periodic_chanmap); - - ble_ll_adv_sync_calculate(advsm, sync_next, next_sync_data_offset, chan); - max_usecs = ble_ll_pdu_tx_time_get(sync_next->payload_len, advsm->sec_phy); - - sync_next->start_time = sync->sch.end_time + - ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY)); - - sch = &sync_next->sch; - sch->start_time = sync_next->start_time - g_ble_ll_sched_offset_ticks; - - /* adjust for previous packets remainder */ - sch->remainder = sync->sch.remainder; - sch->end_time = sync_next->start_time + - ble_ll_usecs_to_ticks_round_up(max_usecs); - - /* here we can use ble_ll_sched_adv_new as we don't care about timing */ - ble_ll_sched_adv_new(&sync_next->sch, ble_ll_adv_sync_next_scheduled, - sync_next); - - /* if we are pass advertising interval, drop chain */ - if (sch->end_time > advsm->periodic_adv_event_start_time + - advsm->periodic_adv_itvl_ticks) { - STATS_INC(ble_ll_stats, periodic_chain_drop_event); - ble_ll_sched_rmv_elem(&sync->sch); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, - &advsm->adv_periodic_txdone_ev); - } -} - -static void -ble_ll_adv_sync_schedule(struct ble_ll_adv_sm *advsm, bool first_pdu) -{ - /* - * For secondary channel we always start by scheduling two consecutive - * auxiliary packets at once. Then, after sending one packet we try to - * schedule another one as long as there are some data left to send. This - * is to make sure we can always calculate AuxPtr to subsequent packet - * without need to scheduled it in an interrupt. - */ - - ble_ll_adv_periodic_schedule_first(advsm, first_pdu); - ble_ll_adv_periodic_schedule_next(advsm); -} - -static void -ble_ll_adv_reschedule_periodic_event(struct ble_ll_adv_sm *advsm) -{ - advsm->periodic_adv_event_start_time += advsm->periodic_adv_itvl_ticks; - ble_ll_adv_sync_schedule(advsm, false); -} - -static void -ble_ll_adv_update_periodic_data(struct ble_ll_adv_sm *advsm) -{ - if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_NEW_DATA)) { - return; - } - - if (advsm->periodic_sync_active) { - return; - } - - if (advsm->periodic_new_data) { - os_mbuf_free_chain(advsm->periodic_adv_data); - advsm->periodic_adv_data = advsm->periodic_new_data; - advsm->periodic_new_data = NULL; - } - - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_NEW_DATA); -} - -/** - * Called when periodic packet is txd on secondary channel - * - * Context: Link Layer task. - * - * @param ev - */ -static void -ble_ll_adv_periodic_done(struct ble_ll_adv_sm *advsm) -{ - struct ble_ll_adv_sync *sync; - struct ble_ll_adv_sync *sync_next; - - assert(advsm->periodic_adv_enabled); - assert(advsm->periodic_adv_active); - assert(advsm->periodic_sync_active); - - ble_ll_rfmgmt_release(); - - sync = SYNC_CURRENT(advsm); - sync_next = SYNC_NEXT(advsm); - - /* Remove anything else scheduled for periodic */ - ble_ll_sched_rmv_elem(&sync->sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_periodic_txdone_ev); - - /* If we have next SYNC scheduled, try to schedule another one */ - if (sync_next->sch.enqueued) { - advsm->periodic_sync_index ^= 1; - ble_ll_adv_periodic_schedule_next(advsm); - return; - } - - /* Check if we need to resume scanning */ - ble_ll_scan_chk_resume(); - - advsm->periodic_sync_active = 0; - ble_ll_adv_update_periodic_data(advsm); - ble_ll_adv_reschedule_periodic_event(advsm); -} - -static void -ble_ll_adv_periodic_event_done(struct ble_npl_event *ev) -{ - ble_ll_adv_periodic_done(ble_npl_event_get_arg(ev)); -} - -static void -ble_ll_adv_sm_start_periodic(struct ble_ll_adv_sm *advsm) -{ - uint32_t usecs; - uint32_t ticks; - - /* - * The Advertising DID is not required to change when a SyncInfo field is - * added to or removed from an advertising set. However, if it does not - * change, then scanners may fail to synchronize to periodic advertising - * because entries in the Advertising DID cache (see Section 4.3.3) mean - * they ignore the advertisements containing the SyncInfo field. Therefore, - * advertisers should update the Advertising DID when a periodic advertising - * train is enabled. - */ - ble_ll_adv_update_did(advsm); - - advsm->periodic_adv_active = 1; - - /* keep channel map since we cannot change it later on */ - memcpy(advsm->periodic_chanmap, g_ble_ll_conn_params.master_chan_map, - BLE_LL_CONN_CHMAP_LEN); - advsm->periodic_num_used_chans = g_ble_ll_conn_params.num_used_chans; - advsm->periodic_event_cntr = 0; - /* for chaining we start with random counter as we share access addr */ - advsm->periodic_chain_event_cntr = ble_ll_rand(); - advsm->periodic_access_addr = ble_ll_utils_calc_access_addr(); - advsm->periodic_channel_id = ((advsm->periodic_access_addr & 0xffff0000) >> 16) ^ - (advsm->periodic_access_addr & 0x0000ffff); - advsm->periodic_crcinit = ble_ll_rand() & 0xffffff; - - usecs = (uint32_t)advsm->periodic_adv_itvl_max * BLE_LL_ADV_PERIODIC_ITVL; - ticks = os_cputime_usecs_to_ticks(usecs); - - advsm->periodic_adv_itvl_rem_usec = (usecs - os_cputime_ticks_to_usecs(ticks)); - if (advsm->periodic_adv_itvl_rem_usec == 31) { - advsm->periodic_adv_itvl_rem_usec = 0; - ticks++; - } - advsm->periodic_adv_itvl_ticks = ticks; - - /* There is no point in starting periodic advertising until next advertising - * event since SyncInfo is needed for synchronization - */ - advsm->periodic_adv_event_start_time_remainder = 0; - advsm->periodic_adv_event_start_time = advsm->adv_pdu_start_time + - os_cputime_usecs_to_ticks(advsm->adv_itvl_usecs + 5000); - - ble_ll_adv_sync_schedule(advsm, true); -} - -static void -ble_ll_adv_sm_stop_periodic(struct ble_ll_adv_sm *advsm) -{ - os_sr_t sr; - - ble_ll_rfmgmt_release(); - - if (!advsm->periodic_adv_active) { - return; - } - - /* - * The Advertising DID is not required to change when a SyncInfo field is - * added to or removed from an advertising set. However, if it does not - * change, then scanners may unnecessary try to synchronize to instance that - * no longer has periodic advertising enabled because entries in the - * Advertising DID cache (see Section 4.3.3) mean they ignore the - * advertisements no longer containing the SyncInfo field. Therefore, - * advertisers should update the Advertising DID when a periodic advertising - * train is disabled. - */ - ble_ll_adv_update_did(advsm); - - /* Remove any scheduled advertising items */ - advsm->periodic_adv_active = 0; - advsm->periodic_sync_active = 0; - ble_ll_sched_rmv_elem(&advsm->periodic_sync[0].sch); - ble_ll_sched_rmv_elem(&advsm->periodic_sync[1].sch); - - /* Set to standby if we are no longer advertising */ - OS_ENTER_CRITICAL(sr); - if ((g_ble_ll_cur_adv_sm == advsm) && - (advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING)) { - ble_phy_disable(); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - g_ble_ll_cur_adv_sm = NULL; - ble_ll_scan_chk_resume(); - } - OS_EXIT_CRITICAL(sr); - - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); - - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, - &advsm->adv_periodic_txdone_ev); - - ble_ll_adv_update_periodic_data(advsm); -} -#endif - -/** - * Start the advertising state machine. This is called when the host sends - * the "enable advertising" command and is not called again while in the - * advertising state. - * - * Context: Link-layer task. - * - * @param advsm Pointer to advertising state machine - * - * @return int - */ -static int -ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) -{ - uint8_t adv_chan; - uint8_t *addr; - uint8_t *evbuf; - uint32_t start_delay_us; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - uint32_t access_addr; -#endif - const uint8_t *random_addr; - uint32_t earliest_start_time; - int32_t delta; - - /* only clear flags that are not set from HCI */ - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_TX_ADD | - BLE_LL_ADV_SM_FLAG_RX_ADD | - BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - random_addr = advsm->adv_random_addr; -#else - random_addr = g_random_addr; -#endif - - if (!ble_ll_is_valid_own_addr_type(advsm->own_addr_type, random_addr)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* - * Get an event with which to send the connection complete event if - * this is connectable - */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { - /* We expect this to be NULL but if not we wont allocate one... */ - if (advsm->conn_comp_ev == NULL) { - evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (!evbuf) { - return BLE_ERR_MEM_CAPACITY; - } - advsm->conn_comp_ev = evbuf; - } - } - - /* Set advertising address */ - if ((advsm->own_addr_type & 1) == 0) { - addr = g_dev_addr; - } else { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - addr = advsm->adv_random_addr; -#else - addr = g_random_addr; -#endif - advsm->flags |= BLE_LL_ADV_SM_FLAG_TX_ADD; - } - memcpy(advsm->adva, addr, BLE_DEV_ADDR_LEN); - - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { - memcpy(advsm->initiator_addr, advsm->peer_addr, BLE_DEV_ADDR_LEN); - if (advsm->peer_addr_type & 1) { - advsm->flags |= BLE_LL_ADV_SM_FLAG_RX_ADD; - } - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* This will generate an RPA for both initiator addr and adva */ - if (advsm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { - ble_ll_adv_rpa_update(advsm); - } -#endif - - /* Set flag telling us that advertising is enabled */ - advsm->adv_enabled = 1; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - advsm->event_cntr = 0; - access_addr = ble_ll_utils_calc_access_addr(); - advsm->channel_id = ((access_addr & 0xffff0000) >> 16) ^ - (access_addr & 0x0000ffff); -#endif - - /* Determine the advertising interval we will use */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { - /* Set it to max. allowed for high duty cycle advertising */ - advsm->adv_itvl_usecs = BLE_LL_ADV_PDU_ITVL_HD_MS_MAX; - } else { - advsm->adv_itvl_usecs = (uint32_t)advsm->adv_itvl_max; - advsm->adv_itvl_usecs *= BLE_LL_ADV_ITVL; - } - - /* Set first advertising channel */ - adv_chan = ble_ll_adv_first_chan(advsm); - advsm->adv_chan = adv_chan; - - /* - * Scheduling 1st PDU is a bit tricky. - * Earliest possible start time is after RF is enabled so just force RF to - * start here to see when if will be fully enabled - it will be too early, - * but this is the only reliable way to have it enabled on time. - * Next we calculate expected start time (randomize it a bit) and this is - * used to setup start time for scheduler item. - * Then we check if start time for scheduler item (which includes scheduler - * overhead) is no earlier than calculated earliest possible start time and - * adjust scheduler item if necessary. - */ - earliest_start_time = ble_ll_rfmgmt_enable_now(); - - start_delay_us = ble_ll_rand() % (BLE_LL_ADV_DELAY_MS_MAX * 1000); - advsm->adv_pdu_start_time = os_cputime_get32() + - os_cputime_usecs_to_ticks(start_delay_us); - - ble_ll_adv_set_sched(advsm); - - delta = (int32_t)(advsm->adv_sch.start_time - earliest_start_time); - if (delta < 0) { - advsm->adv_sch.start_time -= delta; - advsm->adv_sch.end_time -= delta; - } - - /* This does actual scheduling */ - ble_ll_sched_adv_new(&advsm->adv_sch, ble_ll_adv_scheduled, NULL); - - /* we start periodic before AE since we need PDU start time in SyncInfo */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - if (advsm->periodic_adv_enabled && !advsm->periodic_adv_active) { - ble_ll_adv_sm_start_periodic(advsm); - } -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) { - ble_ll_adv_aux_schedule(advsm); - } -#endif - - return BLE_ERR_SUCCESS; -} - -/** - * Called when the LE HCI command read advertising channel tx power command - * has been received. Returns the current advertising transmit power. - * - * Context: Link Layer task (HCI command parser) - * - * @return int - */ -int -ble_ll_adv_read_txpwr(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_adv_chan_txpwr_rp *rsp = (void *) rspbuf; - - rsp->power_level = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -/** - * Turn advertising on/off. - * - * Context: Link Layer task - * - * @param cmd - * - * @return int - */ -static int -ble_ll_adv_set_enable(uint8_t instance, uint8_t enable, int duration, - uint8_t events) -{ - int rc; - struct ble_ll_adv_sm *advsm; - - advsm = ble_ll_adv_sm_find_configured(instance); - if (!advsm) { - return BLE_ERR_UNK_ADV_INDENT; - } - - rc = BLE_ERR_SUCCESS; - if (enable == 1) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (advsm->flags & BLE_LL_ADV_SM_FLAG_ADV_DATA_INCOMPLETE) { - return BLE_ERR_CMD_DISALLOWED; - } - - if (ble_ll_hci_adv_mode_ext() && - (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) && - !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && - SCAN_RSP_DATA_LEN(advsm) == 0) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* handle specifics of HD dir adv enabled in legacy way */ - if (duration < 0) { - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { - duration = BLE_LL_ADV_STATE_HD_MAX / 10; - } else { - duration = 0; - } - } - advsm->duration = duration; - advsm->events_max = events; - advsm->events = 0; -#endif - - /* If already enabled, do nothing */ - if (!advsm->adv_enabled) { - /* Start the advertising state machine */ - rc = ble_ll_adv_sm_start(advsm); - } - } else if (enable == 0) { - ble_ll_adv_sm_stop(advsm); - } else { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - } - - return rc; -} - -int -ble_ll_hci_adv_set_enable(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_adv_enable_cp *cmd = (const void *) cmdbuf; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return ble_ll_adv_set_enable(0, cmd->enable, -1, 0); -} - -static void -ble_ll_adv_update_data_mbuf(struct os_mbuf **omp, bool new_data, uint16_t maxlen, - const void *data, uint16_t datalen) -{ - struct os_mbuf *om; - int ret; - - om = *omp; - - if (new_data) { - if (om) { - os_mbuf_free_chain(om); - } - - om = os_msys_get_pkthdr(datalen, 0); - if (!om) { - goto done; - } - } - - assert(om); - - if (OS_MBUF_PKTLEN(om) + datalen > maxlen) { - os_mbuf_free_chain(om); - om = NULL; - goto done; - } - - ret = os_mbuf_append(om, data, datalen); - if (ret) { - os_mbuf_free_chain(om); - om = NULL; - } - -done: - *omp = om; -} - -/** - * Set the scan response data that the controller will send. - * - * @param cmd - * @param len - * - * @return int - */ -static int -ble_ll_adv_set_scan_rsp_data(const uint8_t *data, uint8_t datalen, - uint8_t instance, uint8_t operation) -{ - struct ble_ll_adv_sm *advsm; - bool new_data; - - advsm = ble_ll_adv_sm_find_configured(instance); - if (!advsm) { - return BLE_ERR_UNK_ADV_INDENT; - } - - /* check if type of advertising support scan rsp */ - if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { - if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - } - - switch (operation) { - case BLE_HCI_LE_SET_DATA_OPER_COMPLETE: - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - if (datalen > BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - } - - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - case BLE_HCI_LE_SET_DATA_OPER_LAST: - /* TODO mark scan rsp as complete? */ - /* fall through */ - case BLE_HCI_LE_SET_DATA_OPER_INT: - if (!advsm->scan_rsp_data) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (advsm->adv_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } - - if (!datalen) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - break; - case BLE_HCI_LE_SET_DATA_OPER_FIRST: - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (advsm->adv_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } - - if (!datalen) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - break; -#endif - default: - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - new_data = (operation == BLE_HCI_LE_SET_DATA_OPER_COMPLETE) || - (operation == BLE_HCI_LE_SET_DATA_OPER_FIRST); - - if (advsm->adv_enabled) { - if (advsm->new_scan_rsp_data) { - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_NEW_SCAN_RSP_DATA); - os_mbuf_free_chain(advsm->new_scan_rsp_data); - advsm->new_scan_rsp_data = NULL; - } - - ble_ll_adv_update_data_mbuf(&advsm->new_scan_rsp_data, new_data, - BLE_ADV_DATA_MAX_LEN, data, datalen); - if (!advsm->new_scan_rsp_data) { - return BLE_ERR_MEM_CAPACITY; - } - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_NEW_SCAN_RSP_DATA); - } else { - ble_ll_adv_update_data_mbuf(&advsm->scan_rsp_data, new_data, - BLE_SCAN_RSP_DATA_MAX_LEN, data, datalen); - if (!advsm->scan_rsp_data) { - return BLE_ERR_MEM_CAPACITY; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* DID shall be updated when host provides new scan response data */ - ble_ll_adv_update_did(advsm); -#endif - } - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_hci_set_scan_rsp_data(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_scan_rsp_data_cp *cmd = (const void *) cmdbuf; - - if ((len != sizeof(*cmd)) || (cmd->scan_rsp_len > sizeof(cmd->scan_rsp))) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return ble_ll_adv_set_scan_rsp_data(cmd->scan_rsp, cmd->scan_rsp_len, 0, - BLE_HCI_LE_SET_DATA_OPER_COMPLETE); -} -/** - * Called by the LL HCI command parser when a set advertising - * data command has been sent from the host to the controller. - * - * @param cmd Pointer to command data - * @param len Length of command data - * - * @return int 0: success; BLE_ERR_INV_HCI_CMD_PARMS otherwise. - */ -static int -ble_ll_adv_set_adv_data(const uint8_t *data, uint8_t datalen, uint8_t instance, - uint8_t operation) -{ - struct ble_ll_adv_sm *advsm; - bool new_data; - - advsm = ble_ll_adv_sm_find_configured(instance); - if (!advsm) { - return BLE_ERR_UNK_ADV_INDENT; - } - - /* check if type of advertising support adv data */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { - if (ble_ll_hci_adv_mode_ext()) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - } - } else { - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - } - - switch (operation) { - case BLE_HCI_LE_SET_DATA_OPER_COMPLETE: - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - if (datalen > BLE_ADV_LEGACY_DATA_MAX_LEN) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - } - - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_ADV_DATA_INCOMPLETE); - - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - case BLE_HCI_LE_SET_DATA_OPER_UNCHANGED: - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (!advsm->adv_enabled || !ADV_DATA_LEN(advsm) || datalen) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* update DID only */ - ble_ll_adv_update_did(advsm); - return BLE_ERR_SUCCESS; - case BLE_HCI_LE_SET_DATA_OPER_LAST: - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_ADV_DATA_INCOMPLETE); - /* fall through */ - case BLE_HCI_LE_SET_DATA_OPER_INT: - if (!advsm->adv_data) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (!datalen) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (advsm->adv_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } - break; - case BLE_HCI_LE_SET_DATA_OPER_FIRST: - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (advsm->adv_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } - - if (!datalen) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_ADV_DATA_INCOMPLETE); - break; -#endif - default: - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - new_data = (operation == BLE_HCI_LE_SET_DATA_OPER_COMPLETE) || - (operation == BLE_HCI_LE_SET_DATA_OPER_FIRST); - - if (advsm->adv_enabled) { - if (advsm->new_adv_data) { - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_NEW_ADV_DATA); - os_mbuf_free_chain(advsm->new_adv_data); - advsm->new_adv_data = NULL; - } - - ble_ll_adv_update_data_mbuf(&advsm->new_adv_data, new_data, - BLE_ADV_DATA_MAX_LEN, data, datalen); - if (!advsm->new_adv_data) { - return BLE_ERR_MEM_CAPACITY; - } - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_NEW_ADV_DATA); - } else { - ble_ll_adv_update_data_mbuf(&advsm->adv_data, new_data, - BLE_ADV_DATA_MAX_LEN, data, datalen); - if (!advsm->adv_data) { - return BLE_ERR_MEM_CAPACITY; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* DID shall be updated when host provides new advertising data */ - ble_ll_adv_update_did(advsm); -#endif - } - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_hci_set_adv_data(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_adv_data_cp *cmd = (const void *) cmdbuf; - - if ((len != sizeof(*cmd)) || (cmd->adv_data_len > sizeof(cmd->adv_data))) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return ble_ll_adv_set_adv_data(cmd->adv_data, cmd->adv_data_len, 0, - BLE_HCI_LE_SET_DATA_OPER_COMPLETE); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static bool -pri_phy_valid(uint8_t phy) -{ - switch (phy) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case BLE_HCI_LE_PHY_CODED: -#endif - case BLE_HCI_LE_PHY_1M: - return true; - default: - return false; - } -} - -static bool -sec_phy_valid(uint8_t phy) -{ - switch (phy) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case BLE_HCI_LE_PHY_CODED: -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - case BLE_HCI_LE_PHY_2M: -#endif - case BLE_HCI_LE_PHY_1M: - return true; - default: - return false; - } -} - -static struct ble_ll_adv_sm * -ble_ll_adv_sm_get(uint8_t instance) -{ - struct ble_ll_adv_sm *advsm; - int i; - - advsm = ble_ll_adv_sm_find_configured(instance); - if (advsm) { - return advsm; - } - - for (i = 0; i < ARRAY_SIZE(g_ble_ll_adv_sm); i++) { - advsm = &g_ble_ll_adv_sm[i]; - - if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONFIGURED)) { - ble_ll_adv_sm_init(advsm); - - /* configured flag is set by caller on success config */ - advsm->adv_instance = instance; - return advsm; - } - } - - return NULL; -} - -int -ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_set_ext_adv_params_cp *cmd = (const void *) cmdbuf; - struct ble_hci_le_set_ext_adv_params_rp *rsp = (void *) rspbuf; - struct ble_ll_adv_sm *advsm; - uint32_t adv_itvl_min; - uint32_t adv_itvl_max; - uint16_t props; - int rc; - - if (len != sizeof(*cmd )) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - advsm = ble_ll_adv_sm_get(cmd->adv_handle); - if (!advsm) { - rc = BLE_ERR_MEM_CAPACITY; - goto done; - } - - if (advsm->adv_enabled) { - rc = BLE_ERR_CMD_DISALLOWED; - goto done; - } - - props = le16toh(cmd->props); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - /* If the Host issues this command when periodic advertising is enabled for - * the specified advertising set and connectable, scannable, legacy, or - * anonymous advertising is specified, the Controller shall return the - * error code Invalid HCI Command Parameters (0x12). - */ - if (advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_CONFIGURED) { - if (advsm->periodic_adv_enabled) { - if (props & (BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE | - BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE | - BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY | - BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - } - } -#endif - - adv_itvl_min = cmd->pri_itvl_min[2] << 16 | cmd->pri_itvl_min[1] << 8 | - cmd->pri_itvl_min[0]; - adv_itvl_max = cmd->pri_itvl_max[2] << 16 | cmd->pri_itvl_max[1] << 8 | - cmd->pri_itvl_max[0]; - - if (props & ~BLE_HCI_LE_SET_EXT_ADV_PROP_MASK) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - if (ADV_DATA_LEN(advsm) > BLE_ADV_LEGACY_DATA_MAX_LEN || - SCAN_RSP_DATA_LEN(advsm) > BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - /* if legacy bit is set possible values are limited */ - switch (props) { - case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND: - case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_LD_DIR: - case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_HD_DIR: - case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_SCAN: - case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_NONCONN: - break; - default: - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - } else { - /* HD directed advertising allowed only on legacy PDUs */ - if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - /* if ext advertising PDUs are used then it shall not be both - * connectable and scanable - */ - if ((props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) && - (props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - } - - /* High Duty Directed advertising is special */ - if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { - if (ADV_DATA_LEN(advsm) || SCAN_RSP_DATA_LEN(advsm)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - /* Ignore min/max interval */ - adv_itvl_min = 0; - adv_itvl_max = 0; - } else { - /* validate intervals for non HD-directed advertising */ - if ((adv_itvl_min > adv_itvl_max) || - (adv_itvl_min < BLE_HCI_ADV_ITVL_MIN) || - (adv_itvl_max < BLE_HCI_ADV_ITVL_MIN)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - /* TODO for now limit those to values from legacy advertising - * - * If the primary advertising interval range is outside the advertising - * interval range supported by the Controller, then the Controller shall - * return the error code Unsupported Feature or Parameter Value (0x11). - */ - if ((adv_itvl_min > BLE_HCI_ADV_ITVL_MAX) || - (adv_itvl_max > BLE_HCI_ADV_ITVL_MAX)) { - rc = BLE_ERR_UNSUPPORTED; - goto done; - } - } - - /* There are only three adv channels, so check for any outside the range */ - if (((cmd->pri_chan_map & 0xF8) != 0) || (cmd->pri_chan_map == 0)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - if (cmd->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* If we dont support privacy some address types wont work */ - if (cmd->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { - rc = BLE_ERR_UNSUPPORTED; - goto done; - } -#endif - - /* peer address type is only valid for directed */ - if ((props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) && - (cmd->peer_addr_type > BLE_HCI_ADV_PEER_ADDR_MAX)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - /* Check filter policy (valid only for undirected) */ - if (!(props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) && - cmd->filter_policy > BLE_HCI_ADV_FILT_MAX) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - if (!pri_phy_valid(cmd->pri_phy)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - /* check secondary phy only if not using legacy PDUs */ - if (!(props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && - !sec_phy_valid(cmd->sec_phy)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - if (cmd->sid > 0x0f) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - if (cmd->scan_req_notif > 0x01) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - rc = BLE_ERR_SUCCESS; - - if (cmd->tx_power == 127) { - /* no preference */ - advsm->adv_txpwr = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); - } else { - advsm->adv_txpwr = ble_phy_txpower_round(cmd->tx_power); - } - - /* we can always store as those are validated and used only when needed */ - advsm->peer_addr_type = cmd->peer_addr_type; - memcpy(advsm->peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); - advsm->own_addr_type = cmd->own_addr_type; - advsm->adv_filter_policy = cmd->filter_policy; - advsm->adv_chanmask = cmd->pri_chan_map; - advsm->adv_itvl_min = adv_itvl_min; - advsm->adv_itvl_max = adv_itvl_max; - advsm->pri_phy = cmd->pri_phy; - advsm->sec_phy = cmd->sec_phy; - /* Update SID only */ - advsm->adi = (advsm->adi & 0x0fff) | ((cmd->sid << 12)); - - advsm->props = props; - - /* Set proper mbuf chain for aux data */ - if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - advsm->aux_data = NULL; - } else if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) { - advsm->aux_data = &advsm->scan_rsp_data; - } else { - advsm->aux_data = &advsm->adv_data; - } - - if (cmd->scan_req_notif) { - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_SCAN_REQ_NOTIF); - } else { - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_SCAN_REQ_NOTIF); - } - - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_CONFIGURED); - -done: - /* Update TX power */ - rsp->tx_power = rc ? 0 : advsm->adv_txpwr; - - *rsplen = sizeof(*rsp); - return rc; -} - -int -ble_ll_adv_ext_set_adv_data(const uint8_t *cmdbuf, uint8_t cmdlen) -{ - const struct ble_hci_le_set_ext_adv_data_cp *cmd = (const void *) cmdbuf; - - if (cmdlen < sizeof(*cmd )) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (cmd->adv_data_len > BLE_HCI_MAX_EXT_ADV_DATA_LEN || - cmd->adv_data_len > cmdlen - sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* TODO fragment preference ignored for now */ - - return ble_ll_adv_set_adv_data(cmd->adv_data, cmd->adv_data_len, - cmd->adv_handle, cmd->operation); -} - -int -ble_ll_adv_ext_set_scan_rsp(const uint8_t *cmdbuf, uint8_t cmdlen) -{ - const struct ble_hci_le_set_ext_scan_rsp_data_cp *cmd = (const void *) cmdbuf; - - if (cmdlen < sizeof(*cmd )) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (cmd->scan_rsp_len > BLE_HCI_MAX_EXT_ADV_DATA_LEN || - cmd->scan_rsp_len > cmdlen - sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* TODO fragment preference ignored for now */ - - return ble_ll_adv_set_scan_rsp_data(cmd->scan_rsp, cmd->scan_rsp_len, - cmd->adv_handle, cmd->operation); -} - -/** - * HCI LE extended advertising enable command - * - * @param cmd Pointer to command data - * @param len Command data length - * - * @return int BLE error code - */ -int -ble_ll_adv_ext_set_enable(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_ext_adv_enable_cp *cmd = (const void *) cmdbuf; - struct ble_ll_adv_sm *advsm; - int i, j, rc; - - if (len < sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* check if length is correct */ - if (len != 2 + (cmd->num_sets * sizeof(cmd->sets[0]))) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (cmd->num_sets > BLE_ADV_INSTANCES) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (cmd->num_sets == 0) { - if (cmd->enable) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* disable all instances */ - for (i = 0; i < BLE_ADV_INSTANCES; i++) { - ble_ll_adv_set_enable(i, 0, 0, 0); - } - - return BLE_ERR_SUCCESS; - } - - /* validate instances */ - for (i = 0; i < cmd->num_sets; i++) { - /* validate duplicated sets */ - for (j = i + 1; j < cmd->num_sets; j++) { - if (cmd->sets[i].adv_handle == cmd->sets[j].adv_handle) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - } - - advsm = ble_ll_adv_sm_find_configured(cmd->sets[i].adv_handle); - if (!advsm) { - return BLE_ERR_UNK_ADV_INDENT; - } - - if (cmd->enable) { - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { - if (cmd->sets[i].duration == 0 || - le16toh(cmd->sets[i].duration) > 128) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - } - } - } - - for (i = 0; i < cmd->num_sets; i++) { - rc = ble_ll_adv_set_enable(cmd->sets[i].adv_handle, cmd->enable, - le16toh(cmd->sets[i].duration), - cmd->sets[i].max_events); - if (rc) { - return rc; - } - } - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_adv_set_random_addr(const uint8_t *addr, uint8_t instance) -{ - struct ble_ll_adv_sm *advsm; - - advsm = ble_ll_adv_sm_find_configured(instance); - if (!advsm) { - return BLE_ERR_UNK_ADV_INDENT; - } - - /* - * Reject if connectable advertising is on - * Core Spec Vol. 2 Part E 7.8.52 - */ - if (advsm->adv_enabled && - (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE)) { - return BLE_ERR_CMD_DISALLOWED; - } - - memcpy(advsm->adv_random_addr, addr, BLE_DEV_ADDR_LEN); - return BLE_ERR_SUCCESS; -} - -int -ble_ll_adv_hci_set_random_addr(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_adv_set_rnd_addr_cp *cmd = (const void *) cmdbuf; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return ble_ll_adv_set_random_addr(cmd->addr, cmd->adv_handle); -} - -/** - * HCI LE extended advertising remove command - * - * @return int BLE error code - */ -int -ble_ll_adv_remove(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_remove_adv_set_cp *cmd = (const void *) cmdbuf; - struct ble_ll_adv_sm *advsm; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - advsm = ble_ll_adv_sm_find_configured(cmd->adv_handle); - if (!advsm) { - return BLE_ERR_UNK_ADV_INDENT; - } - - if (advsm->adv_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - if (advsm->periodic_adv_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } - - if (advsm->periodic_adv_data) { - os_mbuf_free_chain(advsm->periodic_adv_data); - } -#endif - - if (advsm->adv_data) { - os_mbuf_free_chain(advsm->adv_data); - } - if (advsm->scan_rsp_data) { - os_mbuf_free_chain(advsm->scan_rsp_data); - } - - ble_ll_adv_sm_init(advsm); - - return BLE_ERR_SUCCESS; -} - -/** - * HCI LE extended advertising clear command - * - * @return int BLE error code - */ -int -ble_ll_adv_clear_all(void) -{ - int i; - - for (i = 0; i < BLE_ADV_INSTANCES; i++) { - if (g_ble_ll_adv_sm[i].adv_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - if (g_ble_ll_adv_sm[i].periodic_adv_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } -#endif - } - - ble_ll_adv_reset(); - - return BLE_ERR_SUCCESS; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) -static uint16_t -ble_ll_adv_sync_get_pdu_len(uint16_t data_len, uint16_t *data_offset, - uint16_t props) -{ - uint16_t rem_data_len = data_len - *data_offset; - uint8_t hdr_len = BLE_LL_EXT_ADV_HDR_LEN; - uint8_t ext_hdr = 0; - - /* TxPower if configured - * Note: TxPower shall not be present in chain PDU for SYNC - */ - if (*data_offset == 0 && - (props & BLE_HCI_LE_SET_PERIODIC_ADV_PROP_INC_TX_PWR)) { - ext_hdr |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); - hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; - } - - /* if we have any fields in ext header we need to add flags, note that Aux - * PTR is handled later and it will account for flags if needed - * - * This could be handled inside TxPower but lets keep code consistent with - * how Aux calculate works and this also make it easier to add more fields - * into flags if needed in future - */ - if (ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; - } - - /* AdvData always */ - data_len = min(BLE_LL_MAX_PAYLOAD_LEN - hdr_len, rem_data_len); - - /* AuxPtr if there are more AdvData remaining that we can fit here */ - if (rem_data_len > data_len) { - /* adjust for flags that needs to be added if AuxPtr is only field - * in Extended Header - */ - if (!ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; - data_len -= BLE_LL_EXT_ADV_FLAGS_SIZE; - } - - hdr_len += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - data_len -= BLE_LL_EXT_ADV_AUX_PTR_SIZE; - - /* PDU payload should be full if chained */ - BLE_LL_ASSERT(hdr_len + data_len == BLE_LL_MAX_PAYLOAD_LEN); - } - - *data_offset += data_len; - - return hdr_len + data_len; -} - -static bool -ble_ll_adv_periodic_check_data_itvl(uint16_t payload_len, uint16_t props, - uint16_t itvl, uint8_t phy) -{ - uint32_t max_usecs = 0; - uint32_t itvl_usecs; - uint16_t offset = 0; - uint16_t pdu_len; - - while (offset < payload_len) { - pdu_len = ble_ll_adv_sync_get_pdu_len(payload_len, &offset, props); - - max_usecs += ble_ll_pdu_tx_time_get(pdu_len, phy); - max_usecs += ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS + - MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY)); - } - - itvl_usecs = (uint32_t)itvl * BLE_LL_ADV_PERIODIC_ITVL; - - return max_usecs < itvl_usecs; -} - -int -ble_ll_adv_periodic_set_param(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_periodic_adv_params_cp *cmd = (const void *) cmdbuf; - struct ble_ll_adv_sm *advsm; - uint16_t adv_itvl_min; - uint16_t adv_itvl_max; - uint16_t props; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - adv_itvl_min = le16toh(cmd->min_itvl); - adv_itvl_max = le16toh(cmd->max_itvl); - props = le16toh(cmd->props); - - advsm = ble_ll_adv_sm_find_configured(cmd->adv_handle); - if (!advsm) { - return BLE_ERR_UNK_ADV_INDENT; - } - - /* If the advertising set identified by the Advertising_Handle specified - * scannable, connectable, legacy, or anonymous advertising, the Controller - * shall return the error code Invalid HCI Command Parameters (0x12). - */ - if (advsm->props & (BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV | - BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE | - BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE | - BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* If the Host issues this command when periodic advertising is enabled for - * the specified advertising set, the Controller shall return the error code - * Command Disallowed (0x0C). - */ - if (advsm->periodic_adv_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* validate intervals */ - if ((adv_itvl_min < 0x0006) || (adv_itvl_max < 0x006) || - (adv_itvl_min > adv_itvl_max)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* validate properties */ - if (props & ~BLE_HCI_LE_SET_PERIODIC_ADV_PROP_MASK) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* If the advertising set already contains periodic advertising data and the - * length of the data is greater than the maximum that the Controller can - * transmit within a periodic advertising interval of - * Periodic_Advertising_Interval_Max, the Controller shall return the error - * code Packet Too Long (0x45). - */ - if (!ble_ll_adv_periodic_check_data_itvl(SYNC_DATA_LEN(advsm), props, - adv_itvl_max, advsm->sec_phy)) { - return BLE_ERR_PACKET_TOO_LONG; - } - - advsm->periodic_adv_itvl_min = adv_itvl_min; - advsm->periodic_adv_itvl_max = adv_itvl_max; - advsm->periodic_adv_props = props; - - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_CONFIGURED); - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_adv_periodic_set_data(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_periodic_adv_data_cp *cmd = (const void *) cmdbuf; - struct ble_ll_adv_sm *advsm; - uint16_t payload_total_len; - bool new_data = false; - - if (len < sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (cmd->adv_data_len > BLE_HCI_MAX_PERIODIC_ADV_DATA_LEN || - cmd->adv_data_len != len - sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - advsm = ble_ll_adv_sm_find_configured(cmd->adv_handle); - if (!advsm) { - return BLE_ERR_UNK_ADV_INDENT; - } - - if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_CONFIGURED)) { - return BLE_ERR_CMD_DISALLOWED; - } - - switch (cmd->operation) { - case BLE_HCI_LE_SET_DATA_OPER_LAST: - case BLE_HCI_LE_SET_DATA_OPER_INT: - if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_DATA_INCOMPLETE)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (!advsm->periodic_adv_data || !cmd->adv_data_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (advsm->periodic_adv_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } - break; - case BLE_HCI_LE_SET_DATA_OPER_FIRST: - if (advsm->periodic_adv_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } - - if (!cmd->adv_data_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - new_data = true; - break; - case BLE_HCI_LE_SET_DATA_OPER_COMPLETE: - new_data = true; - break; - default: - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - payload_total_len = cmd->adv_data_len; - if (!new_data) { - payload_total_len += SYNC_DATA_LEN(advsm); - } - - /* If the combined length of the data is greater than the maximum that the - * Controller can transmit within the current periodic advertising interval - * (if periodic advertising is currently enabled) or the - * Periodic_Advertising_Interval_Max for the advertising set (if currently - * disabled), all the data shall be discarded and the Controller shall - * return the error code Packet Too Long (0x45). - */ - if (!ble_ll_adv_periodic_check_data_itvl(payload_total_len, - advsm->periodic_adv_props, - advsm->periodic_adv_itvl_max, - advsm->sec_phy)) { - return BLE_ERR_PACKET_TOO_LONG; - } - - if (advsm->periodic_adv_active) { - ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_NEW_DATA); - - ble_ll_adv_update_data_mbuf(&advsm->periodic_new_data, true, - BLE_ADV_DATA_MAX_LEN, - cmd->adv_data, cmd->adv_data_len); - if (!advsm->periodic_new_data) { - return BLE_ERR_MEM_CAPACITY; - } - - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_NEW_DATA); - } else { - ble_ll_adv_update_data_mbuf(&advsm->periodic_adv_data, new_data, - BLE_ADV_DATA_MAX_LEN, cmd->adv_data, - cmd->adv_data_len); - if (!advsm->periodic_adv_data) { - return BLE_ERR_MEM_CAPACITY; - } - } - - /* set/clear incomplete data flag only on success */ - switch (cmd->operation) { - case BLE_HCI_LE_SET_DATA_OPER_LAST: - case BLE_HCI_LE_SET_DATA_OPER_COMPLETE: - ble_ll_adv_flags_clear(advsm, - BLE_LL_ADV_SM_FLAG_PERIODIC_DATA_INCOMPLETE); - break; - case BLE_HCI_LE_SET_DATA_OPER_INT: - case BLE_HCI_LE_SET_DATA_OPER_FIRST: - default: - ble_ll_adv_flags_set(advsm, - BLE_LL_ADV_SM_FLAG_PERIODIC_DATA_INCOMPLETE); - break; - } - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_adv_periodic_enable(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_periodic_adv_enable_cp *cmd = (const void *)cmdbuf; - struct ble_ll_adv_sm *advsm; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - advsm = ble_ll_adv_sm_find_configured(cmd->adv_handle); - if (!advsm) { - return BLE_ERR_UNK_ADV_INDENT; - } - - if (cmd->enable) { - if (advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_DATA_INCOMPLETE) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* If Enable is set to 0x01 and the length of the periodic advertising - * data is greater than the maximum that the Controller can transmit - * within the chosen periodicadvertising interval, the Controller shall - * return the error code Packet Too Long (0x45). - */ - if (!ble_ll_adv_periodic_check_data_itvl(SYNC_DATA_LEN(advsm), - advsm->periodic_adv_props, - advsm->periodic_adv_itvl_max, - advsm->sec_phy)) { - return BLE_ERR_PACKET_TOO_LONG; - } - - /* If the advertising set is not currently enabled (see the - * LE_Set_Extended_Advertising_Enable command), the periodic advertising - * is not started until the advertising set is enabled. - */ - if (advsm->adv_enabled && !advsm->periodic_adv_active) { - /* Start the periodic advertising state machine */ - ble_ll_adv_sm_start_periodic(advsm); - } - } else { - /* Stop the periodic advertising state machine */ - ble_ll_adv_sm_stop_periodic(advsm); - } - - advsm->periodic_adv_enabled = cmd->enable; - - return BLE_ERR_SUCCESS; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -static int -ble_ll_adv_periodic_send_sync_ind(struct ble_ll_adv_sm *advsm, - struct ble_ll_conn_sm *connsm, - uint16_t service_data) -{ - struct os_mbuf *om; - uint8_t *sync_ind; - - om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN, - sizeof(struct ble_mbuf_hdr)); - if (!om) { - return BLE_ERR_MEM_CAPACITY; - } - - om->om_data[0] = BLE_LL_CTRL_PERIODIC_SYNC_IND; - - sync_ind = om->om_data + 1; - - /* ID (service_data), already in LE order */ - memcpy(sync_ind, &service_data, sizeof(service_data)); - - /* fill in syncinfo */ - ble_ll_adv_put_syncinfo(advsm, connsm, sync_ind + 20, sync_ind + 2); - - /* lastPaEventCounter */ - put_le16(sync_ind + 22, advsm->periodic_event_cntr_last_sent); - - /* SID, AType, SCA */ - sync_ind[24] = (advsm->adi >> 12); - sync_ind[24] |= !!(advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) << 4; - sync_ind[24] |= BLE_LL_SCA_ENUM << 5; - - /* PHY */ - sync_ind[25] = (0x01 << (advsm->sec_phy - 1)); - - /* AdvA */ - memcpy(sync_ind + 26, advsm->adva, BLE_DEV_ADDR_LEN); - - /* syncConnEventCount */ - put_le16(sync_ind + 32, connsm->event_cntr); - - ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, - BLE_LL_CTRL_PERIODIC_SYNC_IND_LEN + 1); - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_periodic_adv_set_info_transfer_cp *cmd = (const void *)cmdbuf; - struct ble_hci_le_periodic_adv_set_info_transfer_rp *rsp = (void *) rspbuf; - struct ble_ll_conn_sm *connsm; - struct ble_ll_adv_sm *advsm; - uint16_t handle; - int rc; - - if (len != sizeof(*cmd)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - advsm = ble_ll_adv_sm_find_configured(cmd->adv_handle); - if (!advsm) { - rc = BLE_ERR_UNK_ADV_INDENT; - goto done; - } - - if (!advsm->periodic_adv_active) { - rc = BLE_ERR_CMD_DISALLOWED; - goto done; - } - - handle = le16toh(cmd->conn_handle); - if (handle > 0xeff) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - connsm = ble_ll_conn_find_active_conn(handle); - if (!connsm) { - rc = BLE_ERR_UNK_CONN_ID; - goto done; - } - - /* TODO should not need to shift - * byte 3 (0 byte is conn_feature) , bit 1 - * - * Allow initiate LL procedure only if remote supports it. - */ - if (!(connsm->remote_features[2] & (BLE_LL_FEAT_SYNC_TRANS_RECV >> (8 * 3)))) { - rc = BLE_ERR_UNSUPP_REM_FEATURE; - goto done; - } - - rc = ble_ll_adv_periodic_send_sync_ind(advsm, connsm, cmd->service_data); - done: - rsp->conn_handle = cmd->conn_handle; - *rsplen = sizeof(*rsp); - return rc; -} -#endif -#endif -#endif - -/** - * Says whether the specified address is already connected or not. - * @param [in] addr The peer address. - * @param [in] addr_type Public address (0) or random address (1). - * @return Return 1 if already connected, 0 otherwise. - */ -static int -ble_ll_adv_already_connected(const uint8_t* addr, uint8_t addr_type) -{ - struct ble_ll_conn_sm *connsm; - - /* extracted from ble_ll_conn_slave_start function */ - SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) { - if (!memcmp(&connsm->peer_addr, addr, BLE_DEV_ADDR_LEN)) { - if (addr_type == BLE_ADDR_RANDOM) { - if (connsm->peer_addr_type & 1) { - return 1; - } - } else { - if ((connsm->peer_addr_type & 1) == 0) { - return 1; - } - } - } - } - - return 0; -} - -/** - * Called when the LL receives a scan request or connection request - * - * Context: Called from interrupt context. - * - * @param rxbuf - * - * @return -1: request not for us or is a connect request. - * 0: request (scan) is for us and we successfully went from rx to tx. - * > 0: PHY error attempting to go from rx to tx. - */ -static int -ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) -{ - int rc; - int resolved; - uint8_t chk_wl; - uint8_t txadd; - uint8_t peer_addr_type; - uint8_t *rxbuf; - uint8_t *adva; - uint8_t *peer; - struct ble_mbuf_hdr *ble_hdr; - struct ble_ll_adv_sm *advsm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct aux_conn_rsp_data rsp_data; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - struct ble_ll_resolv_entry *rl; -#endif - - /* See if adva in the request (scan or connect) matches what we sent */ - advsm = g_ble_ll_cur_adv_sm; - rxbuf = rxpdu->om_data; - adva = rxbuf + BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN; - if (memcmp(advsm->adva, adva, BLE_DEV_ADDR_LEN)) { - return -1; - } - - /* Set device match bit if we are whitelisting */ - if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) { - chk_wl = advsm->adv_filter_policy & 1; - } else { - chk_wl = advsm->adv_filter_policy & 2; - } - - /* Get the peer address type */ - if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) { - txadd = BLE_ADDR_RANDOM; - } else { - txadd = BLE_ADDR_PUBLIC; - } - - ble_hdr = BLE_MBUF_HDR_PTR(rxpdu); - peer = rxbuf + BLE_LL_PDU_HDR_LEN; - peer_addr_type = txadd; - resolved = 0; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - rl = NULL; - if (ble_ll_resolv_enabled()) { - if (ble_ll_is_rpa(peer, txadd)) { - advsm->adv_rpa_index = ble_hw_resolv_list_match(); - if (advsm->adv_rpa_index >= 0) { - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_RESOLVED; - rl = &g_ble_ll_resolv_list[advsm->adv_rpa_index]; - if (chk_wl) { - peer = rl->rl_identity_addr; - peer_addr_type = rl->rl_addr_type; - resolved = 1; - } - } else { - if (chk_wl) { - return -1; - } - } - } else { - /* Verify privacy mode */ - rl = ble_ll_resolv_list_find(peer, peer_addr_type); - if (rl && (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && - rl->rl_has_peer) { - return -1; - } - } - } -#endif - - /* Set device match bit if we are whitelisting */ - if (chk_wl && !ble_ll_whitelist_match(peer, peer_addr_type, resolved)) { - return -1; - } - - /* - * We set the device match bit to tell the upper layer that we will - * accept the request - */ - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_DEVMATCH; - - /* Setup to transmit the scan response if appropriate */ - rc = -1; - - if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) { - /* PHY used for scan requests shall be the same as the PHY used for the - * PDU that they reply to so no need to change PHY mode. - */ - ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (advsm->flags & BLE_LL_ADV_SM_FLAG_SCAN_REQ_NOTIF) { - ble_ll_hci_ev_send_scan_req_recv(advsm->adv_instance, peer, - peer_addr_type); - } - - /* - * We need to store current rxed packet header temporarily so AuxPtr - * can be calculated (if necessary) relative to AUX_SCAN_RSP instead of - * AUX_ADV_IND. - */ - - advsm->rx_ble_hdr = ble_hdr; - rc = ble_phy_tx(ble_ll_adv_scan_rsp_pdu_make, advsm, - BLE_PHY_TRANSITION_NONE); - advsm->rx_ble_hdr = NULL; -#else - rc = ble_phy_tx(ble_ll_adv_scan_rsp_legacy_pdu_make, advsm, - BLE_PHY_TRANSITION_NONE); -#endif - - if (!rc) { - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_SCAN_RSP_TXD; - STATS_INC(ble_ll_stats, scan_rsp_txg); - } - } else if (pdu_type == BLE_ADV_PDU_TYPE_AUX_CONNECT_REQ) { - /* See if the device is already connected */ - if (ble_ll_adv_already_connected(peer, peer_addr_type)) { - return -1; - } - - /* - * Only accept connect requests from the desired address if we - * are doing directed advertising - */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { - if (memcmp(advsm->initiator_addr, peer, BLE_DEV_ADDR_LEN)) { - return -1; - } - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - return -1; - } - - /* use remote address used over the air */ - rsp_data.advsm = advsm; - rsp_data.peer = rxbuf + BLE_LL_PDU_HDR_LEN; - rsp_data.rxadd = rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK; - - ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm); - rc = ble_phy_tx(ble_ll_adv_aux_conn_rsp_pdu_make, &rsp_data, - BLE_PHY_TRANSITION_NONE); - if (!rc) { - ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD); - STATS_INC(ble_ll_stats, aux_conn_rsp_tx); - } -#endif - } - - return rc; -} - -/** - * Called when a connect request has been received. - * - * Context: Link Layer - * - * @param rxbuf - * @param flags - * - * @return 0: no connection started. 1: connection started - */ -static int -ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr, - struct ble_ll_adv_sm *advsm) -{ - int valid; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - uint8_t resolved; -#endif - uint8_t addr_type; - uint8_t *inita; - uint8_t *ident_addr; - - /* Don't create connection if AUX_CONNECT_RSP was not send */ - if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) { - if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD)) { - return 0; - } - } - - /* Check filter policy. */ - valid = 0; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - resolved = BLE_MBUF_HDR_RESOLVED(hdr); -#endif - inita = rxbuf + BLE_LL_PDU_HDR_LEN; - if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_DEVMATCH) { - - valid = 1; - if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) { - addr_type = BLE_ADDR_RANDOM; - } else { - addr_type = BLE_ADDR_PUBLIC; - } - - /* - * Only accept connect requests from the desired address if we - * are doing directed advertising - */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { - ident_addr = inita; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (resolved) { - ident_addr = g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_identity_addr; - addr_type = g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_addr_type; - } -#endif - if ((addr_type != advsm->peer_addr_type) || - memcmp(advsm->peer_addr, ident_addr, BLE_DEV_ADDR_LEN)) { - valid = 0; - } - } - } - - if (valid) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (resolved) { - /* Retain the resolvable private address that we received. */ - memcpy(advsm->adv_rpa, inita, BLE_DEV_ADDR_LEN); - - /* Update resolving list with current peer RPA */ - ble_ll_resolv_set_peer_rpa(advsm->adv_rpa_index, inita); - - /* - * Overwrite received inita with identity address since that - * is used from now on. - */ - memcpy(inita, - g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_identity_addr, - BLE_DEV_ADDR_LEN); - - /* Peer address type is an identity address */ - addr_type = g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_addr_type; - addr_type += 2; - } -#endif - - /* Try to start slave connection. If successful, stop advertising */ - valid = ble_ll_conn_slave_start(rxbuf, addr_type, hdr, - !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)); - if (valid) { - /* stop advertising only if not transmitting connection response */ - if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD)) { - ble_ll_adv_sm_stop(advsm); - } - } - } - - return valid; -} - -/** - * Called on phy rx pdu end when in advertising state. - * - * There are only two pdu types we care about in this state: scan requests - * and connection requests. When we receive a scan request we must determine if - * we need to send a scan response and that needs to be acted on within T_IFS. - * - * When we receive a connection request, we need to determine if we will allow - * this device to start a connection with us. However, no immediate response is - * sent so we handle this at the link layer task. - * - * Context: Interrupt - * - * @param pdu_type Type of pdu received. - * @param rxpdu Pointer to received PDU - * - * @return int - * < 0: Disable the phy after reception. - * == 0: Do not disable the PHY - * > 0: Do not disable PHY as that has already been done. - */ -int -ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok) -{ - int rc; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_mbuf_hdr *rxhdr; -#endif - - rc = -1; - if (rxpdu == NULL) { - ble_ll_adv_tx_done(g_ble_ll_cur_adv_sm); - } else { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - rxhdr = BLE_MBUF_HDR_PTR(rxpdu); - rxhdr->rxinfo.user_data = g_ble_ll_cur_adv_sm; - if (ble_ll_adv_active_chanset_is_sec(g_ble_ll_cur_adv_sm)) { - rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_EXT_ADV_SEC; - } else { - assert(ble_ll_adv_active_chanset_is_pri(g_ble_ll_cur_adv_sm)); - } -#endif - if (crcok) { - if ((pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) || - (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_IND)) { - /* Process request */ - rc = ble_ll_adv_rx_req(pdu_type, rxpdu); - } - } - - if (rc) { - /* We no longer have a current state machine */ - g_ble_ll_cur_adv_sm = NULL; - } - } - - if (rc) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - } - - return rc; -} - -/** - * Process a received packet at the link layer task when in the advertising - * state - * - * Context: Link Layer - * - * - * @param ptype - * @param rxbuf - * @param hdr - * - * @return int - */ -void -ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr) -{ - int adv_event_over; - struct ble_ll_adv_sm *advsm; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - advsm = (struct ble_ll_adv_sm *)hdr->rxinfo.user_data; -#else - advsm = &g_ble_ll_adv_sm[0]; -#endif - - /* - * It is possible that advertising was stopped and a packet plcaed on the - * LL receive packet queue. In this case, just ignore the received packet - * as the advertising state machine is no longer "valid" - */ - if (!advsm->adv_enabled) { - return; - } - - /* - * If we have received a scan request and we are transmitting a response - * or we have received a valid connect request, dont "end" the advertising - * event. In the case of a connect request we will stop advertising. In - * the case of the scan response transmission we will get a transmit - * end callback. - */ - adv_event_over = 1; - if (BLE_MBUF_HDR_CRC_OK(hdr)) { - if (ptype == BLE_ADV_PDU_TYPE_CONNECT_IND) { - if (ble_ll_adv_conn_req_rxd(rxbuf, hdr, advsm)) { - adv_event_over = 0; - } - } else { - if ((ptype == BLE_ADV_PDU_TYPE_SCAN_REQ) && - (hdr->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_TXD)) { - adv_event_over = 0; - } - } - } - - if (adv_event_over) { - ble_ll_adv_make_done(advsm, hdr); - } -} - -/** - * Called when a receive PDU has started and we are advertising. - * - * Context: interrupt - * - * @param pdu_type - * @param rxpdu - * - * @return int - * < 0: A frame we dont want to receive. - * = 0: Continue to receive frame. Dont go from rx to tx - * > 0: Continue to receive frame and go from rx to tx when done - */ -int -ble_ll_adv_rx_isr_start(uint8_t pdu_type) -{ - int rc; - struct ble_ll_adv_sm *advsm; - - /* Assume we will abort the frame */ - rc = -1; - - /* If we get a scan request we must tell the phy to go from rx to tx */ - advsm = g_ble_ll_cur_adv_sm; - if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) { - /* Only accept scan requests if we are indirect adv or scan adv */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) { - rc = 1; - } - } else { - /* Only accept connect requests if connectable advertising event */ - if (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_IND) { - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { - /* Need transition to TX if extended adv */ - rc = !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY); - } - } - } - - /* - * If we abort the frame, we need to post the LL task to check if the - * advertising event is over. - */ - if (rc < 0) { - ble_ll_adv_tx_done(advsm); - } - - return rc; -} - -static void -ble_ll_adv_drop_event(struct ble_ll_adv_sm *advsm) -{ - STATS_INC(ble_ll_stats, adv_drop_event); - - ble_ll_sched_rmv_elem(&advsm->adv_sch); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_ll_sched_rmv_elem(&advsm->aux[0].sch); - ble_ll_sched_rmv_elem(&advsm->aux[1].sch); - - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); - advsm->aux_active = 0; -#endif - - advsm->adv_chan = ble_ll_adv_final_chan(advsm); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); -} - -static void -ble_ll_adv_reschedule_event(struct ble_ll_adv_sm *advsm) -{ - int rc; - uint32_t start_time; - uint32_t max_delay_ticks; - - assert(advsm->adv_enabled); - - if (!advsm->adv_sch.enqueued) { - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { - max_delay_ticks = 0; - } else { - max_delay_ticks = - os_cputime_usecs_to_ticks(BLE_LL_ADV_DELAY_MS_MAX * 1000); - } - - rc = ble_ll_sched_adv_reschedule(&advsm->adv_sch, &start_time, - max_delay_ticks); - if (rc) { - ble_ll_adv_drop_event(advsm); - return; - } - - start_time += g_ble_ll_sched_offset_ticks; - advsm->adv_event_start_time = start_time; - advsm->adv_pdu_start_time = start_time; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && - !advsm->aux_active) { - ble_ll_adv_aux_schedule(advsm); - } -#endif -} - -/** - * Called when an advertising event is over. - * - * Context: Link Layer task. - * - * @param arg Pointer to advertising state machine. - */ -static void -ble_ll_adv_done(struct ble_ll_adv_sm *advsm) - -{ - int rc; - int resched_pdu; - uint8_t mask; - uint8_t final_adv_chan; - int32_t delta_t; - uint32_t itvl; - uint32_t tick_itvl; - uint32_t start_time; - - assert(advsm->adv_enabled); - - ble_ll_rfmgmt_release(); - - ble_ll_adv_update_adv_scan_rsp_data(advsm); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - /* stop advertising this was due to transmitting connection response */ - if (advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD) { - ble_ll_adv_sm_stop(advsm); - return; - } - } -#endif - - /* Remove the element from the schedule if it is still there. */ - ble_ll_sched_rmv_elem(&advsm->adv_sch); - - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); - - /* - * Check if we have ended our advertising event. If our last advertising - * packet was sent on the last channel, it means we are done with this - * event. - */ - final_adv_chan = ble_ll_adv_final_chan(advsm); - - if (advsm->adv_chan == final_adv_chan) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (advsm->events_max) { - advsm->events++; - } -#endif - - ble_ll_scan_chk_resume(); - - /* This event is over. Set adv channel to first one */ - advsm->adv_chan = ble_ll_adv_first_chan(advsm); - - /* - * Calculate start time of next advertising event. NOTE: we do not - * add the random advDelay as the scheduling code will do that. - */ - itvl = advsm->adv_itvl_usecs; - tick_itvl = os_cputime_usecs_to_ticks(itvl); - advsm->adv_event_start_time += tick_itvl; - advsm->adv_pdu_start_time = advsm->adv_event_start_time; - - /* - * The scheduled time better be in the future! If it is not, we will - * just keep advancing until we the time is in the future - */ - start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks; - - delta_t = (int32_t)(start_time - os_cputime_get32()); - if (delta_t < 0) { - /* - * NOTE: we just the same interval that we calculated earlier. - * No real need to keep recalculating a new interval. - */ - while (delta_t < 0) { - advsm->adv_event_start_time += tick_itvl; - advsm->adv_pdu_start_time = advsm->adv_event_start_time; - delta_t += (int32_t)tick_itvl; - } - } - resched_pdu = 0; - } else { - /* - * Move to next advertising channel. If not in the mask, just - * increment by 1. We can do this because we already checked if we - * just transmitted on the last advertising channel - */ - ++advsm->adv_chan; - mask = 1 << (advsm->adv_chan - BLE_PHY_ADV_CHAN_START); - if ((mask & advsm->adv_chanmask) == 0) { - ++advsm->adv_chan; - } - - /* - * We will transmit right away. Set next pdu start time to now - * plus a xcvr start delay just so we dont count late adv starts - */ - advsm->adv_pdu_start_time = os_cputime_get32() + - g_ble_ll_sched_offset_ticks; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* If we're past aux (unlikely, but can happen), just drop an event */ - if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && - advsm->aux_active && - advsm->adv_pdu_start_time > AUX_CURRENT(advsm)->start_time) { - ble_ll_adv_drop_event(advsm); - return; - } -#endif - - resched_pdu = 1; - } - - /* check if advertising timed out */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (advsm->duration && - advsm->adv_pdu_start_time >= advsm->adv_end_time) { - /* Legacy PDUs need to be stop here. - * For ext adv it will be stopped when AUX is done (unless it was - * dropped so check if AUX is active here as well). - */ - if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) || - !advsm->aux_active) { - ble_ll_adv_sm_stop_timeout(advsm); - } - - return; - } -#else - if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) && - (advsm->adv_pdu_start_time >= advsm->adv_end_time)) { - ble_ll_adv_sm_stop_timeout(advsm); - return; - } -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (advsm->events_max && (advsm->events >= advsm->events_max)) { - /* Legacy PDUs need to be stop here. - * For ext adv it will be stopped when AUX is done (unless it was - * dropped so check if AUX is active here as well). - */ - if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) || - !advsm->aux_active) { - ble_ll_adv_sm_stop_limit_reached(advsm); - } - - return; - } -#endif - - /* We need to regenerate our RPA's if we have passed timeout */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - ble_ll_adv_chk_rpa_timeout(advsm); -#endif - - /* Schedule advertising transmit */ - ble_ll_adv_set_sched(advsm); - - if (!resched_pdu) { - ble_ll_adv_reschedule_event(advsm); - return; - } - - /* - * In the unlikely event we can't reschedule this, just post a done event - * and we will reschedule the next advertising PDU. - */ - rc = ble_ll_sched_adv_resched_pdu(&advsm->adv_sch); - if (rc) { - STATS_INC(ble_ll_stats, adv_resched_pdu_fail); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); - } -} - -static void -ble_ll_adv_event_done(struct ble_npl_event *ev) -{ - ble_ll_adv_done(ble_npl_event_get_arg(ev)); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -/** - * Called when auxiliary packet is txd on secondary channel - * - * Context: Link Layer task. - * - * @param ev - */ -static void -ble_ll_adv_sec_done(struct ble_ll_adv_sm *advsm) -{ - struct ble_ll_adv_aux *aux; - struct ble_ll_adv_aux *aux_next; - - assert(advsm->adv_enabled); - assert(advsm->aux_active); - - aux = AUX_CURRENT(advsm); - aux_next = AUX_NEXT(advsm); - - /* We don't need RF anymore */ - ble_ll_rfmgmt_release(); - - if (advsm->aux_dropped) { - ble_ll_adv_drop_event(advsm); - return; - } - - if (advsm->aux_not_scanned) { - ble_ll_sched_rmv_elem(&aux_next->sch); - } - - /* Remove anything else scheduled for secondary channel */ - ble_ll_sched_rmv_elem(&aux->sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); - - /* Stop advertising due to transmitting connection response */ - if (advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD) { - ble_ll_adv_sm_stop(advsm); - return; - } - - /* If we have next AUX scheduled, try to schedule another one */ - if (aux_next->sch.enqueued) { - advsm->aux_index ^= 1; - advsm->aux_first_pdu = 0; - ble_ll_adv_aux_schedule_next(advsm); - return; - } - - ble_ll_scan_chk_resume(); - - /* Check if advertising timed out */ - if (advsm->duration && (advsm->adv_pdu_start_time >= advsm->adv_end_time)) { - ble_ll_adv_sm_stop_timeout(advsm); - return; - } - - if (advsm->events_max && (advsm->events >= advsm->events_max)) { - ble_ll_adv_sm_stop_limit_reached(advsm); - return; - } - - advsm->aux_active = 0; - ble_ll_adv_update_adv_scan_rsp_data(advsm); - ble_ll_adv_reschedule_event(advsm); -} - -static void -ble_ll_adv_sec_event_done(struct ble_npl_event *ev) -{ - ble_ll_adv_sec_done(ble_npl_event_get_arg(ev)); -} -#endif - -static void -ble_ll_adv_make_done(struct ble_ll_adv_sm *advsm, struct ble_mbuf_hdr *hdr) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (BLE_MBUF_HDR_EXT_ADV_SEC(hdr)) { - assert(!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)); - assert(ble_ll_adv_active_chanset_is_sec(advsm)); - ble_ll_adv_active_chanset_clear(advsm); - ble_ll_adv_sec_done(advsm); - } else { - assert(ble_ll_adv_active_chanset_is_pri(advsm)); - ble_ll_adv_active_chanset_clear(advsm); - ble_ll_adv_done(advsm); - } -#else - ble_ll_adv_active_chanset_clear(advsm); - ble_ll_adv_done(advsm); -#endif -} - -/** - * Checks if the controller can change the whitelist. If advertising is enabled - * and is using the whitelist the controller is not allowed to change the - * whitelist. - * - * @return int 0: not allowed to change whitelist; 1: change allowed. - */ -int -ble_ll_adv_can_chg_whitelist(void) -{ - struct ble_ll_adv_sm *advsm; - int rc; - int i; - - rc = 1; - for (i = 0; i < BLE_ADV_INSTANCES; ++i) { - advsm = &g_ble_ll_adv_sm[i]; - if (advsm->adv_enabled && - (advsm->adv_filter_policy != BLE_HCI_ADV_FILT_NONE)) { - rc = 0; - break; - } - } - - return rc; -} - -/** - * Sends the connection complete event when advertising a connection starts. - * - * @return uint8_t* Pointer to event buffer - */ -void -ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm, - struct ble_mbuf_hdr *rxhdr) -{ - uint8_t *evbuf; - struct ble_ll_adv_sm *advsm; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - advsm = (struct ble_ll_adv_sm *)rxhdr->rxinfo.user_data; -#else - advsm = &g_ble_ll_adv_sm[0]; -#endif - - evbuf = advsm->conn_comp_ev; - assert(evbuf != NULL); - advsm->conn_comp_ev = NULL; - - ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, evbuf, advsm); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - ble_ll_hci_ev_le_csa(connsm); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (ble_ll_hci_adv_mode_ext()) { - ble_ll_hci_ev_send_adv_set_terminated(0, advsm->adv_instance, - connsm->conn_handle, advsm->events); - } -#endif -} - -/** - * Returns the local resolvable private address currently being using by - * the advertiser - * - * @return uint8_t* - */ -uint8_t * -ble_ll_adv_get_local_rpa(struct ble_ll_adv_sm *advsm) -{ - uint8_t *rpa = NULL; - - if (advsm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { - if ((advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) && - ble_ll_is_rpa(advsm->adva, 1)) { - rpa = advsm->adva; - } - } - - return rpa; -} - -/** - * Returns the peer resolvable private address of last device connecting to us - * - * @return uint8_t* - */ -uint8_t * -ble_ll_adv_get_peer_rpa(struct ble_ll_adv_sm *advsm) -{ - /* XXX: should this go into IRK list or connection? */ - return advsm->adv_rpa; -} - -/** - * Called when the LL wait for response timer expires while in the advertising - * state. Disables the phy and - * - */ -void -ble_ll_adv_wfr_timer_exp(void) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - g_ble_ll_cur_adv_sm->aux_not_scanned = 1; -#endif - - ble_phy_disable(); - ble_ll_adv_tx_done(g_ble_ll_cur_adv_sm); -} - -/** - * Reset the advertising state machine. - * - * Context: Link Layer task - * - */ -void -ble_ll_adv_reset(void) -{ - int i; - struct ble_ll_adv_sm *advsm; - - for (i = 0; i < BLE_ADV_INSTANCES; ++i) { - advsm = &g_ble_ll_adv_sm[i]; - - /* Stop advertising state machine */ - ble_ll_adv_sm_stop(advsm); - - /* clear any data present */ - os_mbuf_free_chain(advsm->adv_data); - os_mbuf_free_chain(advsm->scan_rsp_data); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - /* Stop periodic advertising state machine */ - ble_ll_adv_sm_stop_periodic(advsm); - - /* clear any periodic data present */ - os_mbuf_free_chain(advsm->periodic_adv_data); -#endif - - /* re-initialize the advertiser state machine */ - ble_ll_adv_sm_init(advsm); - } -} - -/* Called to determine if advertising is enabled. - */ -uint8_t -ble_ll_adv_enabled(void) -{ - int i; - - for (i = 0; i < BLE_ADV_INSTANCES; i++) { - if (g_ble_ll_adv_sm[i].adv_enabled) { - return 1; - } - } - - return 0; -} - -static void -ble_ll_adv_sm_init(struct ble_ll_adv_sm *advsm) -{ - memset(advsm, 0, sizeof(struct ble_ll_adv_sm)); - - advsm->adv_itvl_min = BLE_HCI_ADV_ITVL_DEF; - advsm->adv_itvl_max = BLE_HCI_ADV_ITVL_DEF; - advsm->adv_chanmask = BLE_HCI_ADV_CHANMASK_DEF; - - /* Initialize advertising tx done event */ - ble_npl_event_init(&advsm->adv_txdone_ev, ble_ll_adv_event_done, advsm); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_npl_event_init(&advsm->adv_sec_txdone_ev, ble_ll_adv_sec_event_done, advsm); -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - ble_npl_event_init(&advsm->adv_periodic_txdone_ev, - ble_ll_adv_periodic_event_done, advsm); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* Initialize aux schedulers */ - advsm->aux_active = 0; - advsm->aux[0].sch.cb_arg = advsm; - advsm->aux[0].sch.sched_cb = ble_ll_adv_secondary_tx_start_cb; - advsm->aux[0].sch.sched_type = BLE_LL_SCHED_TYPE_ADV; - advsm->aux[1].sch.cb_arg = advsm; - advsm->aux[1].sch.sched_cb = ble_ll_adv_secondary_tx_start_cb; - advsm->aux[1].sch.sched_type = BLE_LL_SCHED_TYPE_ADV; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - /* Initialize sync schedulers */ - advsm->periodic_sync_active = 0; - advsm->periodic_sync[0].sch.cb_arg = advsm; - advsm->periodic_sync[0].sch.sched_cb = ble_ll_adv_sync_tx_start_cb; - advsm->periodic_sync[0].sch.sched_type = BLE_LL_SCHED_TYPE_PERIODIC; - advsm->periodic_sync[1].sch.cb_arg = advsm; - advsm->periodic_sync[1].sch.sched_cb = ble_ll_adv_sync_tx_start_cb; - advsm->periodic_sync[1].sch.sched_type = BLE_LL_SCHED_TYPE_PERIODIC; -#endif -#endif - - /* Configure instances to be legacy on start */ - advsm->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE; - advsm->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY; -} - -/** - * Initialize the advertising functionality of a BLE device. This should - * be called once on initialization - */ -void -ble_ll_adv_init(void) -{ - int i; - - /* Set default advertising parameters */ - for (i = 0; i < BLE_ADV_INSTANCES; ++i) { - ble_ll_adv_sm_init(&g_ble_ll_adv_sm[i]); - } -} - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_conn.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_conn.c deleted file mode 100644 index c77e9a8b1..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_conn.c +++ /dev/null @@ -1,4507 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os.h" -#include "nimble/porting/nimble/include/os/os_cputime.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "nimble/nimble/include/nimble/ble_hci_trans.h" - -#if defined(ARDUINO_ARCH_NRF5) && defined(NRF51) -#include "nimble/nimble/drivers/nrf51/include/ble/xcvr.h" -#elif defined(ARDUINO_ARCH_NRF5) && defined(NRF52_SERIES) -#include "nimble/nimble/drivers/nrf52/include/ble/xcvr.h" -#endif - -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_hci.h" -#include "../include/controller/ble_ll_scan.h" -#include "../include/controller/ble_ll_whitelist.h" -#include "../include/controller/ble_ll_sched.h" -#include "../include/controller/ble_ll_ctrl.h" -#include "../include/controller/ble_ll_resolv.h" -#include "../include/controller/ble_ll_adv.h" -#include "../include/controller/ble_ll_trace.h" -#include "../include/controller/ble_ll_rfmgmt.h" -#include "../include/controller/ble_phy.h" -#include "../include/controller/ble_hw.h" -#include "../include/controller/ble_ll_utils.h" -#include "ble_ll_conn_priv.h" - -#if (BLETEST_THROUGHPUT_TEST == 1) -extern void bletest_completed_pkt(uint16_t handle); -#endif - -/* XXX TODO - * 1) I think if we are initiating and we already have a connection with - * a device that we will still try and connect to it. Fix this. - * -> This is true. There are a couple things to do - * i) When a connection create is issued, if we already are connected - * deny it. BLE ERROR = 0x0B (ACL connection exists). - * ii) If we receive an advertisement while initiating and want to send - * a connect request to the device, make sure we dont have it. - * iii) I think I need to do something like this: I am initiating and - * advertising. Suppose the device I want to connect to sends me a connect - * request because I am advertising? What happens to connection? Deal - * with this! - * - * 2) Make sure we check incoming data packets for size and all that. You - * know, supported octets and all that. For both rx and tx. - * - * 3) Make sure we are setting the schedule end time properly for both slave - * and master. We should just set this to the end of the connection event. - * We might want to guarantee a IFS time as well since the next event needs - * to be scheduled prior to the start of the event to account for the time it - * takes to get a frame ready (which is pretty much the IFS time). - * - * 4) looks like the current code will allow the 1st packet in a - * connection to extend past the end of the allocated connection end - * time. That is not good. Need to deal with that. Need to extend connection - * end time. - * - * 6) Use error code 0x3E correctly! Connection failed to establish. If you - * read the LE connection complete event, it says that if the connection - * fails to be established that the connection complete event gets sent to - * the host that issued the create connection. Need to resolve this. - * - * 7) How does peer address get set if we are using whitelist? Look at filter - * policy and make sure you are doing this correctly. - * - * 8) Right now I use a fixed definition for required slots. CHange this. - * - * 10) See what connection state machine elements are purely master and - * purely slave. We can make a union of them. - * - * 11) Not sure I am dealing with the connection terminate timeout perfectly. - * I may extend a connection event too long although if it is always in terms - * of connection events I am probably fine. Checking at end that the next - * connection event will occur past terminate timeould would be fine. - * - * 12) When a slave receives a data packet in a connection it has to send a - * response. Well, it should. If this packet will overrun the next scheduled - * event, what should we do? Transmit anyway? Not transmit? For now, we just - * transmit. - * - * 32kHz crystal - * 1) When scheduling, I need to make sure I have time between - * this one and the next. Should I deal with this in the sched. Or - * is this basically accounted for given a slot? I really just need to - * make sure everything is over N ticks before the next sched start! - * Just add to end time? - * - * 2) I think one way to handle the problem of losing up to a microsecond - * every time we call ble_ll_conn_next_event in a loop is to do everything by - * keeping track of last anchor point. Would need last anchor usecs too. I guess - * we could also keep last anchor usecs as a uint32 or something and when we - * do the next event keep track of the residual using a different ticks to - * usecs calculation. Not sure. - */ - -/* - * XXX: How should we deal with a late connection event? We need to determine - * what we want to do under the following cases: - * 1) The current connection event has not ended but a schedule item starts - */ - -/* This is a dummy structure we use for the empty PDU */ -struct ble_ll_empty_pdu -{ - struct os_mbuf om; - struct os_mbuf_pkthdr pkt_hdr; - struct ble_mbuf_hdr ble_hdr; -}; - -/* We cannot have more than 254 connections given our current implementation */ -#if (MYNEWT_VAL(BLE_MAX_CONNECTIONS) >= 255) - #error "Maximum # of connections is 254" -#endif - -/* Global connection complete event. Used when initiating */ -uint8_t *g_ble_ll_conn_comp_ev; - -/* Global LL connection parameters */ -struct ble_ll_conn_global_params g_ble_ll_conn_params; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -/* Global default sync transfer params */ -struct ble_ll_conn_sync_transfer_params g_ble_ll_conn_sync_transfer_params; -#endif - -/* Pointer to connection state machine we are trying to create */ -struct ble_ll_conn_sm *g_ble_ll_conn_create_sm; - -/* Pointer to current connection */ -struct ble_ll_conn_sm *g_ble_ll_conn_cur_sm; - -/* Connection state machine array */ -struct ble_ll_conn_sm g_ble_ll_conn_sm[MYNEWT_VAL(BLE_MAX_CONNECTIONS)]; - -/* List of active connections */ -struct ble_ll_conn_active_list g_ble_ll_conn_active_list; - -/* List of free connections */ -struct ble_ll_conn_free_list g_ble_ll_conn_free_list; - -STATS_SECT_START(ble_ll_conn_stats) - STATS_SECT_ENTRY(cant_set_sched) - STATS_SECT_ENTRY(conn_ev_late) - STATS_SECT_ENTRY(wfr_expirations) - STATS_SECT_ENTRY(handle_not_found) - STATS_SECT_ENTRY(no_conn_sm) - STATS_SECT_ENTRY(no_free_conn_sm) - STATS_SECT_ENTRY(rx_data_pdu_no_conn) - STATS_SECT_ENTRY(rx_data_pdu_bad_aa) - STATS_SECT_ENTRY(slave_rxd_bad_conn_req_params) - STATS_SECT_ENTRY(slave_ce_failures) - STATS_SECT_ENTRY(data_pdu_rx_dup) - STATS_SECT_ENTRY(data_pdu_txg) - STATS_SECT_ENTRY(data_pdu_txf) - STATS_SECT_ENTRY(conn_req_txd) - STATS_SECT_ENTRY(l2cap_enqueued) - STATS_SECT_ENTRY(rx_ctrl_pdus) - STATS_SECT_ENTRY(rx_l2cap_pdus) - STATS_SECT_ENTRY(rx_l2cap_bytes) - STATS_SECT_ENTRY(rx_malformed_ctrl_pdus) - STATS_SECT_ENTRY(rx_bad_llid) - STATS_SECT_ENTRY(tx_ctrl_pdus) - STATS_SECT_ENTRY(tx_ctrl_bytes) - STATS_SECT_ENTRY(tx_l2cap_pdus) - STATS_SECT_ENTRY(tx_l2cap_bytes) - STATS_SECT_ENTRY(tx_empty_pdus) - STATS_SECT_ENTRY(mic_failures) - STATS_SECT_ENTRY(sched_start_in_idle) - STATS_SECT_ENTRY(sched_end_in_idle) - STATS_SECT_ENTRY(conn_event_while_tmo) -STATS_SECT_END -STATS_SECT_DECL(ble_ll_conn_stats) ble_ll_conn_stats; - -STATS_NAME_START(ble_ll_conn_stats) - STATS_NAME(ble_ll_conn_stats, cant_set_sched) - STATS_NAME(ble_ll_conn_stats, conn_ev_late) - STATS_NAME(ble_ll_conn_stats, wfr_expirations) - STATS_NAME(ble_ll_conn_stats, handle_not_found) - STATS_NAME(ble_ll_conn_stats, no_conn_sm) - STATS_NAME(ble_ll_conn_stats, no_free_conn_sm) - STATS_NAME(ble_ll_conn_stats, rx_data_pdu_no_conn) - STATS_NAME(ble_ll_conn_stats, rx_data_pdu_bad_aa) - STATS_NAME(ble_ll_conn_stats, slave_rxd_bad_conn_req_params) - STATS_NAME(ble_ll_conn_stats, slave_ce_failures) - STATS_NAME(ble_ll_conn_stats, data_pdu_rx_dup) - STATS_NAME(ble_ll_conn_stats, data_pdu_txg) - STATS_NAME(ble_ll_conn_stats, data_pdu_txf) - STATS_NAME(ble_ll_conn_stats, conn_req_txd) - STATS_NAME(ble_ll_conn_stats, l2cap_enqueued) - STATS_NAME(ble_ll_conn_stats, rx_ctrl_pdus) - STATS_NAME(ble_ll_conn_stats, rx_l2cap_pdus) - STATS_NAME(ble_ll_conn_stats, rx_l2cap_bytes) - STATS_NAME(ble_ll_conn_stats, rx_malformed_ctrl_pdus) - STATS_NAME(ble_ll_conn_stats, rx_bad_llid) - STATS_NAME(ble_ll_conn_stats, tx_ctrl_pdus) - STATS_NAME(ble_ll_conn_stats, tx_ctrl_bytes) - STATS_NAME(ble_ll_conn_stats, tx_l2cap_pdus) - STATS_NAME(ble_ll_conn_stats, tx_l2cap_bytes) - STATS_NAME(ble_ll_conn_stats, tx_empty_pdus) - STATS_NAME(ble_ll_conn_stats, mic_failures) - STATS_NAME(ble_ll_conn_stats, sched_start_in_idle) - STATS_NAME(ble_ll_conn_stats, sched_end_in_idle) - STATS_NAME(ble_ll_conn_stats, conn_event_while_tmo) -STATS_NAME_END(ble_ll_conn_stats) - -static void ble_ll_conn_event_end(struct ble_npl_event *ev); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) -struct ble_ll_conn_cth_flow { - bool enabled; - uint16_t max_buffers; - uint16_t num_buffers; -}; - -static struct ble_ll_conn_cth_flow g_ble_ll_conn_cth_flow; - -static struct ble_npl_event g_ble_ll_conn_cth_flow_error_ev; - -static bool -ble_ll_conn_cth_flow_is_enabled(void) -{ - return g_ble_ll_conn_cth_flow.enabled; -} - -static bool -ble_ll_conn_cth_flow_alloc_credit(struct ble_ll_conn_sm *connsm) -{ - struct ble_ll_conn_cth_flow *cth = &g_ble_ll_conn_cth_flow; - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - - if (!cth->num_buffers) { - OS_EXIT_CRITICAL(sr); - return false; - } - - connsm->cth_flow_pending++; - cth->num_buffers--; - - OS_EXIT_CRITICAL(sr); - - return true; -} - -static void -ble_ll_conn_cth_flow_free_credit(struct ble_ll_conn_sm *connsm, uint16_t credits) -{ - struct ble_ll_conn_cth_flow *cth = &g_ble_ll_conn_cth_flow; - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - - /* - * It's not quite clear what we should do if host gives back more credits - * that we have allocated. For now let's just set invalid values back to - * sane values and continue. - */ - - cth->num_buffers += credits; - if (cth->num_buffers > cth->max_buffers) { - cth->num_buffers = cth->max_buffers; - } - - if (connsm->cth_flow_pending < credits) { - connsm->cth_flow_pending = 0; - } else { - connsm->cth_flow_pending -= credits; - } - - OS_EXIT_CRITICAL(sr); -} - -static void -ble_ll_conn_cth_flow_error_fn(struct ble_npl_event *ev) -{ - struct ble_hci_ev *hci_ev; - struct ble_hci_ev_command_complete *hci_ev_cp; - uint16_t opcode; - - hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (!hci_ev) { - /* Not much we can do anyway... */ - return; - } - - /* - * We are here in case length of HCI_Host_Number_Of_Completed_Packets was - * invalid. We will send an error back to host and we can only hope host is - * reasonable and will do some actions to recover, e.g. it should disconnect - * all connections to guarantee that all credits are back in pool and we're - * back in sync (although spec does not really say what should happen). - */ - - opcode = BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, - BLE_HCI_OCF_CB_HOST_NUM_COMP_PKTS); - - hci_ev->opcode = BLE_HCI_EVCODE_COMMAND_COMPLETE; - hci_ev->length = sizeof(*hci_ev_cp); - - hci_ev_cp = (void *)hci_ev->data; - hci_ev_cp->num_packets = BLE_LL_CFG_NUM_HCI_CMD_PKTS; - hci_ev_cp->opcode = htole16(opcode); - hci_ev_cp->status = BLE_ERR_INV_HCI_CMD_PARMS; - - ble_ll_hci_event_send(hci_ev); -} - -void -ble_ll_conn_cth_flow_set_buffers(uint16_t num_buffers) -{ - BLE_LL_ASSERT(num_buffers); - - g_ble_ll_conn_cth_flow.max_buffers = num_buffers; - g_ble_ll_conn_cth_flow.num_buffers = num_buffers; -} - -bool -ble_ll_conn_cth_flow_enable(bool enabled) -{ - struct ble_ll_conn_cth_flow *cth = &g_ble_ll_conn_cth_flow; - - if (cth->enabled == enabled) { - return true; - } - - if (!SLIST_EMPTY(&g_ble_ll_conn_active_list)) { - return false; - } - - cth->enabled = enabled; - - return true; -} - -void -ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf) -{ - const struct ble_hci_cmd *cmd; - const struct ble_hci_cb_host_num_comp_pkts_cp *cp; - struct ble_ll_conn_sm *connsm; - int i; - - cmd = (const void *)cmdbuf; - cp = (const void *)cmd->data; - - if (cmd->length != sizeof(cp->handles) + cp->handles * sizeof(cp->h[0])) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_conn_cth_flow_error_ev); - return; - } - - for (i = 0; i < cp->handles; i++) { - /* - * It's probably ok that we do not have active connection with given - * handle - this can happen if disconnection already happened in LL but - * host sent credits back before processing disconnection event. In such - * case we can simply ignore command for that connection since credits - * are returned by LL already. - */ - connsm = ble_ll_conn_find_active_conn(cp->h[i].handle); - if (connsm) { - ble_ll_conn_cth_flow_free_credit(connsm, cp->h[i].count); - } - } -} -#endif - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) -/** - * Checks to see if we should start a PHY update procedure - * - * If current phy is not one of the preferred we need to start control - * procedure. - * - * XXX: we could also decide to change the PHY if RSSI is really good - * and we are currently at 1Mbps or lower data rate and we could use - * a higher data rate. - * - * @param connsm - * @return 0: success; -1: no phy update procedure started - */ -int -ble_ll_conn_chk_phy_upd_start(struct ble_ll_conn_sm *csm) -{ - int rc; - - /* If no host preferences or */ - if (((csm->phy_data.host_pref_tx_phys_mask == 0) && - (csm->phy_data.host_pref_rx_phys_mask == 0)) || - ((csm->phy_data.host_pref_tx_phys_mask & CONN_CUR_TX_PHY_MASK(csm)) && - (csm->phy_data.host_pref_rx_phys_mask & CONN_CUR_RX_PHY_MASK(csm)))) { - rc = -1; - } else { - csm->phy_data.req_pref_tx_phys_mask = csm->phy_data.host_pref_tx_phys_mask; - csm->phy_data.req_pref_rx_phys_mask = csm->phy_data.host_pref_rx_phys_mask; - ble_ll_ctrl_proc_start(csm, BLE_LL_CTRL_PROC_PHY_UPDATE); - rc = 0; - } - - return rc; -} -#endif - -static void -ble_ll_conn_calc_itvl_ticks(struct ble_ll_conn_sm *connsm) -{ - uint32_t ticks; - uint32_t usecs; - - /* - * Precalculate the number of ticks and remaining microseconds for - * the connection interval - */ - usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS; - ticks = os_cputime_usecs_to_ticks(usecs); - connsm->conn_itvl_usecs = (uint8_t)(usecs - - os_cputime_ticks_to_usecs(ticks)); - if (connsm->conn_itvl_usecs == 31) { - connsm->conn_itvl_usecs = 0; - ++ticks; - } - connsm->conn_itvl_ticks = ticks; -} - -/** - * Get the event buffer allocated to send the connection complete event - * when we are initiating. - * - * @return uint8_t* - */ -static uint8_t * -ble_ll_init_get_conn_comp_ev(void) -{ - uint8_t *evbuf; - - evbuf = g_ble_ll_conn_comp_ev; - BLE_LL_ASSERT(evbuf != NULL); - g_ble_ll_conn_comp_ev = NULL; - - return evbuf; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/** - * Called to determine if the received PDU is an empty PDU or not. - */ -static int -ble_ll_conn_is_empty_pdu(uint8_t *rxbuf) -{ - int rc; - uint8_t llid; - - llid = rxbuf[0] & BLE_LL_DATA_HDR_LLID_MASK; - if ((llid == BLE_LL_LLID_DATA_FRAG) && (rxbuf[1] == 0)) { - rc = 1; - } else { - rc = 0; - } - return rc; -} -#endif - -/** - * Called to return the currently running connection state machine end time. - * Always called when interrupts are disabled. - * - * @return int 0: s1 is not least recently used. 1: s1 is least recently used - */ -int -ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2) -{ - int rc; - - /* Set time that we last serviced the schedule */ - if (CPUTIME_LT(s1->last_scheduled, s2->last_scheduled)) { - rc = 1; - } else { - rc = 0; - } - - return rc; -} - -/** - * Called to return the currently running connection state machine end time. - * Always called when interrupts are disabled. - * - * @return uint32_t - */ -uint32_t -ble_ll_conn_get_ce_end_time(void) -{ - uint32_t ce_end_time; - - if (g_ble_ll_conn_cur_sm) { - ce_end_time = g_ble_ll_conn_cur_sm->ce_end_time; - } else { - ce_end_time = os_cputime_get32(); - } - return ce_end_time; -} - -/** - * Called when connection state machine needs to halt. This function will: - * -> Disable the PHY, which will prevent any transmit/receive interrupts. - * -> Disable the wait for response timer, if running. - * -> Remove the connection state machine from the scheduler. - * -> Sets the Link Layer state to standby. - * -> Sets the current state machine to NULL. - * - * NOTE: the ordering of these function calls is important! We have to stop - * the PHY and remove the schedule item before we can set the state to - * standby and set the current state machine pointer to NULL. - */ -static void -ble_ll_conn_halt(void) -{ - ble_phy_disable(); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - g_ble_ll_conn_cur_sm = NULL; -} - -/** - * Called when the current connection state machine is no longer being used. - */ -static void -ble_ll_conn_current_sm_over(struct ble_ll_conn_sm *connsm) -{ - - ble_ll_conn_halt(); - - /* - * NOTE: the connection state machine may be NULL if we are calling - * this when we are ending the connection. In that case, there is no - * need to post to the LL the connection event end event - */ - if (connsm) { - ble_ll_event_send(&connsm->conn_ev_end); - } -} - -/** - * Given a handle, find an active connection matching the handle - * - * @param handle - * - * @return struct ble_ll_conn_sm* - */ -struct ble_ll_conn_sm * -ble_ll_conn_find_active_conn(uint16_t handle) -{ - struct ble_ll_conn_sm *connsm; - - connsm = NULL; - if ((handle != 0) && (handle <= MYNEWT_VAL(BLE_MAX_CONNECTIONS))) { - connsm = &g_ble_ll_conn_sm[handle - 1]; - if (connsm->conn_state == BLE_LL_CONN_STATE_IDLE) { - connsm = NULL; - } - } - return connsm; -} - -/** - * Get a connection state machine. - */ -struct ble_ll_conn_sm * -ble_ll_conn_sm_get(void) -{ - struct ble_ll_conn_sm *connsm; - - connsm = STAILQ_FIRST(&g_ble_ll_conn_free_list); - if (connsm) { - STAILQ_REMOVE_HEAD(&g_ble_ll_conn_free_list, free_stqe); - } else { - STATS_INC(ble_ll_conn_stats, no_free_conn_sm); - } - - return connsm; -} - -static uint8_t -ble_ll_conn_calc_dci_csa1(struct ble_ll_conn_sm *conn) -{ - uint8_t curchan; - uint8_t remap_index; - uint8_t bitpos; - - /* Get next unmapped channel */ - curchan = conn->last_unmapped_chan + conn->hop_inc; - if (curchan > BLE_PHY_NUM_DATA_CHANS) { - curchan -= BLE_PHY_NUM_DATA_CHANS; - } - - /* Save unmapped channel */ - conn->last_unmapped_chan = curchan; - - /* Is this a valid channel? */ - bitpos = 1 << (curchan & 0x07); - if (conn->chanmap[curchan >> 3] & bitpos) { - return curchan; - } - - /* Calculate remap index */ - remap_index = curchan % conn->num_used_chans; - - return ble_ll_utils_remapped_channel(remap_index, conn->chanmap); -} - -/** - * Determine data channel index to be used for the upcoming/current - * connection event - * - * @param conn - * @param latency Used only for CSA #1 - * - * @return uint8_t - */ -uint8_t -ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn, uint16_t latency) -{ - uint8_t index; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - if (CONN_F_CSA2_SUPP(conn)) { - return ble_ll_utils_calc_dci_csa2(conn->event_cntr, conn->channel_id, - conn->num_used_chans, conn->chanmap); - } -#endif - - index = conn->data_chan_index; - - while (latency > 0) { - index = ble_ll_conn_calc_dci_csa1(conn); - latency--; - } - - return index; -} - -/** - * Called when we are in the connection state and the wait for response timer - * fires off. - * - * Context: Interrupt - */ -void -ble_ll_conn_wfr_timer_exp(void) -{ - struct ble_ll_conn_sm *connsm; - - connsm = g_ble_ll_conn_cur_sm; - ble_ll_conn_current_sm_over(connsm); - STATS_INC(ble_ll_conn_stats, wfr_expirations); -} - -void -ble_ll_conn_reset_pending_aux_conn_rsp(void) -{ -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - return; -#endif - struct ble_ll_conn_sm *connsm; - - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return; - } - - if (CONN_F_AUX_CONN_REQ(connsm)) { - STATS_INC(ble_ll_stats, aux_conn_rsp_err); - CONN_F_CONN_REQ_TXD(connsm) = 0; - CONN_F_AUX_CONN_REQ(connsm) = 0; - ble_ll_sched_rmv_elem(&connsm->conn_sch); - return; - } - - return; -} - -bool -ble_ll_conn_init_pending_aux_conn_rsp(void) -{ -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - return false; -#endif - struct ble_ll_conn_sm *connsm; - - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return false; - } - - return CONN_F_AUX_CONN_REQ(connsm); -} - -void -ble_ll_conn_init_wfr_timer_exp(void) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_conn_sm *connsm; - - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return; - } - - ble_ll_conn_reset_pending_aux_conn_rsp(); - connsm->inita_identity_used = 0; - - ble_ll_scan_interrupted(connsm->scansm); - -#endif -} -/** - * Callback for slave when it transmits a data pdu and the connection event - * ends after the transmission. - * - * Context: Interrupt - * - * @param sch - * - */ -static void -ble_ll_conn_wait_txend(void *arg) -{ - struct ble_ll_conn_sm *connsm; - - connsm = (struct ble_ll_conn_sm *)arg; - ble_ll_conn_current_sm_over(connsm); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -static void -ble_ll_conn_start_rx_encrypt(void *arg) -{ - struct ble_ll_conn_sm *connsm; - - connsm = (struct ble_ll_conn_sm *)arg; - CONN_F_ENCRYPTED(connsm) = 1; - ble_phy_encrypt_enable(connsm->enc_data.rx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - !CONN_IS_MASTER(connsm)); -} - -static void -ble_ll_conn_start_rx_unencrypt(void *arg) -{ - struct ble_ll_conn_sm *connsm; - - connsm = (struct ble_ll_conn_sm *)arg; - CONN_F_ENCRYPTED(connsm) = 0; - ble_phy_encrypt_disable(); -} - -static void -ble_ll_conn_txend_encrypt(void *arg) -{ - struct ble_ll_conn_sm *connsm; - - connsm = (struct ble_ll_conn_sm *)arg; - CONN_F_ENCRYPTED(connsm) = 1; - ble_ll_conn_current_sm_over(connsm); -} - -static void -ble_ll_conn_rxend_unencrypt(void *arg) -{ - struct ble_ll_conn_sm *connsm; - - connsm = (struct ble_ll_conn_sm *)arg; - CONN_F_ENCRYPTED(connsm) = 0; - ble_ll_conn_current_sm_over(connsm); -} - -static void -ble_ll_conn_continue_rx_encrypt(void *arg) -{ - struct ble_ll_conn_sm *connsm; - - connsm = (struct ble_ll_conn_sm *)arg; - ble_phy_encrypt_set_pkt_cntr(connsm->enc_data.rx_pkt_cntr, - !CONN_IS_MASTER(connsm)); -} -#endif - -/** - * Returns the cputime of the next scheduled item on the scheduler list or - * when the current connection will start its next interval (whichever is - * earlier). This API is called when determining at what time we should end - * the current connection event. The current connection event must end before - * the next scheduled item. However, the current connection itself is not - * in the scheduler list! Thus, we need to calculate the time at which the - * next connection will start (the schedule start time; not the anchor point) - * and not overrun it. - * - * Context: Interrupt - * - * @param connsm - * - * @return uint32_t - */ -static uint32_t -ble_ll_conn_get_next_sched_time(struct ble_ll_conn_sm *connsm) -{ -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) - uint32_t ce_end; - ce_end = connsm->ce_end_time; -#else - uint32_t ce_end; - uint32_t next_sched_time; - - /* Calculate time at which next connection event will start */ - /* NOTE: We dont care if this time is tick short. */ - ce_end = connsm->anchor_point + connsm->conn_itvl_ticks - - g_ble_ll_sched_offset_ticks; - if ((connsm->anchor_point_usecs + connsm->conn_itvl_usecs) >= 31) { - ++ce_end; - } - - if (ble_ll_sched_next_time(&next_sched_time)) { - if (CPUTIME_LT(next_sched_time, ce_end)) { - ce_end = next_sched_time; - } - } -#endif - - return ce_end; -} - -/** - * Called to check if certain connection state machine flags have been - * set. - * - * @param connsm - */ -static void -ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm) -{ - uint8_t update_status; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (connsm->csmflags.cfbit.send_ltk_req) { - /* - * Send Long term key request event to host. If masked, we need to - * send a REJECT_IND. - */ - if (ble_ll_hci_ev_ltk_req(connsm)) { - ble_ll_ctrl_reject_ind_send(connsm, BLE_LL_CTRL_ENC_REQ, - BLE_ERR_PINKEY_MISSING); - } - connsm->csmflags.cfbit.send_ltk_req = 0; - } -#endif - - /* - * There are two cases where this flag gets set: - * 1) A connection update procedure was started and the event counter - * has passed the instant. - * 2) We successfully sent the reject reason. - */ - if (connsm->csmflags.cfbit.host_expects_upd_event) { - update_status = BLE_ERR_SUCCESS; - if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) { - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE); - } else { - if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) { - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ); - update_status = connsm->reject_reason; - } - } - ble_ll_hci_ev_conn_update(connsm, update_status); - connsm->csmflags.cfbit.host_expects_upd_event = 0; - } - - /* Check if we need to send PHY update complete event */ -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - if (CONN_F_PHY_UPDATE_EVENT(connsm)) { - if (!ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS)) { - /* Sent event. Clear flag */ - CONN_F_PHY_UPDATE_EVENT(connsm) = 0; - } - } -#endif -} - -/** - * Called when we want to send a data channel pdu inside a connection event. - * - * Context: interrupt - * - * @param connsm - * - * @return int 0: success; otherwise failure to transmit - */ -static uint16_t -ble_ll_conn_adjust_pyld_len(struct ble_ll_conn_sm *connsm, uint16_t pyld_len) -{ - uint16_t phy_max_tx_octets; - uint16_t ret; - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - uint8_t phy_mode; - - if (connsm->phy_tx_transition) { - phy_mode = ble_ll_phy_to_phy_mode(connsm->phy_tx_transition, - connsm->phy_data.phy_options); - } else { - phy_mode = connsm->phy_data.tx_phy_mode; - } - - phy_max_tx_octets = ble_ll_pdu_max_tx_octets_get(connsm->eff_max_tx_time, - phy_mode); - -#else - phy_max_tx_octets = ble_ll_pdu_max_tx_octets_get(connsm->eff_max_tx_time, - BLE_PHY_MODE_1M); -#endif - - ret = pyld_len; - - if (ret > connsm->eff_max_tx_octets) { - ret = connsm->eff_max_tx_octets; - } - - if (ret > phy_max_tx_octets) { - ret = phy_max_tx_octets; - } - - return ret; -} - -static int -ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) -{ - int rc; - uint8_t md; - uint8_t hdr_byte; - uint8_t end_transition; - uint8_t cur_txlen; - uint8_t next_txlen; - uint8_t cur_offset; - uint16_t pktlen; - uint32_t next_event_time; - uint32_t ticks; - struct os_mbuf *m; - struct ble_mbuf_hdr *ble_hdr; - struct os_mbuf_pkthdr *pkthdr = NULL; - struct os_mbuf_pkthdr *nextpkthdr; - struct ble_ll_empty_pdu empty_pdu; - ble_phy_tx_end_func txend_func; - int tx_phy_mode; - uint8_t llid; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - int is_ctrl; - uint8_t opcode; -#endif - - /* For compiler warnings... */ - ble_hdr = NULL; - m = NULL; - md = 0; - hdr_byte = BLE_LL_LLID_DATA_FRAG; - - if (connsm->csmflags.cfbit.terminate_ind_rxd) { - /* We just received terminate indication. - * Just send empty packet as an ACK - */ - CONN_F_EMPTY_PDU_TXD(connsm) = 1; - goto conn_tx_pdu; - } - - /* - * We need to check if we are retrying a pdu or if there is a pdu on - * the transmit queue. - */ - pkthdr = STAILQ_FIRST(&connsm->conn_txq); - if (!connsm->cur_tx_pdu && !CONN_F_EMPTY_PDU_TXD(connsm) && !pkthdr) { - CONN_F_EMPTY_PDU_TXD(connsm) = 1; - goto conn_tx_pdu; - } - - /* - * If we dont have a pdu we have previously transmitted, take it off - * the connection transmit queue - */ - cur_offset = 0; - if (!connsm->cur_tx_pdu && !CONN_F_EMPTY_PDU_TXD(connsm)) { - /* Convert packet header to mbuf */ - m = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); - nextpkthdr = STAILQ_NEXT(pkthdr, omp_next); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - /* - * If we are encrypting, we are only allowed to send certain - * kinds of LL control PDU's. If none is enqueued, send empty pdu! - * - * In Slave role, we are allowed to send unencrypted packets until - * LL_ENC_RSP is sent. - */ - if (((connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) && - CONN_IS_MASTER(connsm)) || - ((connsm->enc_data.enc_state > CONN_ENC_S_ENC_RSP_TO_BE_SENT) && - CONN_IS_SLAVE(connsm))) { - if (!ble_ll_ctrl_enc_allowed_pdu_tx(pkthdr)) { - CONN_F_EMPTY_PDU_TXD(connsm) = 1; - goto conn_tx_pdu; - } - - /* - * We will allow a next packet if it itself is allowed or we are - * a slave and we are sending the START_ENC_RSP. The master has - * to wait to receive the START_ENC_RSP from the slave before - * packets can be let go. - */ - if (nextpkthdr && !ble_ll_ctrl_enc_allowed_pdu_tx(nextpkthdr) - && ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) || - !ble_ll_ctrl_is_start_enc_rsp(m))) { - nextpkthdr = NULL; - } - } -#endif - /* Take packet off queue*/ - STAILQ_REMOVE_HEAD(&connsm->conn_txq, omp_next); - ble_hdr = BLE_MBUF_HDR_PTR(m); - - /* - * We dequeued new packet for transmission. - * If this is a data PDU we need to calculate payload length we can send - * over current PHY. Effectively, this determines fragmentation of packet - * into PDUs. - * If this is a control PDU we send complete PDU as only data PDU can be - * fragmented. We assume that checks (i.e. if remote supports such PDU) - * were already performed before putting packet on queue. - */ - llid = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK; - pktlen = pkthdr->omp_len; - if (llid == BLE_LL_LLID_CTRL) { - cur_txlen = pktlen; - } else { - cur_txlen = ble_ll_conn_adjust_pyld_len(connsm, pktlen); - } - ble_hdr->txinfo.pyld_len = cur_txlen; - - /* NOTE: header was set when first enqueued */ - hdr_byte = ble_hdr->txinfo.hdr_byte; - connsm->cur_tx_pdu = m; - } else { - nextpkthdr = pkthdr; - if (connsm->cur_tx_pdu) { - m = connsm->cur_tx_pdu; - ble_hdr = BLE_MBUF_HDR_PTR(m); - pktlen = OS_MBUF_PKTLEN(m); - cur_txlen = ble_hdr->txinfo.pyld_len; - cur_offset = ble_hdr->txinfo.offset; - if (cur_offset == 0) { - hdr_byte = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK; - } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) { - /* We will allow a next packet if it itself is allowed */ - pkthdr = OS_MBUF_PKTHDR(connsm->cur_tx_pdu); - if (nextpkthdr && !ble_ll_ctrl_enc_allowed_pdu_tx(nextpkthdr) - && ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) || - !ble_ll_ctrl_is_start_enc_rsp(connsm->cur_tx_pdu))) { - nextpkthdr = NULL; - } - } -#endif - } else { - /* Empty PDU here. NOTE: header byte gets set later */ - pktlen = 0; - cur_txlen = 0; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) { - /* We will allow a next packet if it itself is allowed */ - if (nextpkthdr && !ble_ll_ctrl_enc_allowed_pdu_tx(nextpkthdr)) { - nextpkthdr = NULL; - } - } -#endif - } - } - - /* - * Set the more data data flag if we have more data to send and we - * have not been asked to terminate - */ - if (nextpkthdr || ((cur_offset + cur_txlen) < pktlen)) { - /* Get next event time */ - next_event_time = ble_ll_conn_get_next_sched_time(connsm); - - /* XXX: TODO: need to check this with phy update procedure. There are - limitations if we have started update */ - - /* - * Dont bother to set the MD bit if we cannot do the following: - * -> wait IFS, send the current frame. - * -> wait IFS, receive a maximum size frame. - * -> wait IFS, send the next frame. - * -> wait IFS, receive a maximum size frame. - * - * For slave: - * -> wait IFS, send current frame. - * -> wait IFS, receive maximum size frame. - * -> wait IFS, send next frame. - */ - if ((cur_offset + cur_txlen) < pktlen) { - next_txlen = pktlen - (cur_offset + cur_txlen); - } else { - if (nextpkthdr->omp_len > connsm->eff_max_tx_octets) { - next_txlen = connsm->eff_max_tx_octets; - } else { - next_txlen = nextpkthdr->omp_len; - } - } - - /* - * XXX: this calculation is based on using the current time - * and assuming the transmission will occur an IFS time from - * now. This is not the most accurate especially if we have - * received a frame and we are replying to it. - */ -#if BLE_LL_BT5_PHY_SUPPORTED - tx_phy_mode = connsm->phy_data.tx_phy_mode; -#else - tx_phy_mode = BLE_PHY_MODE_1M; -#endif - - ticks = (BLE_LL_IFS * 3) + connsm->eff_max_rx_time + - ble_ll_pdu_tx_time_get(next_txlen, tx_phy_mode) + - ble_ll_pdu_tx_time_get(cur_txlen, tx_phy_mode); - - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - ticks += (BLE_LL_IFS + connsm->eff_max_rx_time); - } - - ticks = os_cputime_usecs_to_ticks(ticks); - if (CPUTIME_LT(os_cputime_get32() + ticks, next_event_time)) { - md = 1; - } - } - - /* If we send an empty PDU we need to initialize the header */ -conn_tx_pdu: - if (CONN_F_EMPTY_PDU_TXD(connsm)) { - /* - * This looks strange, but we dont use the data pointer in the mbuf - * when we have an empty pdu. - */ - m = (struct os_mbuf *)&empty_pdu; - m->om_data = (uint8_t *)&empty_pdu; - m->om_data += BLE_MBUF_MEMBLOCK_OVERHEAD; - ble_hdr = &empty_pdu.ble_hdr; - ble_hdr->txinfo.flags = 0; - ble_hdr->txinfo.offset = 0; - ble_hdr->txinfo.pyld_len = 0; - } - - /* Set tx seqnum */ - if (connsm->tx_seqnum) { - hdr_byte |= BLE_LL_DATA_HDR_SN_MASK; - } - - /* If we have more data, set the bit */ - if (md) { - hdr_byte |= BLE_LL_DATA_HDR_MD_MASK; - } - - /* Set NESN (next expected sequence number) bit */ - if (connsm->next_exp_seqnum) { - hdr_byte |= BLE_LL_DATA_HDR_NESN_MASK; - } - - /* Set the header byte in the outgoing frame */ - ble_hdr->txinfo.hdr_byte = hdr_byte; - - /* - * If we are a slave, check to see if this transmission will end the - * connection event. We will end the connection event if we have - * received a valid frame with the more data bit set to 0 and we dont - * have more data. - * - * XXX: for a slave, we dont check to see if we can: - * -> wait IFS, rx frame from master (either big or small). - * -> wait IFS, send empty pdu or next pdu. - * - * We could do this. Now, we just keep going and hope that we dont - * overrun next scheduled item. - */ - if ((connsm->csmflags.cfbit.terminate_ind_rxd) || - ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && (md == 0) && - (connsm->cons_rxd_bad_crc == 0) && - ((connsm->last_rxd_hdr_byte & BLE_LL_DATA_HDR_MD_MASK) == 0) && - !ble_ll_ctrl_is_terminate_ind(hdr_byte, m->om_data[0]))) { - /* We will end the connection event */ - end_transition = BLE_PHY_TRANSITION_NONE; - txend_func = ble_ll_conn_wait_txend; - } else { - /* Wait for a response here */ - end_transition = BLE_PHY_TRANSITION_TX_RX; - txend_func = NULL; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - llid = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK; - if (llid == BLE_LL_LLID_CTRL) { - is_ctrl = 1; - opcode = m->om_data[0]; - } else { - is_ctrl = 0; - opcode = 0; - } - - if (is_ctrl && (opcode == BLE_LL_CTRL_START_ENC_RSP)) { - /* - * Both master and slave send the START_ENC_RSP encrypted and receive - * encrypted - */ - CONN_F_ENCRYPTED(connsm) = 1; - connsm->enc_data.tx_encrypted = 1; - ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - CONN_IS_MASTER(connsm)); - } else if (is_ctrl && (opcode == BLE_LL_CTRL_START_ENC_REQ)) { - /* - * Only the slave sends this and it gets sent unencrypted but - * we receive encrypted - */ - CONN_F_ENCRYPTED(connsm) = 0; - connsm->enc_data.enc_state = CONN_ENC_S_START_ENC_RSP_WAIT; - connsm->enc_data.tx_encrypted = 0; - ble_phy_encrypt_disable(); - if (txend_func == NULL) { - txend_func = ble_ll_conn_start_rx_encrypt; - } else { - txend_func = ble_ll_conn_txend_encrypt; - } - } else if (is_ctrl && (opcode == BLE_LL_CTRL_PAUSE_ENC_RSP)) { - /* - * The slave sends the PAUSE_ENC_RSP encrypted. The master sends - * it unencrypted (note that link was already set unencrypted). - */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - CONN_F_ENCRYPTED(connsm) = 1; - connsm->enc_data.tx_encrypted = 1; - ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - CONN_IS_MASTER(connsm)); - if (txend_func == NULL) { - txend_func = ble_ll_conn_start_rx_unencrypt; - } else { - txend_func = ble_ll_conn_rxend_unencrypt; - } - } else { - CONN_F_ENCRYPTED(connsm) = 0; - connsm->enc_data.enc_state = CONN_ENC_S_PAUSED; - connsm->enc_data.tx_encrypted = 0; - ble_phy_encrypt_disable(); - } - } else { - /* If encrypted set packet counter */ - if (CONN_F_ENCRYPTED(connsm)) { - connsm->enc_data.tx_encrypted = 1; - ble_phy_encrypt_set_pkt_cntr(connsm->enc_data.tx_pkt_cntr, - CONN_IS_MASTER(connsm)); - if (txend_func == NULL) { - txend_func = ble_ll_conn_continue_rx_encrypt; - } - } - } -#endif - - /* Set transmit end callback */ - ble_phy_set_txend_cb(txend_func, connsm); - rc = ble_phy_tx(ble_ll_tx_mbuf_pducb, m, end_transition); - if (!rc) { - /* Log transmit on connection state */ - cur_txlen = ble_hdr->txinfo.pyld_len; - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_CONN_TX, cur_txlen, - ble_hdr->txinfo.offset); - - /* Set last transmitted MD bit */ - CONN_F_LAST_TXD_MD(connsm) = md; - - /* Increment packets transmitted */ - if (CONN_F_EMPTY_PDU_TXD(connsm)) { - if (connsm->csmflags.cfbit.terminate_ind_rxd) { - connsm->csmflags.cfbit.terminate_ind_rxd_acked = 1; - } - STATS_INC(ble_ll_conn_stats, tx_empty_pdus); - } else if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) { - STATS_INC(ble_ll_conn_stats, tx_ctrl_pdus); - STATS_INCN(ble_ll_conn_stats, tx_ctrl_bytes, cur_txlen); - } else { - STATS_INC(ble_ll_conn_stats, tx_l2cap_pdus); - STATS_INCN(ble_ll_conn_stats, tx_l2cap_bytes, cur_txlen); - } - } - return rc; -} - -/** - * Schedule callback for start of connection event. - * - * Context: Interrupt - * - * @param sch - * - * @return int 0: scheduled item is still running. 1: schedule item is done. - */ -static int -ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) -{ - int rc; - uint32_t usecs; - uint32_t start; - struct ble_ll_conn_sm *connsm; - - /* XXX: note that we can extend end time here if we want. Look at this */ - - /* Set current connection state machine */ - connsm = (struct ble_ll_conn_sm *)sch->cb_arg; - g_ble_ll_conn_cur_sm = connsm; - BLE_LL_ASSERT(connsm); - if (connsm->conn_state == BLE_LL_CONN_STATE_IDLE) { - /* That should not happen. If it does it means connection - * is already closed - */ - STATS_INC(ble_ll_conn_stats, sched_start_in_idle); - BLE_LL_ASSERT(0); - ble_ll_conn_current_sm_over(connsm); - return BLE_LL_SCHED_STATE_DONE; - } - - /* Log connection event start */ - ble_ll_trace_u32(BLE_LL_TRACE_ID_CONN_EV_START, connsm->conn_handle); - - /* Disable whitelisting as connections do not use it */ - ble_ll_whitelist_disable(); - - /* Set LL state */ - ble_ll_state_set(BLE_LL_STATE_CONNECTION); - - /* Set channel */ - ble_phy_setchan(connsm->data_chan_index, connsm->access_addr, - connsm->crcinit); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - ble_phy_resolv_list_disable(); -#endif - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_set(connsm->phy_data.tx_phy_mode, connsm->phy_data.rx_phy_mode); -#endif - - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - /* Set start time of transmission */ - start = sch->start_time + g_ble_ll_sched_offset_ticks; - rc = ble_phy_tx_set_start_time(start, sch->remainder); - if (!rc) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (CONN_F_ENCRYPTED(connsm)) { - ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - 1); - } else { - ble_phy_encrypt_disable(); - } -#endif - rc = ble_ll_conn_tx_pdu(connsm); - if (!rc) { - rc = BLE_LL_SCHED_STATE_RUNNING; - } else { - /* Inform LL task of connection event end */ - rc = BLE_LL_SCHED_STATE_DONE; - } - } else { - STATS_INC(ble_ll_conn_stats, conn_ev_late); - rc = BLE_LL_SCHED_STATE_DONE; - } - } else { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (CONN_F_ENCRYPTED(connsm)) { - ble_phy_encrypt_enable(connsm->enc_data.rx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - 1); - } else { - ble_phy_encrypt_disable(); - } -#endif - - /* XXX: what is this really for the slave? */ - start = sch->start_time + g_ble_ll_sched_offset_ticks; - rc = ble_phy_rx_set_start_time(start, sch->remainder); - if (rc) { - /* End the connection event as we have no more buffers */ - STATS_INC(ble_ll_conn_stats, slave_ce_failures); - rc = BLE_LL_SCHED_STATE_DONE; - } else { - /* - * Set flag that tells slave to set last anchor point if a packet - * has been received. - */ - connsm->csmflags.cfbit.slave_set_last_anchor = 1; - - /* - * Set the wait for response time. The anchor point is when we - * expect the master to start transmitting. Worst-case, we expect - * to hear a reply within the anchor point plus: - * -> current tx window size - * -> current window widening amount (includes +/- 16 usec jitter) - * -> Amount of time it takes to detect packet start. - * -> Some extra time (16 usec) to insure timing is OK - */ - - /* - * For the 32 kHz crystal, the amount of usecs we have to wait - * is not from the anchor point; we have to account for the time - * from when the receiver is enabled until the anchor point. The - * time we start before the anchor point is this: - * -> current window widening. - * -> up to one 32 kHz tick since we discard remainder. - * -> Up to one tick since the usecs to ticks calc can be off - * by up to one tick. - * NOTES: - * 1) the 61 we add is for the two ticks mentioned above. - * 2) The address rx time and jitter is accounted for in the - * phy function - */ - usecs = connsm->slave_cur_tx_win_usecs + 61 + - (2 * connsm->slave_cur_window_widening); - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, usecs); - /* Set next wakeup time to connection event end time */ - rc = BLE_LL_SCHED_STATE_RUNNING; - } - } - - if (rc == BLE_LL_SCHED_STATE_DONE) { - ble_ll_event_send(&connsm->conn_ev_end); - ble_phy_disable(); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - g_ble_ll_conn_cur_sm = NULL; - } - - /* Set time that we last serviced the schedule */ - connsm->last_scheduled = os_cputime_get32(); - return rc; -} - -/** - * Called to determine if the device is allowed to send the next pdu in the - * connection event. This will always return 'true' if we are a slave. If we - * are a master, we must be able to send the next fragment and get a minimum - * sized response from the slave. - * - * Context: Interrupt context (rx end isr). - * - * @param connsm - * @param begtime Time at which IFS before pdu transmission starts - * - * @return int 0: not allowed to send 1: allowed to send - */ -static int -ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime, - uint32_t add_usecs) -{ - int rc; - uint8_t rem_bytes; - uint32_t ticks; - uint32_t usecs; - uint32_t next_sched_time; - struct os_mbuf *txpdu; - struct os_mbuf_pkthdr *pkthdr; - struct ble_mbuf_hdr *txhdr; - uint32_t allowed_usecs; - int tx_phy_mode; - -#if BLE_LL_BT5_PHY_SUPPORTED - tx_phy_mode = connsm->phy_data.tx_phy_mode; -#else - tx_phy_mode = BLE_PHY_MODE_1M; -#endif - - rc = 1; - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - /* Get next scheduled item time */ - next_sched_time = ble_ll_conn_get_next_sched_time(connsm); - - txpdu = connsm->cur_tx_pdu; - if (!txpdu) { - pkthdr = STAILQ_FIRST(&connsm->conn_txq); - if (pkthdr) { - txpdu = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); - } - } else { - pkthdr = OS_MBUF_PKTHDR(txpdu); - } - - /* XXX: TODO: need to check this with phy update procedure. There are - limitations if we have started update */ - if (txpdu) { - txhdr = BLE_MBUF_HDR_PTR(txpdu); - rem_bytes = pkthdr->omp_len - txhdr->txinfo.offset; - if (rem_bytes > connsm->eff_max_tx_octets) { - rem_bytes = connsm->eff_max_tx_octets; - } - usecs = ble_ll_pdu_tx_time_get(rem_bytes, tx_phy_mode); - } else { - /* We will send empty pdu (just a LL header) */ - usecs = ble_ll_pdu_tx_time_get(0, tx_phy_mode); - } - usecs += (BLE_LL_IFS * 2) + connsm->eff_max_rx_time; - - ticks = (uint32_t)(next_sched_time - begtime); - allowed_usecs = os_cputime_ticks_to_usecs(ticks); - if ((usecs + add_usecs) >= allowed_usecs) { - rc = 0; - } - } - - return rc; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) -/** - * Callback for the Authenticated payload timer. This function is called - * when the authenticated payload timer expires. When the authenticated - * payload timeout expires, we should - * -> Send the authenticated payload timeout event. - * -> Start the LE ping procedure. - * -> Restart the timer. - * - * @param arg - */ -void -ble_ll_conn_auth_pyld_timer_cb(struct ble_npl_event *ev) -{ - struct ble_ll_conn_sm *connsm; - - connsm = (struct ble_ll_conn_sm *)ble_npl_event_get_arg(ev); - ble_ll_auth_pyld_tmo_event_send(connsm); - ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_LE_PING); - ble_ll_conn_auth_pyld_timer_start(connsm); -} - -void -ble_ll_conn_rd_features_timer_cb(struct ble_npl_event *ev) -{ - struct ble_ll_conn_sm *connsm; - - connsm = (struct ble_ll_conn_sm *)ble_npl_event_get_arg(ev); - - if (!connsm->csmflags.cfbit.pending_hci_rd_features || - !connsm->csmflags.cfbit.rxd_features) { - return; - } - - ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; -} - -/** - * Start (or restart) the authenticated payload timer - * - * @param connsm - */ -void -ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm) -{ - int32_t tmo; - - /* Timeout in is in 10 msec units */ - tmo = (int32_t)BLE_LL_CONN_AUTH_PYLD_OS_TMO(connsm->auth_pyld_tmo); - ble_npl_callout_reset(&connsm->auth_pyld_timer, tmo); -} -#endif - -static void -ble_ll_conn_master_common_init(struct ble_ll_conn_sm *connsm) -{ - - /* Set master role */ - connsm->conn_role = BLE_LL_CONN_ROLE_MASTER; - - /* Set default ce parameters */ - - /* - * XXX: for now, we need twice the transmit window as our calculations - * for the transmit window offset could be off. - */ - connsm->tx_win_size = BLE_LL_CONN_TX_WIN_MIN + 1; - connsm->tx_win_off = 0; - connsm->master_sca = BLE_LL_SCA_ENUM; - - /* Hop increment is a random value between 5 and 16. */ - connsm->hop_inc = (ble_ll_rand() % 12) + 5; - - /* Set channel map to map requested by host */ - connsm->num_used_chans = g_ble_ll_conn_params.num_used_chans; - memcpy(connsm->chanmap, g_ble_ll_conn_params.master_chan_map, - BLE_LL_CONN_CHMAP_LEN); - - /* Calculate random access address and crc initialization value */ - connsm->access_addr = ble_ll_utils_calc_access_addr(); - connsm->crcinit = ble_ll_rand() & 0xffffff; - - /* Set initial schedule callback */ - connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb; -} -/** - * Called when a create connection command has been received. This initializes - * a connection state machine in the master role. - * - * NOTE: Must be called before the state machine is started - * - * @param connsm - * @param hcc - */ -void -ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm, - struct hci_create_conn *hcc) -{ - - ble_ll_conn_master_common_init(connsm); - - /* Set slave latency and supervision timeout */ - connsm->slave_latency = hcc->conn_latency; - connsm->supervision_tmo = hcc->supervision_timeout; - - /* Set own address type and peer address if needed */ - connsm->own_addr_type = hcc->own_addr_type; - if (hcc->filter_policy == 0) { - memcpy(&connsm->peer_addr, &hcc->peer_addr, BLE_DEV_ADDR_LEN); - connsm->peer_addr_type = hcc->peer_addr_type; - } - - /* XXX: for now, just make connection interval equal to max */ - connsm->conn_itvl = hcc->conn_itvl_max; - - /* Check the min/max CE lengths are less than connection interval */ - if (hcc->min_ce_len > (connsm->conn_itvl * 2)) { - connsm->min_ce_len = connsm->conn_itvl * 2; - } else { - connsm->min_ce_len = hcc->min_ce_len; - } - - if (hcc->max_ce_len > (connsm->conn_itvl * 2)) { - connsm->max_ce_len = connsm->conn_itvl * 2; - } else { - connsm->max_ce_len = hcc->max_ce_len; - } -} - -static void -ble_ll_update_max_tx_octets_phy_mode(struct ble_ll_conn_sm *connsm) -{ - uint32_t usecs; - - usecs = connsm->eff_max_tx_time; - - connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_1M] = - ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_1M); - connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_2M] = - ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_2M); - connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_CODED_125KBPS] = - ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_CODED_125KBPS); - connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_CODED_500KBPS] = - ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_CODED_500KBPS); -} - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - -static void -ble_ll_conn_set_phy(struct ble_ll_conn_sm *connsm, int tx_phy, int rx_phy) -{ - - struct ble_ll_conn_phy_data *phy_data = &connsm->phy_data; - - phy_data->rx_phy_mode = ble_ll_phy_to_phy_mode(rx_phy, - BLE_HCI_LE_PHY_CODED_ANY); - phy_data->cur_rx_phy = rx_phy; - - phy_data->tx_phy_mode = ble_ll_phy_to_phy_mode(tx_phy, - BLE_HCI_LE_PHY_CODED_ANY); - phy_data->cur_tx_phy = tx_phy; - -} - -static void -ble_ll_conn_init_phy(struct ble_ll_conn_sm *connsm, int phy) -{ - struct ble_ll_conn_global_params *conngp; - - /* Always initialize symmetric PHY - controller can change this later */ - ble_ll_conn_set_phy(connsm, phy, phy); - - /* Update data length management to match initial PHY */ - conngp = &g_ble_ll_conn_params; - connsm->max_tx_octets = conngp->conn_init_max_tx_octets; - connsm->max_rx_octets = conngp->supp_max_rx_octets; - if (phy == BLE_PHY_CODED) { - connsm->max_tx_time = conngp->conn_init_max_tx_time_coded; - connsm->max_rx_time = BLE_LL_CONN_SUPP_TIME_MAX_CODED; - connsm->rem_max_tx_time = BLE_LL_CONN_SUPP_TIME_MIN_CODED; - connsm->rem_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN_CODED; - /* Assume peer does support coded */ - connsm->remote_features[0] |= (BLE_LL_FEAT_LE_CODED_PHY >> 8); - } else { - connsm->max_tx_time = conngp->conn_init_max_tx_time_uncoded; - connsm->max_rx_time = BLE_LL_CONN_SUPP_TIME_MAX_UNCODED; - connsm->rem_max_tx_time = BLE_LL_CONN_SUPP_TIME_MIN_UNCODED; - connsm->rem_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN_UNCODED; - } - connsm->eff_max_tx_time = connsm->rem_max_tx_time; - connsm->eff_max_rx_time = connsm->rem_max_rx_time; - connsm->rem_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; - connsm->rem_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; - connsm->eff_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; - connsm->eff_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; - - ble_ll_update_max_tx_octets_phy_mode(connsm); -} - -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - -void -ble_ll_conn_ext_master_init(struct ble_ll_conn_sm *connsm, - struct hci_ext_create_conn *hcc) -{ - - ble_ll_conn_master_common_init(connsm); - - /* Set own address type and peer address if needed */ - connsm->own_addr_type = hcc->own_addr_type; - if (hcc->filter_policy == 0) { - memcpy(&connsm->peer_addr, &hcc->peer_addr, BLE_DEV_ADDR_LEN); - connsm->peer_addr_type = hcc->peer_addr_type; - } - - connsm->initial_params = *hcc; -} - -void -ble_ll_conn_ext_set_params(struct ble_ll_conn_sm *connsm, - struct hci_ext_conn_params *hcc_params, int phy) -{ - /* Set slave latency and supervision timeout */ - connsm->slave_latency = hcc_params->conn_latency; - connsm->supervision_tmo = hcc_params->supervision_timeout; - - /* XXX: for now, just make connection interval equal to max */ - connsm->conn_itvl = hcc_params->conn_itvl_max; - - - /* Check the min/max CE lengths are less than connection interval */ - if (hcc_params->min_ce_len > (connsm->conn_itvl * 2)) { - connsm->min_ce_len = connsm->conn_itvl * 2; - } else { - connsm->min_ce_len = hcc_params->min_ce_len; - } - - if (hcc_params->max_ce_len > (connsm->conn_itvl * 2)) { - connsm->max_ce_len = connsm->conn_itvl * 2; - } else { - connsm->max_ce_len = hcc_params->max_ce_len; - } - - ble_ll_conn_calc_itvl_ticks(connsm); - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_ll_conn_init_phy(connsm, phy); -#endif -} - - -#endif - -static void -ble_ll_conn_set_csa(struct ble_ll_conn_sm *connsm, bool chsel) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - if (chsel) { - CONN_F_CSA2_SUPP(connsm) = 1; - connsm->channel_id = ((connsm->access_addr & 0xffff0000) >> 16) ^ - (connsm->access_addr & 0x0000ffff); - - /* calculate the next data channel */ - connsm->data_chan_index = ble_ll_conn_calc_dci(connsm, 0); - return; - } -#endif - - connsm->last_unmapped_chan = 0; - - /* calculate the next data channel */ - connsm->data_chan_index = ble_ll_conn_calc_dci(connsm, 1); -} - -/** - * Create a new connection state machine. This is done once per - * connection when the HCI command "create connection" is issued to the - * controller or when a slave receives a connect request. - * - * Context: Link Layer task - * - * @param connsm - */ -void -ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) -{ - struct ble_ll_conn_global_params *conn_params; - - /* Reset following elements */ - connsm->csmflags.conn_flags = 0; - connsm->event_cntr = 0; - connsm->conn_state = BLE_LL_CONN_STATE_IDLE; - connsm->disconnect_reason = 0; - connsm->rxd_disconnect_reason = 0; - connsm->conn_features = BLE_LL_CONN_INITIAL_FEATURES; - memset(connsm->remote_features, 0, sizeof(connsm->remote_features)); - connsm->vers_nr = 0; - connsm->comp_id = 0; - connsm->sub_vers_nr = 0; - connsm->reject_reason = BLE_ERR_SUCCESS; - connsm->conn_rssi = BLE_LL_CONN_UNKNOWN_RSSI; - connsm->rpa_index = -1; - connsm->inita_identity_used = 0; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - connsm->sync_transfer_sync_timeout = g_ble_ll_conn_sync_transfer_params.sync_timeout_us; - connsm->sync_transfer_mode = g_ble_ll_conn_sync_transfer_params.mode; - connsm->sync_transfer_skip = g_ble_ll_conn_sync_transfer_params.max_skip; -#endif - - /* XXX: TODO set these based on PHY that started connection */ -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - connsm->phy_data.cur_tx_phy = BLE_PHY_1M; - connsm->phy_data.cur_rx_phy = BLE_PHY_1M; - connsm->phy_data.tx_phy_mode = BLE_PHY_MODE_1M; - connsm->phy_data.rx_phy_mode = BLE_PHY_MODE_1M; - connsm->phy_data.req_pref_tx_phys_mask = 0; - connsm->phy_data.req_pref_rx_phys_mask = 0; - connsm->phy_data.host_pref_tx_phys_mask = g_ble_ll_data.ll_pref_tx_phys; - connsm->phy_data.host_pref_rx_phys_mask = g_ble_ll_data.ll_pref_rx_phys; - connsm->phy_data.phy_options = 0; - connsm->phy_tx_transition = 0; -#endif - - /* Reset current control procedure */ - connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE; - connsm->pending_ctrl_procs = 0; - - /* - * Set handle in connection update procedure to 0. If the handle - * is non-zero it means that the host initiated the connection - * parameter update request and the rest of the parameters are valid. - */ - connsm->conn_param_req.handle = 0; - - /* Connection end event */ - ble_npl_event_init(&connsm->conn_ev_end, ble_ll_conn_event_end, connsm); - - /* Initialize transmit queue and ack/flow control elements */ - STAILQ_INIT(&connsm->conn_txq); - connsm->cur_tx_pdu = NULL; - connsm->tx_seqnum = 0; - connsm->next_exp_seqnum = 0; - connsm->cons_rxd_bad_crc = 0; - connsm->last_rxd_sn = 1; - connsm->completed_pkts = 0; - - /* initialize data length mgmt */ - conn_params = &g_ble_ll_conn_params; - connsm->max_tx_octets = conn_params->conn_init_max_tx_octets; - connsm->max_rx_octets = conn_params->supp_max_rx_octets; - connsm->max_tx_time = conn_params->conn_init_max_tx_time; - connsm->max_rx_time = conn_params->supp_max_rx_time; - connsm->rem_max_tx_time = BLE_LL_CONN_SUPP_TIME_MIN; - connsm->rem_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN; - connsm->eff_max_tx_time = BLE_LL_CONN_SUPP_TIME_MIN; - connsm->eff_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN; - connsm->rem_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; - connsm->rem_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; - connsm->eff_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; - connsm->eff_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - connsm->host_req_max_tx_time = 0; -#endif - - ble_ll_update_max_tx_octets_phy_mode(connsm); - - /* Reset encryption data */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - memset(&connsm->enc_data, 0, sizeof(struct ble_ll_conn_enc_data)); - connsm->enc_data.enc_state = CONN_ENC_S_UNENCRYPTED; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) - connsm->auth_pyld_tmo = BLE_LL_CONN_DEF_AUTH_PYLD_TMO; - CONN_F_LE_PING_SUPP(connsm) = 1; - ble_npl_callout_init(&connsm->auth_pyld_timer, - &g_ble_ll_data.ll_evq, - ble_ll_conn_auth_pyld_timer_cb, - connsm); -#endif - - ble_ll_conn_calc_itvl_ticks(connsm); - - /* Add to list of active connections */ - SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle); -} - -void -ble_ll_conn_update_eff_data_len(struct ble_ll_conn_sm *connsm) -{ - int send_event; - uint16_t eff_time; - uint16_t eff_bytes; - - /* Assume no event sent */ - send_event = 0; - - /* See if effective times have changed */ - eff_time = min(connsm->rem_max_tx_time, connsm->max_rx_time); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - if (connsm->phy_data.cur_rx_phy == BLE_PHY_CODED) { - eff_time = max(eff_time, BLE_LL_CONN_SUPP_TIME_MIN_CODED); - } -#endif - if (eff_time != connsm->eff_max_rx_time) { - connsm->eff_max_rx_time = eff_time; - send_event = 1; - } - eff_time = min(connsm->rem_max_rx_time, connsm->max_tx_time); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - if (connsm->phy_data.cur_tx_phy == BLE_PHY_CODED) { - eff_time = max(eff_time, BLE_LL_CONN_SUPP_TIME_MIN_CODED); - } -#endif - if (eff_time != connsm->eff_max_tx_time) { - connsm->eff_max_tx_time = eff_time; - send_event = 1; - - ble_ll_update_max_tx_octets_phy_mode(connsm); - } - eff_bytes = min(connsm->rem_max_tx_octets, connsm->max_rx_octets); - if (eff_bytes != connsm->eff_max_rx_octets) { - connsm->eff_max_rx_octets = eff_bytes; - send_event = 1; - } - eff_bytes = min(connsm->rem_max_rx_octets, connsm->max_tx_octets); - if (eff_bytes != connsm->eff_max_tx_octets) { - connsm->eff_max_tx_octets = eff_bytes; - send_event = 1; - } - - if (send_event) { - ble_ll_hci_ev_datalen_chg(connsm); - } -} - -/** - * Called when a connection is terminated - * - * Context: Link Layer task. - * - * @param connsm - * @param ble_err - */ -void -ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) -{ - struct os_mbuf *m; - struct os_mbuf_pkthdr *pkthdr; - os_sr_t sr; - - /* Remove scheduler events just in case */ - ble_ll_sched_rmv_elem(&connsm->conn_sch); - - /* In case of the supervision timeout we shall make sure - * that there is no ongoing connection event. It could happen - * because we scheduled connection event before checking connection timeout. - * If connection event managed to start, let us drop it. - */ - OS_ENTER_CRITICAL(sr); - if (g_ble_ll_conn_cur_sm == connsm) { - ble_ll_conn_halt(); - STATS_INC(ble_ll_conn_stats, conn_event_while_tmo); - } - OS_EXIT_CRITICAL(sr); - - /* Stop any control procedures that might be running */ - ble_npl_callout_stop(&connsm->ctrl_proc_rsp_timer); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) - ble_npl_callout_stop(&connsm->auth_pyld_timer); -#endif - - /* Remove from the active connection list */ - SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, act_sle); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) - ble_ll_conn_cth_flow_free_credit(connsm, connsm->cth_flow_pending); -#endif - - /* Free the current transmit pdu if there is one. */ - if (connsm->cur_tx_pdu) { - os_mbuf_free_chain(connsm->cur_tx_pdu); - connsm->cur_tx_pdu = NULL; - } - - /* Free all packets on transmit queue */ - while (1) { - /* Get mbuf pointer from packet header pointer */ - pkthdr = STAILQ_FIRST(&connsm->conn_txq); - if (!pkthdr) { - break; - } - STAILQ_REMOVE_HEAD(&connsm->conn_txq, omp_next); - - m = (struct os_mbuf *)((uint8_t *)pkthdr - sizeof(struct os_mbuf)); - os_mbuf_free_chain(m); - } - - /* Make sure events off queue */ - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_ev_end); - -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) - /* Remove from occupied periods */ - OS_ENTER_CRITICAL(sr); - BLE_LL_ASSERT(g_ble_ll_sched_data.sch_num_occ_periods > 0); - BLE_LL_ASSERT(g_ble_ll_sched_data.sch_occ_period_mask & connsm->period_occ_mask); - --g_ble_ll_sched_data.sch_num_occ_periods; - g_ble_ll_sched_data.sch_occ_period_mask &= ~connsm->period_occ_mask; - OS_EXIT_CRITICAL(sr); -#endif - - /* Connection state machine is now idle */ - connsm->conn_state = BLE_LL_CONN_STATE_IDLE; - - /* - * If we have features and there's pending HCI command, send an event before - * disconnection event so it does make sense to host. - */ - if (connsm->csmflags.cfbit.pending_hci_rd_features && - connsm->csmflags.cfbit.rxd_features) { - ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; - } - - /* - * If there is still pending read features request HCI command, send an - * event to complete it. - */ - if (connsm->csmflags.cfbit.pending_hci_rd_features) { - ble_ll_hci_ev_rd_rem_used_feat(connsm, ble_err); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; - } - - /* - * We need to send a disconnection complete event. Connection Complete for - * canceling connection creation is sent from LE Create Connection Cancel - * Command handler. - * - * If the ble error is "success" it means that the reset command was - * received and we should not send an event. - */ - if (ble_err && (ble_err != BLE_ERR_UNK_CONN_ID || - connsm->csmflags.cfbit.terminate_ind_rxd)) { - ble_ll_disconn_comp_event_send(connsm, ble_err); - } - - /* Put connection state machine back on free list */ - STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); - - /* Log connection end */ - ble_ll_trace_u32x3(BLE_LL_TRACE_ID_CONN_END, connsm->conn_handle, - connsm->event_cntr, (uint32_t)ble_err); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -void -ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event, - uint32_t *anchor, uint8_t *anchor_usecs) -{ - uint32_t ticks; - uint32_t itvl; - - itvl = (connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS); - - if ((int16_t)(conn_event - connsm->event_cntr) < 0) { - itvl *= connsm->event_cntr - conn_event; - ticks = os_cputime_usecs_to_ticks(itvl); - *anchor = connsm->anchor_point - ticks; - } else { - itvl *= conn_event - connsm->event_cntr; - ticks = os_cputime_usecs_to_ticks(itvl); - *anchor = connsm->anchor_point + ticks; - } - - *anchor_usecs = connsm->anchor_point_usecs; - *anchor_usecs += (itvl - os_cputime_ticks_to_usecs(ticks)); - if (*anchor_usecs >= 31) { - (*anchor)++; - *anchor_usecs -= 31; - } -} -#endif - -/** - * Called to move to the next connection event. - * - * Context: Link Layer task. - * - * @param connsm - * - * @return int - */ -static int -ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) -{ - uint16_t latency; - uint32_t itvl; - uint32_t cur_ww; - uint32_t max_ww; - struct ble_ll_conn_upd_req *upd; - uint32_t ticks; - uint32_t usecs; - - /* XXX: deal with connection request procedure here as well */ - ble_ll_conn_chk_csm_flags(connsm); - - /* If unable to start terminate procedure, start it now */ - if (connsm->disconnect_reason && !CONN_F_TERMINATE_STARTED(connsm)) { - ble_ll_ctrl_terminate_start(connsm); - } - - if (CONN_F_TERMINATE_STARTED(connsm) && (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE)) { - /* Some of the devices waits whole connection interval to ACK our - * TERMINATE_IND sent as a Slave. Since we are here it means we are still waiting for ACK. - * Make sure we catch it in next connection event. - */ - connsm->slave_latency = 0; - } - - /* - * XXX: TODO Probably want to add checks to see if we need to start - * a control procedure here as an instant may have prevented us from - * starting one. - */ - - /* - * XXX TODO: I think this is technically incorrect. We can allow slave - * latency if we are doing one of these updates as long as we - * know that the master has received the ACK to the PDU that set - * the instant - */ - /* Set event counter to the next connection event that we will tx/rx in */ - itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS; - latency = 1; - if (connsm->csmflags.cfbit.allow_slave_latency && - !connsm->csmflags.cfbit.conn_update_sched && - !CONN_F_PHY_UPDATE_SCHED(connsm) && - !connsm->csmflags.cfbit.chanmap_update_scheduled) { - if (connsm->csmflags.cfbit.pkt_rxd) { - latency += connsm->slave_latency; - itvl = itvl * latency; - } - } - connsm->event_cntr += latency; - - /* Set next connection event start time */ - /* We can use pre-calculated values for one interval if latency is 1. */ - if (latency == 1) { - connsm->anchor_point += connsm->conn_itvl_ticks; - connsm->anchor_point_usecs += connsm->conn_itvl_usecs; - } else { - uint32_t ticks; - ticks = os_cputime_usecs_to_ticks(itvl); - connsm->anchor_point += ticks; - connsm->anchor_point_usecs += (itvl - os_cputime_ticks_to_usecs(ticks)); - } - if (connsm->anchor_point_usecs >= 31) { - ++connsm->anchor_point; - connsm->anchor_point_usecs -= 31; - } - - /* - * If a connection update has been scheduled and the event counter - * is now equal to the instant, we need to adjust the start of the - * connection by the the transmit window offset. We also copy in the - * update parameters as they now should take effect. - */ - if (connsm->csmflags.cfbit.conn_update_sched && - (connsm->event_cntr == connsm->conn_update_req.instant)) { - - /* Set flag so we send connection update event */ - upd = &connsm->conn_update_req; - if ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) || - ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && - IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) || - (connsm->conn_itvl != upd->interval) || - (connsm->slave_latency != upd->latency) || - (connsm->supervision_tmo != upd->timeout)) { - connsm->csmflags.cfbit.host_expects_upd_event = 1; - } - - connsm->supervision_tmo = upd->timeout; - connsm->slave_latency = upd->latency; - connsm->tx_win_size = upd->winsize; - connsm->slave_cur_tx_win_usecs = - connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS; - connsm->tx_win_off = upd->winoffset; - connsm->conn_itvl = upd->interval; - ble_ll_conn_calc_itvl_ticks(connsm); - if (upd->winoffset != 0) { - usecs = upd->winoffset * BLE_LL_CONN_ITVL_USECS; - ticks = os_cputime_usecs_to_ticks(usecs); - connsm->anchor_point += ticks; - usecs = usecs - os_cputime_ticks_to_usecs(ticks); - connsm->anchor_point_usecs += usecs; - if (connsm->anchor_point_usecs >= 31) { - ++connsm->anchor_point; - connsm->anchor_point_usecs -= 31; - } - } - - /* Reset the starting point of the connection supervision timeout */ - connsm->last_rxd_pdu_cputime = connsm->anchor_point; - - /* Reset update scheduled flag */ - connsm->csmflags.cfbit.conn_update_sched = 0; - } - - /* - * If there is a channel map request pending and we have reached the - * instant, change to new channel map. Note there is a special case here. - * If we received a channel map update with an instant equal to the event - * counter, when we get here the event counter has already been - * incremented by 1. That is why we do a signed comparison and change to - * new channel map once the event counter equals or has passed channel - * map update instant. - */ - if (connsm->csmflags.cfbit.chanmap_update_scheduled && - ((int16_t)(connsm->chanmap_instant - connsm->event_cntr) <= 0)) { - - /* XXX: there is a chance that the control packet is still on - * the queue of the master. This means that we never successfully - * transmitted update request. Would end up killing connection - on slave side. Could ignore it or see if still enqueued. */ - connsm->num_used_chans = - ble_ll_utils_calc_num_used_chans(connsm->req_chanmap); - memcpy(connsm->chanmap, connsm->req_chanmap, BLE_LL_CONN_CHMAP_LEN); - - connsm->csmflags.cfbit.chanmap_update_scheduled = 0; - - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CHAN_MAP_UPD); - - /* XXX: host could have resent channel map command. Need to - check to make sure we dont have to restart! */ - } - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - if (CONN_F_PHY_UPDATE_SCHED(connsm) && - (connsm->event_cntr == connsm->phy_instant)) { - - /* Set cur phy to new phy */ - if (connsm->phy_data.new_tx_phy) { - connsm->phy_data.cur_tx_phy = connsm->phy_data.new_tx_phy; - connsm->phy_data.tx_phy_mode = - ble_ll_phy_to_phy_mode(connsm->phy_data.cur_tx_phy, - connsm->phy_data.phy_options); - } - - if (connsm->phy_data.new_rx_phy) { - connsm->phy_data.cur_rx_phy = connsm->phy_data.new_rx_phy; - connsm->phy_data.rx_phy_mode = - ble_ll_phy_to_phy_mode(connsm->phy_data.cur_rx_phy, - connsm->phy_data.phy_options); - } - - /* Clear flags and set flag to send event at next instant */ - CONN_F_PHY_UPDATE_SCHED(connsm) = 0; - CONN_F_PHY_UPDATE_EVENT(connsm) = 1; - - ble_ll_ctrl_phy_update_proc_complete(connsm); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - /* Recalculate effective connection parameters */ - ble_ll_conn_update_eff_data_len(connsm); - - /* - * If PHY in either direction was changed to coded, we assume that peer - * does support LE Coded PHY even if features were not exchanged yet. - * This means that MaxRxTime can be updated to supported max and we need - * initiate DLE to notify peer about the change. - */ - if (((connsm->phy_data.cur_tx_phy == BLE_PHY_CODED) || - (connsm->phy_data.cur_rx_phy == BLE_PHY_CODED)) && - !(connsm->remote_features[0] & (BLE_LL_FEAT_LE_CODED_PHY >> 8))) { - connsm->remote_features[0] |= (BLE_LL_FEAT_LE_CODED_PHY >> 8); - connsm->max_rx_time = BLE_LL_CONN_SUPP_TIME_MAX_CODED; - ble_ll_ctrl_initiate_dle(connsm); - } -#endif - } -#endif - - /* Calculate data channel index of next connection event */ - connsm->data_chan_index = ble_ll_conn_calc_dci(connsm, latency); - - /* - * If we are trying to terminate connection, check if next wake time is - * passed the termination timeout. If so, no need to continue with - * connection as we will time out anyway. - */ - if (CONN_F_TERMINATE_STARTED(connsm)) { - if ((int32_t)(connsm->terminate_timeout - connsm->anchor_point) <= 0) { - return -1; - } - } - - /* - * Calculate ce end time. For a slave, we need to add window widening and - * the transmit window if we still have one. - */ -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) - itvl = g_ble_ll_sched_data.sch_ticks_per_period; -#else - itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT; -#endif - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - - cur_ww = ble_ll_utils_calc_window_widening(connsm->anchor_point, - connsm->last_anchor_point, - connsm->master_sca); - max_ww = (connsm->conn_itvl * (BLE_LL_CONN_ITVL_USECS/2)) - BLE_LL_IFS; - if (cur_ww >= max_ww) { - return -1; - } - cur_ww += BLE_LL_JITTER_USECS; - connsm->slave_cur_window_widening = cur_ww; - itvl += os_cputime_usecs_to_ticks(cur_ww + connsm->slave_cur_tx_win_usecs); - } - itvl -= g_ble_ll_sched_offset_ticks; - connsm->ce_end_time = connsm->anchor_point + itvl; - - return 0; -} - -/** - * Called when a connection has been created. This function will - * -> Set the connection state to created. - * -> Start the connection supervision timer - * -> Set the Link Layer state to connection. - * -> Send a connection complete event. - * - * See Section 4.5.2 Vol 6 Part B - * - * Context: Link Layer - * - * @param connsm - * - * @ return 0: connection NOT created. 1: connection created - */ -static int -ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) -{ - int rc; - uint8_t *evbuf; - uint32_t endtime; - uint32_t usecs; - - /* XXX: TODO this assumes we received in 1M phy */ - - /* Set state to created */ - connsm->conn_state = BLE_LL_CONN_STATE_CREATED; - - /* Clear packet received flag */ - connsm->csmflags.cfbit.pkt_rxd = 0; - - /* Consider time created the last scheduled time */ - connsm->last_scheduled = os_cputime_get32(); - - /* - * Set the last rxd pdu time since this is where we want to start the - * supervision timer from. - */ - connsm->last_rxd_pdu_cputime = connsm->last_scheduled; - - /* - * Set first connection event time. If slave the endtime is the receive end - * time of the connect request. The actual connection starts 1.25 msecs plus - * the transmit window offset from the end of the connection request. - */ - rc = 1; - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - /* - * With a 32.768 kHz crystal we dont care about the remaining usecs - * when setting last anchor point. The only thing last anchor is used - * for is to calculate window widening. The effect of this is - * negligible. - */ - connsm->last_anchor_point = rxhdr->beg_cputime; - - usecs = rxhdr->rem_usecs + 1250 + - (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS) + - ble_ll_pdu_tx_time_get(BLE_CONNECT_REQ_LEN, - rxhdr->rxinfo.phy_mode); - - if (rxhdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) { - switch (rxhdr->rxinfo.phy) { - case BLE_PHY_1M: - case BLE_PHY_2M: - usecs += 1250; - break; - case BLE_PHY_CODED: - usecs += 2500; - break; - default: - BLE_LL_ASSERT(0); - break; - } - } - - /* Anchor point is cputime. */ - endtime = os_cputime_usecs_to_ticks(usecs); - connsm->anchor_point = rxhdr->beg_cputime + endtime; - connsm->anchor_point_usecs = usecs - os_cputime_ticks_to_usecs(endtime); - if (connsm->anchor_point_usecs == 31) { - ++connsm->anchor_point; - connsm->anchor_point_usecs = 0; - } - - connsm->slave_cur_tx_win_usecs = - connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS; -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) - connsm->ce_end_time = connsm->anchor_point + - g_ble_ll_sched_data.sch_ticks_per_period + - os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1; - -#else - connsm->ce_end_time = connsm->anchor_point + - (MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT) - + os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1; -#endif - connsm->slave_cur_window_widening = BLE_LL_JITTER_USECS; - - /* Start the scheduler for the first connection event */ - while (ble_ll_sched_slave_new(connsm)) { - if (ble_ll_conn_next_event(connsm)) { - STATS_INC(ble_ll_conn_stats, cant_set_sched); - rc = 0; - break; - } - } - } - - /* Send connection complete event to inform host of connection */ - if (rc) { -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - /* - * If we have default phy preferences and they are different than - * the current PHY's in use, start update procedure. - */ - /* - * XXX: should we attempt to start this without knowing if - * the other side can support it? - */ - if (!ble_ll_conn_chk_phy_upd_start(connsm)) { - CONN_F_CTRLR_PHY_UPDATE(connsm) = 1; - } -#endif - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - ble_ll_adv_send_conn_comp_ev(connsm, rxhdr); - } else { - evbuf = ble_ll_init_get_conn_comp_ev(); - ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, evbuf, NULL); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - ble_ll_hci_ev_le_csa(connsm); -#endif - - /* - * Initiate features exchange - * - * XXX we do this only as a master as it was observed that sending - * LL_SLAVE_FEATURE_REQ after connection breaks some recent iPhone - * models; for slave just assume master will initiate features xchg - * if it has some additional features to use. - */ - ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG); - } - } - - return rc; -} - -/** - * Called upon end of connection event - * - * Context: Link-layer task - * - * @param void *arg Pointer to connection state machine - * - */ -static void -ble_ll_conn_event_end(struct ble_npl_event *ev) -{ - uint8_t ble_err; - uint32_t tmo; - struct ble_ll_conn_sm *connsm; - - ble_ll_rfmgmt_release(); - - /* Better be a connection state machine! */ - connsm = (struct ble_ll_conn_sm *)ble_npl_event_get_arg(ev); - BLE_LL_ASSERT(connsm); - if (connsm->conn_state == BLE_LL_CONN_STATE_IDLE) { - /* That should not happen. If it does it means connection - * is already closed. - * Make sure LL state machine is in idle - */ - STATS_INC(ble_ll_conn_stats, sched_end_in_idle); - BLE_LL_ASSERT(0); - - /* Just in case */ - ble_ll_state_set(BLE_LL_STATE_STANDBY); - - ble_ll_scan_chk_resume(); - return; - } - - /* Log event end */ - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_CONN_EV_END, connsm->conn_handle, - connsm->event_cntr); - - ble_ll_scan_chk_resume(); - - /* If we have transmitted the terminate IND successfully, we are done */ - if ((connsm->csmflags.cfbit.terminate_ind_txd) || - (connsm->csmflags.cfbit.terminate_ind_rxd && - connsm->csmflags.cfbit.terminate_ind_rxd_acked)) { - if (connsm->csmflags.cfbit.terminate_ind_txd) { - ble_err = BLE_ERR_CONN_TERM_LOCAL; - } else { - /* Make sure the disconnect reason is valid! */ - ble_err = connsm->rxd_disconnect_reason; - if (ble_err == 0) { - ble_err = BLE_ERR_REM_USER_CONN_TERM; - } - } - ble_ll_conn_end(connsm, ble_err); - return; - } - - /* Remove any connection end events that might be enqueued */ - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_ev_end); - - /* - * If we have received a packet, we can set the current transmit window - * usecs to 0 since we dont need to listen in the transmit window. - */ - if (connsm->csmflags.cfbit.pkt_rxd) { - connsm->slave_cur_tx_win_usecs = 0; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) - /* - * If we are encrypted and have passed the authenticated payload timeout - * we need to send an event to tell the host. Unfortunately, I think we - * need one of these per connection and we have to set this timer - * fairly accurately. So we need to another event in the connection. - * This sucks. - * - * The way this works is that whenever the timer expires it just gets reset - * and we send the autheticated payload timeout event. Note that this timer - * should run even when encryption is paused. - * XXX: what should be here? Was there code here that got deleted? - */ -#endif - - /* Move to next connection event */ - if (ble_ll_conn_next_event(connsm)) { - ble_ll_conn_end(connsm, BLE_ERR_CONN_TERM_LOCAL); - return; - } - - /* Reset "per connection event" variables */ - connsm->cons_rxd_bad_crc = 0; - connsm->csmflags.cfbit.pkt_rxd = 0; - - /* See if we need to start any control procedures */ - ble_ll_ctrl_chk_proc_start(connsm); - - /* Set initial schedule callback */ - connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb; - - /* XXX: I think all this fine for when we do connection updates, but - we may want to force the first event to be scheduled. Not sure */ - /* Schedule the next connection event */ - while (ble_ll_sched_conn_reschedule(connsm)) { - if (ble_ll_conn_next_event(connsm)) { - ble_ll_conn_end(connsm, BLE_ERR_CONN_TERM_LOCAL); - return; - } - } - - /* - * This is definitely not perfect but hopefully will be fine in regards to - * the specification. We check the supervision timer at connection event - * end. If the next connection event is going to start past the supervision - * timeout we end the connection here. I guess this goes against the spec - * in two ways: - * 1) We are actually causing a supervision timeout before the time - * specified. However, this is really a moot point because the supervision - * timeout would have expired before we could possibly receive a packet. - * 2) We may end the supervision timeout a bit later than specified as - * we only check this at event end and a bad CRC could cause us to continue - * the connection event longer than the supervision timeout. Given that two - * bad CRC's consecutively ends the connection event, I dont regard this as - * a big deal but it could cause a slightly longer supervision timeout. - */ - if (connsm->conn_state == BLE_LL_CONN_STATE_CREATED) { - tmo = (uint32_t)connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS * 6UL; - ble_err = BLE_ERR_CONN_ESTABLISHMENT; - } else { - tmo = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000UL; - ble_err = BLE_ERR_CONN_SPVN_TMO; - } - /* XXX: Convert to ticks to usecs calculation instead??? */ - tmo = os_cputime_usecs_to_ticks(tmo); - if ((int32_t)(connsm->anchor_point - connsm->last_rxd_pdu_cputime) >= tmo) { - ble_ll_conn_end(connsm, ble_err); - return; - } - - /* If we have completed packets, send an event */ - ble_ll_conn_num_comp_pkts_event_send(connsm); - - /* If we have features and there's pending HCI command, send an event */ - if (connsm->csmflags.cfbit.pending_hci_rd_features && - connsm->csmflags.cfbit.rxd_features) { - ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; - } -} - -/** - * Update the connection request PDU with the address type and address of - * advertiser we are going to send connect request to. - * - * @param m - * @param adva - * @param addr_type Address type of ADVA from received advertisement. - * @param inita - * @param inita_type Address type of INITA from received advertisement. - - * @param txoffset The tx window offset for this connection - */ -static void -ble_ll_conn_connect_ind_prepare(struct ble_ll_conn_sm *connsm, - struct ble_ll_scan_pdu_data *pdu_data, - uint8_t adva_type, uint8_t *adva, - uint8_t inita_type, uint8_t *inita, - int rpa_index, uint8_t channel) -{ - uint8_t hdr; - uint8_t *addr; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - int is_rpa; - struct ble_ll_resolv_entry *rl; -#endif - - hdr = BLE_ADV_PDU_TYPE_CONNECT_IND; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - /* We need CSA2 bit only for legacy connect */ - if (channel >= BLE_PHY_NUM_DATA_CHANS) { - hdr |= BLE_ADV_PDU_HDR_CHSEL; - } -#endif - - if (adva_type) { - /* Set random address */ - hdr |= BLE_ADV_PDU_HDR_RXADD_MASK; - } - - if (inita) { - memcpy(pdu_data->inita, inita, BLE_DEV_ADDR_LEN); - if (inita_type) { - hdr |= BLE_ADV_PDU_HDR_TXADD_RAND; - } - } else { - /* Get pointer to our device address */ - connsm = g_ble_ll_conn_create_sm; - if ((connsm->own_addr_type & 1) == 0) { - addr = g_dev_addr; - } else { - hdr |= BLE_ADV_PDU_HDR_TXADD_RAND; - addr = g_random_addr; - } - - /* XXX: do this ahead of time? Calculate the local rpa I mean */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (connsm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { - rl = NULL; - is_rpa = ble_ll_is_rpa(adva, adva_type); - if (is_rpa) { - if (rpa_index >= 0) { - rl = &g_ble_ll_resolv_list[rpa_index]; - } - } else { - /* we look for RL entry to generate local RPA regardless if - * resolving is enabled or not (as this is is for local RPA - * not peer RPA) - */ - rl = ble_ll_resolv_list_find(adva, adva_type); - } - - /* - * If peer in on resolving list, we use RPA generated with Local IRK - * from resolving list entry. In other case, we need to use our identity - * address (see Core 5.0, Vol 6, Part B, section 6.4). - */ - if (rl && rl->rl_has_local) { - hdr |= BLE_ADV_PDU_HDR_TXADD_RAND; - ble_ll_resolv_get_priv_addr(rl, 1, pdu_data->inita); - addr = NULL; - } - } -#endif - - if (addr) { - memcpy(pdu_data->inita, addr, BLE_DEV_ADDR_LEN); - /* Identity address used */ - connsm->inita_identity_used = 1; - } - } - - memcpy(pdu_data->adva, adva, BLE_DEV_ADDR_LEN); - - pdu_data->hdr_byte = hdr; -} - -/* Returns true if the address matches the connection peer address having in - * mind privacy mode - */ -static int -ble_ll_conn_is_peer_adv(uint8_t addr_type, uint8_t *adva, int index) -{ - int rc; - uint8_t *peer_addr = NULL; - struct ble_ll_conn_sm *connsm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - struct ble_ll_resolv_entry *rl; -#endif - - /* XXX: Deal with different types of random addresses here! */ - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return 0; - } - - switch (connsm->peer_addr_type) { - /* Fall-through intentional */ - case BLE_HCI_CONN_PEER_ADDR_PUBLIC: - case BLE_HCI_CONN_PEER_ADDR_RANDOM: -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (ble_ll_addr_is_id(adva, addr_type)) { - /* Peer uses its identity address. Let's verify privacy mode. - * - * Note: Core Spec 5.0 Vol 6, Part B - * If the Host has added the peer device to the resolving list - * with an all-zero peer IRK, the Controller shall only accept - * the peer's identity address. - */ - if (ble_ll_resolv_enabled()) { - rl = ble_ll_resolv_list_find(adva, addr_type); - if (rl && (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && - rl->rl_has_peer) { - return 0; - } - } - } - - /* Check if peer uses RPA. If so and it match, use it as controller - * supports privacy mode - */ - if ((index >= 0) && - (g_ble_ll_resolv_list[index].rl_addr_type == connsm->peer_addr_type)) { - peer_addr = g_ble_ll_resolv_list[index].rl_identity_addr; - } -#endif - /* - * If we are here it means we don't know the device, lets - * check if type is what we are looking for and later - * if address matches - */ - if ((connsm->peer_addr_type == addr_type) && !peer_addr) { - peer_addr = adva; - } - - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - case BLE_HCI_CONN_PEER_ADDR_PUBLIC_IDENT: - if ((index < 0) || - (g_ble_ll_resolv_list[index].rl_addr_type != 0)) { - return 0; - } - peer_addr = g_ble_ll_resolv_list[index].rl_identity_addr; - break; - case BLE_HCI_CONN_PEER_ADDR_RANDOM_IDENT: - if ((index < 0) || - (g_ble_ll_resolv_list[index].rl_addr_type != 1)) { - return 0; - } - peer_addr = g_ble_ll_resolv_list[index].rl_identity_addr; - break; -#endif - default: - peer_addr = NULL; - break; - } - - rc = 0; - if (peer_addr) { - if (!memcmp(peer_addr, connsm->peer_addr, BLE_DEV_ADDR_LEN)) { - rc = 1; - } - } - - return rc; -} - -static void -ble_ll_conn_connect_ind_txend_to_standby(void *arg) -{ - ble_ll_state_set(BLE_LL_STATE_STANDBY); -} - -static void -ble_ll_conn_connect_ind_txend_to_init(void *arg) -{ - ble_ll_state_set(BLE_LL_STATE_INITIATING); -} - -static uint8_t -ble_ll_conn_connect_ind_tx_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) -{ - struct ble_ll_conn_sm *connsm; - struct ble_ll_scan_pdu_data *pdu_data; - - connsm = pducb_arg; - /* - * pdu_data was prepared just before starting TX and is expected to be - * still valid here - */ - pdu_data = ble_ll_scan_get_pdu_data(); - - memcpy(dptr, pdu_data->inita, BLE_DEV_ADDR_LEN); - memcpy(dptr + BLE_DEV_ADDR_LEN, pdu_data->adva, BLE_DEV_ADDR_LEN); - - dptr += 2 * BLE_DEV_ADDR_LEN; - - put_le32(dptr, connsm->access_addr); - dptr[4] = (uint8_t)connsm->crcinit; - dptr[5] = (uint8_t)(connsm->crcinit >> 8); - dptr[6] = (uint8_t)(connsm->crcinit >> 16); - dptr[7] = connsm->tx_win_size; - put_le16(dptr + 8, connsm->tx_win_off); - put_le16(dptr + 10, connsm->conn_itvl); - put_le16(dptr + 12, connsm->slave_latency); - put_le16(dptr + 14, connsm->supervision_tmo); - memcpy(dptr + 16, &connsm->chanmap, BLE_LL_CONN_CHMAP_LEN); - dptr[21] = connsm->hop_inc | (connsm->master_sca << 5); - - *hdr_byte = pdu_data->hdr_byte; - - return 34; -} - -/** - * Send a connection requestion to an advertiser - * - * Context: Interrupt - * - * @param addr_type Address type of advertiser - * @param adva Address of advertiser - */ -int -ble_ll_conn_connect_ind_send(struct ble_ll_conn_sm *connsm, uint8_t end_trans) -{ - int rc; - - if (end_trans == BLE_PHY_TRANSITION_NONE) { - ble_phy_set_txend_cb(ble_ll_conn_connect_ind_txend_to_standby, NULL); - } else { - ble_phy_set_txend_cb(ble_ll_conn_connect_ind_txend_to_init, NULL); - } - - rc = ble_phy_tx(ble_ll_conn_connect_ind_tx_pducb, connsm, end_trans); - - return rc; -} - -/** - * Called when a schedule item overlaps the currently running connection - * event. This generally should not happen, but if it does we stop the - * current connection event to let the schedule item run. - * - * NOTE: the phy has been disabled as well as the wfr timer before this is - * called. - */ -void -ble_ll_conn_event_halt(void) -{ - ble_ll_state_set(BLE_LL_STATE_STANDBY); - if (g_ble_ll_conn_cur_sm) { - g_ble_ll_conn_cur_sm->csmflags.cfbit.pkt_rxd = 0; - ble_ll_event_send(&g_ble_ll_conn_cur_sm->conn_ev_end); - g_ble_ll_conn_cur_sm = NULL; - } -} - -/** - * Process a received PDU while in the initiating state. - * - * Context: Link Layer task. - * - * @param pdu_type - * @param rxbuf - * @param ble_hdr - */ -void -ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *ble_hdr) -{ - uint8_t addr_type; - uint8_t *addr; - uint8_t *adv_addr; - uint8_t *inita; - uint8_t inita_type; - struct ble_ll_conn_sm *connsm; - int ext_adv_mode = -1; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data = NULL; - - if (ble_hdr->rxinfo.user_data) { - /* aux_data just a local helper, no need to ref - * as ble_hdr->rxinfo.user_data is unref in the end of this function - */ - aux_data = ble_hdr->rxinfo.user_data; - } -#endif - - /* Get the connection state machine we are trying to create */ - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (aux_data) { - ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data); - ble_hdr->rxinfo.user_data = NULL; - } -#endif - return; - } - - if (!BLE_MBUF_HDR_CRC_OK(ble_hdr)) { - goto scan_continue; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (BLE_MBUF_HDR_AUX_INVALID(ble_hdr)) { - goto scan_continue; - } - - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) { - if (BLE_MBUF_HDR_WAIT_AUX(ble_hdr)) { - /* Just continue scanning. We are waiting for AUX */ - if (!ble_ll_sched_aux_scan(ble_hdr, connsm->scansm, aux_data)) { - /* ref for aux ptr in the scheduler */ - ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data); - ble_hdr->rxinfo.user_data = NULL; - ble_ll_scan_chk_resume(); - return; - } - goto scan_continue; - } - } - - if (CONN_F_AUX_CONN_REQ(connsm)) { - if (pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) { - /* Wait for connection response, in this point of time aux is NULL */ - BLE_LL_ASSERT(ble_hdr->rxinfo.user_data == NULL); - return; - } - } -#endif - - /* If we have sent a connect request, we need to enter CONNECTION state */ - if (connsm && CONN_F_CONN_REQ_TXD(connsm)) { - /* Set address of advertiser to which we are connecting. */ - - if (ble_ll_scan_adv_decode_addr(pdu_type, rxbuf, ble_hdr, - &adv_addr, &addr_type, - &inita, &inita_type, &ext_adv_mode)) { - /* Something got wrong, keep trying to connect */ - goto scan_continue; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* - * Did we resolve this address? If so, set correct peer address - * and peer address type. - */ - if (connsm->rpa_index >= 0) { - addr_type = g_ble_ll_resolv_list[connsm->rpa_index].rl_addr_type + 2; - addr = g_ble_ll_resolv_list[connsm->rpa_index].rl_identity_addr; - } else { - addr = adv_addr; - } -#else - addr = adv_addr; -#endif - - if (connsm->rpa_index >= 0) { - connsm->peer_addr_type = addr_type; - memcpy(connsm->peer_addr, addr, BLE_DEV_ADDR_LEN); - - ble_ll_scan_set_peer_rpa(adv_addr); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* Update resolving list with current peer RPA */ - ble_ll_resolv_set_peer_rpa(connsm->rpa_index, rxbuf + BLE_LL_PDU_HDR_LEN); - if (ble_ll_is_rpa(inita, inita_type)) { - ble_ll_resolv_set_local_rpa(connsm->rpa_index, inita); - } - -#endif - } else if (ble_ll_scan_whitelist_enabled()) { - /* if WL is used we need to store peer addr also if it was not - * resolved - */ - connsm->peer_addr_type = addr_type; - memcpy(connsm->peer_addr, addr, BLE_DEV_ADDR_LEN); - } - - /* Connection has been created. Stop scanning */ - g_ble_ll_conn_create_sm = NULL; - ble_ll_scan_sm_stop(0); - - /* For AUX Connect CSA2 is mandatory. Otherwise we need to check bit - * mask - */ - if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) { - ble_ll_conn_set_csa(connsm, 1); - } else { - ble_ll_conn_set_csa(connsm, rxbuf[0] & BLE_ADV_PDU_HDR_CHSEL_MASK); - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - /* Lets take last used phy */ - ble_ll_conn_init_phy(connsm, ble_hdr->rxinfo.phy); -#endif - if (aux_data) { - ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data); - ble_hdr->rxinfo.user_data = NULL; - } -#endif - ble_ll_conn_created(connsm, NULL); - return; - } - -scan_continue: -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* Drop last reference and keep continue to connect */ - if (aux_data) { - ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data); - ble_hdr->rxinfo.user_data = NULL; - } -#endif - ble_ll_scan_chk_resume(); -} - -/** - * Called when a receive PDU has started and we are in the initiating state. - * - * Context: Interrupt - * - * @param pdu_type - * @param ble_hdr - * - * @return int - * 0: we will not attempt to reply to this frame - * 1: we may send a response to this frame. - */ -int -ble_ll_init_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *ble_hdr) -{ - struct ble_ll_conn_sm *connsm; - - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return 0; - } - - if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) || - (pdu_type == BLE_ADV_PDU_TYPE_ADV_DIRECT_IND || - pdu_type == BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP)) { - return 1; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND && - connsm->scansm->ext_scanning) { - if (connsm->scansm->cur_aux_data) { - STATS_INC(ble_ll_stats, aux_received); - } - - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_EXT_ADV; - return 1; - } -#endif - - return 0; -} - -/** - * Called when a receive PDU has ended and we are in the initiating state. - * - * Context: Interrupt - * - * @param rxpdu - * @param crcok - * @param ble_hdr - * - * @return int - * < 0: Disable the phy after reception. - * == 0: Success. Do not disable the PHY. - * > 0: Do not disable PHY as that has already been done. - */ -int -ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok, - struct ble_mbuf_hdr *ble_hdr) -{ - int rc; - int resolved; - int chk_wl; - int index; - uint8_t pdu_type; - uint8_t adv_addr_type; - uint8_t peer_addr_type; - uint8_t *adv_addr = NULL; - uint8_t *peer; - uint8_t *init_addr = NULL; - uint8_t init_addr_type; - uint8_t pyld_len; - uint8_t inita_is_rpa; - uint8_t conn_req_end_trans; - struct os_mbuf *rxpdu; - struct ble_ll_conn_sm *connsm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - struct ble_ll_resolv_entry *rl; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_scan_sm *scansm; - uint8_t phy; -#endif - int ext_adv_mode = -1; - - /* Get connection state machine to use if connection to be established */ - connsm = g_ble_ll_conn_create_sm; - /* This could happen if connection init was cancelled while isr end was - * already pending - */ - if (!connsm) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - return -1; - } - - rc = -1; - pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK; - pyld_len = rxbuf[1]; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - scansm = connsm->scansm; - if (scansm->cur_aux_data) { - ble_hdr->rxinfo.user_data = scansm->cur_aux_data; - scansm->cur_aux_data = NULL; - } -#endif - - if (!crcok) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* Invalid packet - make sure we do not wait for AUX_CONNECT_RSP */ - ble_ll_conn_reset_pending_aux_conn_rsp(); -#endif - - /* Ignore this packet */ - goto init_rx_isr_exit; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* If we sent AUX_CONNECT_REQ, we only expect AUX_CONNECT_RSP here */ - if (CONN_F_AUX_CONN_REQ(connsm)) { - if (pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) { - STATS_INC(ble_ll_stats, aux_conn_rsp_err); - CONN_F_CONN_REQ_TXD(connsm) = 0; - CONN_F_AUX_CONN_REQ(connsm) = 0; - ble_ll_sched_rmv_elem(&connsm->conn_sch); - } - goto init_rx_isr_exit; - } -#endif - - inita_is_rpa = 0; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) { - if (!scansm->ext_scanning) { - goto init_rx_isr_exit; - } - - rc = ble_ll_scan_update_aux_data(ble_hdr, rxbuf, NULL); - if (rc < 0) { - /* No memory or broken packet */ - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID; - goto init_rx_isr_exit; - } - } -#endif - - /* Lets get addresses from advertising report*/ - if (ble_ll_scan_adv_decode_addr(pdu_type, rxbuf, ble_hdr, - &adv_addr, &adv_addr_type, - &init_addr, &init_addr_type, - &ext_adv_mode)) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID; -#endif - goto init_rx_isr_exit; - } - - switch (pdu_type) { - case BLE_ADV_PDU_TYPE_ADV_IND: - break; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - case BLE_ADV_PDU_TYPE_ADV_EXT_IND: - rc = -1; - - /* If this is not connectable adv mode, lets skip it */ - if (!(ext_adv_mode & BLE_LL_EXT_ADV_MODE_CONN)) { - goto init_rx_isr_exit; - } - - if (!adv_addr) { - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_PTR_WAIT; - goto init_rx_isr_exit; - } - - if (!init_addr) { - break; - } - /* if there is direct address lets fall down and check it.*/ - // no break -#endif - case BLE_ADV_PDU_TYPE_ADV_DIRECT_IND: - inita_is_rpa = (uint8_t)ble_ll_is_rpa(init_addr, init_addr_type); - if (!inita_is_rpa) { - - /* Resolving will be done later. Check if identity InitA matches */ - if (!ble_ll_is_our_devaddr(init_addr, init_addr_type)) { - goto init_rx_isr_exit; - } - } -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - else { - /* If privacy is off - reject RPA InitA*/ - goto init_rx_isr_exit; - } -#endif - - break; - default: - goto init_rx_isr_exit; - } - - /* Should we send a connect request? */ - index = -1; - peer = adv_addr; - peer_addr_type = adv_addr_type; - - resolved = 0; - chk_wl = ble_ll_scan_whitelist_enabled(); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (ble_ll_is_rpa(adv_addr, adv_addr_type) && ble_ll_resolv_enabled()) { - index = ble_hw_resolv_list_match(); - if (index >= 0) { - rl = &g_ble_ll_resolv_list[index]; - - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_RESOLVED; - connsm->rpa_index = index; - peer = rl->rl_identity_addr; - peer_addr_type = rl->rl_addr_type; - resolved = 1; - - /* Assure privacy */ - if ((rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && init_addr && - !inita_is_rpa && rl->rl_has_local) { - goto init_rx_isr_exit; - } - - /* - * If the InitA is a RPA, we must see if it resolves based on the - * identity address of the resolved ADVA. - */ - if (init_addr && inita_is_rpa) { - if (!ble_ll_resolv_rpa(init_addr, - g_ble_ll_resolv_list[index].rl_local_irk)) { - goto init_rx_isr_exit; - } - - /* Core Specification Vol 6, Part B, Section 6.4: - * "The Link Layer should not set the InitA field to the same - * value as the TargetA field in the received advertising PDU." - * - * We update the received PDU directly here, so ble_ll_init_rx_pkt_in - * can process it as is. - */ - memcpy(init_addr, rl->rl_local_rpa, BLE_DEV_ADDR_LEN); - } - - } else { - if (chk_wl) { - goto init_rx_isr_exit; - } - - /* Could not resolved InitA */ - if (init_addr && inita_is_rpa) { - goto init_rx_isr_exit; - } - } - } else if (init_addr) { - - /* If resolving is off and InitA is RPA we reject advertising */ - if (inita_is_rpa && !ble_ll_resolv_enabled()) { - goto init_rx_isr_exit; - } - - /* Let's see if we have IRK with that peer.*/ - rl = ble_ll_resolv_list_find(adv_addr, adv_addr_type); - - /* Lets make sure privacy mode is correct together with InitA in case it - * is identity address - */ - if (rl && !inita_is_rpa && - (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && - rl->rl_has_local) { - goto init_rx_isr_exit; - } - - /* - * If the InitA is a RPA, we must see if it resolves based on the - * identity address of the resolved ADVA. - */ - if (inita_is_rpa) { - if (!rl || !ble_ll_resolv_rpa(init_addr, rl->rl_local_irk)) { - goto init_rx_isr_exit; - } - - /* Core Specification Vol 6, Part B, Section 6.4: - * "The Link Layer should not set the InitA field to the same - * value as the TargetA field in the received advertising PDU." - * - * We update the received PDU directly here, so ble_ll_init_rx_pkt_in - * can process it as is. - */ - memcpy(init_addr, rl->rl_local_rpa, BLE_DEV_ADDR_LEN); - } - } else if (!ble_ll_is_rpa(adv_addr, adv_addr_type)) { - /* undirected with ID address, assure privacy if on RL */ - rl = ble_ll_resolv_list_find(adv_addr, adv_addr_type); - if (rl && (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && - rl->rl_has_peer) { - goto init_rx_isr_exit; - } - } -#endif - - /* Check filter policy */ - if (chk_wl) { - if (!ble_ll_whitelist_match(peer, peer_addr_type, resolved)) { - goto init_rx_isr_exit; - } - } else { - /* Must match the connection address */ - if (!ble_ll_conn_is_peer_adv(adv_addr_type, adv_addr, index)) { - goto init_rx_isr_exit; - } - } - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_DEVMATCH; - - /* For CONNECT_IND we don't go into RX state */ - conn_req_end_trans = BLE_PHY_TRANSITION_NONE; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* Check if we should send AUX_CONNECT_REQ and wait for AUX_CONNECT_RSP */ - if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) { - conn_req_end_trans = BLE_PHY_TRANSITION_TX_RX; - } - - if (connsm->scansm->ext_scanning) { - phy = ble_hdr->rxinfo.phy; - - /* Update connection state machine with appropriate parameters for - * certain PHY - */ - ble_ll_conn_ext_set_params(connsm, - &connsm->initial_params.params[phy - 1], - phy); - - } -#endif - - /* Schedule new connection */ - if (ble_ll_sched_master_new(connsm, ble_hdr, pyld_len)) { - STATS_INC(ble_ll_conn_stats, cant_set_sched); - goto init_rx_isr_exit; - } - - /* Prepare data for connect request */ - ble_ll_conn_connect_ind_prepare(connsm, - ble_ll_scan_get_pdu_data(), - adv_addr_type, adv_addr, - init_addr_type, init_addr, - index, ble_hdr->rxinfo.channel); - - /* Setup to transmit the connect request */ - rc = ble_ll_conn_connect_ind_send(connsm, conn_req_end_trans); - if (rc) { - ble_ll_sched_rmv_elem(&connsm->conn_sch); - goto init_rx_isr_exit; - } - - if (init_addr && !inita_is_rpa) { - connsm->inita_identity_used = 1; - } - - CONN_F_CONN_REQ_TXD(connsm) = 1; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) { - /* Lets wait for AUX_CONNECT_RSP */ - CONN_F_AUX_CONN_REQ(connsm) = 1; - /* Keep aux data until we get scan response */ - scansm->cur_aux_data = ble_hdr->rxinfo.user_data; - ble_hdr->rxinfo.user_data = NULL; - STATS_INC(ble_ll_stats, aux_conn_req_tx); - } -#endif - - STATS_INC(ble_ll_conn_stats, conn_req_txd); - -init_rx_isr_exit: - - /* - * We have to restart receive if we cant hand up pdu. We return 0 so that - * the phy does not get disabled. - */ - rxpdu = ble_ll_rxpdu_alloc(pyld_len + BLE_LL_PDU_HDR_LEN); - if (rxpdu == NULL) { - /* - * XXX: possible allocate the PDU when we start initiating? - * I cannot say I like this solution, but if we cannot allocate a PDU - * to hand up to the LL, we need to remove the connection we just - * scheduled since the connection state machine will not get processed - * by link layer properly. For now, just remove it from the scheduler - */ - if (CONN_F_CONN_REQ_TXD(connsm) == 1) { - CONN_F_CONN_REQ_TXD(connsm) = 0; - CONN_F_AUX_CONN_REQ(connsm) = 0; - ble_ll_sched_rmv_elem(&connsm->conn_sch); - } - ble_phy_restart_rx(); - rc = 0; - } else { - ble_phy_rxpdu_copy(rxbuf, rxpdu); - ble_ll_rx_pdu_in(rxpdu); - } - - if (rc) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - } - - return rc; -} - -/** - * Function called when a timeout has occurred for a connection. There are - * two types of timeouts: a connection supervision timeout and control - * procedure timeout. - * - * Context: Link Layer task - * - * @param connsm - * @param ble_err - */ -void -ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err) -{ - int was_current; - os_sr_t sr; - - was_current = 0; - OS_ENTER_CRITICAL(sr); - if (g_ble_ll_conn_cur_sm == connsm) { - ble_ll_conn_current_sm_over(NULL); - was_current = 1; - } - OS_EXIT_CRITICAL(sr); - - /* Check if we need to resume scanning */ - if (was_current) { - ble_ll_scan_chk_resume(); - } - - ble_ll_conn_end(connsm, ble_err); -} - -/** - * Called when a data channel PDU has started that matches the access - * address of the current connection. Note that the CRC of the PDU has not - * been checked yet. - * - * Context: Interrupt - * - * @param rxhdr - */ -int -ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa) -{ - struct ble_ll_conn_sm *connsm; - - /* - * Disable wait for response timer since we receive a response. We dont - * care if this is the response we were waiting for or not; the code - * called at receive end will deal with ending the connection event - * if needed - */ - connsm = g_ble_ll_conn_cur_sm; - if (connsm) { - /* Double check access address. Better match connection state machine */ - if (aa != connsm->access_addr) { - STATS_INC(ble_ll_conn_stats, rx_data_pdu_bad_aa); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - ble_ll_event_send(&connsm->conn_ev_end); - g_ble_ll_conn_cur_sm = NULL; - return -1; - } - - /* Set connection handle in mbuf header */ - rxhdr->rxinfo.handle = connsm->conn_handle; - - /* Set flag denoting we have received a packet in connection event */ - connsm->csmflags.cfbit.pkt_rxd = 1; - - /* Connection is established */ - connsm->conn_state = BLE_LL_CONN_STATE_ESTABLISHED; - - /* Set anchor point (and last) if 1st rxd frame in connection event */ - if (connsm->csmflags.cfbit.slave_set_last_anchor) { - connsm->csmflags.cfbit.slave_set_last_anchor = 0; - connsm->last_anchor_point = rxhdr->beg_cputime; - connsm->anchor_point = connsm->last_anchor_point; - connsm->anchor_point_usecs = rxhdr->rem_usecs; - } - } - return 1; -} - -/** - * Called from the Link Layer task when a data PDU has been received - * - * Context: Link layer task - * - * @param rxpdu Pointer to received pdu - * @param rxpdu Pointer to ble mbuf header of received pdu - */ -void -ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) -{ - uint8_t hdr_byte; - uint8_t rxd_sn; - uint8_t *rxbuf; - uint8_t llid; - uint16_t acl_len; - uint16_t acl_hdr; - struct ble_ll_conn_sm *connsm; - - /* Packets with invalid CRC are not sent to LL */ - BLE_LL_ASSERT(BLE_MBUF_HDR_CRC_OK(hdr)); - - /* XXX: there is a chance that the connection was thrown away and - re-used before processing packets here. Fix this. */ - /* We better have a connection state machine */ - connsm = ble_ll_conn_find_active_conn(hdr->rxinfo.handle); - if (!connsm) { - STATS_INC(ble_ll_conn_stats, no_conn_sm); - goto conn_rx_data_pdu_end; - } - - /* Check state machine */ - ble_ll_conn_chk_csm_flags(connsm); - - /* Validate rx data pdu */ - rxbuf = rxpdu->om_data; - hdr_byte = rxbuf[0]; - acl_len = rxbuf[1]; - llid = hdr_byte & BLE_LL_DATA_HDR_LLID_MASK; - - /* - * Check that the LLID and payload length are reasonable. - * Empty payload is only allowed for LLID == 01b. - * */ - if ((llid == 0) || ((acl_len == 0) && (llid != BLE_LL_LLID_DATA_FRAG))) { - STATS_INC(ble_ll_conn_stats, rx_bad_llid); - goto conn_rx_data_pdu_end; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - /* Check if PDU is allowed when encryption is started. If not, - * terminate connection. - * - * Reference: Core 5.0, Vol 6, Part B, 5.1.3.1 - */ - if ((connsm->enc_data.enc_state > CONN_ENC_S_PAUSE_ENC_RSP_WAIT && - CONN_IS_MASTER(connsm)) || - (connsm->enc_data.enc_state >= CONN_ENC_S_ENC_RSP_TO_BE_SENT && - CONN_IS_SLAVE(connsm))) { - if (!ble_ll_ctrl_enc_allowed_pdu_rx(rxpdu)) { - ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC); - goto conn_rx_data_pdu_end; - } - } -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) - /* - * Reset authenticated payload timeout if valid MIC. NOTE: we dont - * check the MIC failure bit as that would have terminated the - * connection - */ - if ((connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED) && - CONN_F_LE_PING_SUPP(connsm) && (acl_len != 0)) { - ble_ll_conn_auth_pyld_timer_start(connsm); - } -#endif - - /* Update RSSI */ - connsm->conn_rssi = hdr->rxinfo.rssi; - - /* - * If we are a slave, we can only start to use slave latency - * once we have received a NESN of 1 from the master - */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - if (hdr_byte & BLE_LL_DATA_HDR_NESN_MASK) { - connsm->csmflags.cfbit.allow_slave_latency = 1; - } - } - - /* - * Discard the received PDU if the sequence number is the same - * as the last received sequence number - */ - rxd_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK; - if (rxd_sn == connsm->last_rxd_sn) { - STATS_INC(ble_ll_conn_stats, data_pdu_rx_dup); - goto conn_rx_data_pdu_end; - } - - /* Update last rxd sn */ - connsm->last_rxd_sn = rxd_sn; - - /* No need to do anything if empty pdu */ - if ((llid == BLE_LL_LLID_DATA_FRAG) && (acl_len == 0)) { - goto conn_rx_data_pdu_end; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - /* - * XXX: should we check to see if we are in a state where we - * might expect to get an encrypted PDU? - */ - if (BLE_MBUF_HDR_MIC_FAILURE(hdr)) { - STATS_INC(ble_ll_conn_stats, mic_failures); - ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC); - goto conn_rx_data_pdu_end; - } -#endif - - if (llid == BLE_LL_LLID_CTRL) { - /* Process control frame */ - STATS_INC(ble_ll_conn_stats, rx_ctrl_pdus); - if (ble_ll_ctrl_rx_pdu(connsm, rxpdu)) { - STATS_INC(ble_ll_conn_stats, rx_malformed_ctrl_pdus); - } - } else { - /* Count # of received l2cap frames and byes */ - STATS_INC(ble_ll_conn_stats, rx_l2cap_pdus); - STATS_INCN(ble_ll_conn_stats, rx_l2cap_bytes, acl_len); - - /* NOTE: there should be at least two bytes available */ - BLE_LL_ASSERT(OS_MBUF_LEADINGSPACE(rxpdu) >= 2); - os_mbuf_prepend(rxpdu, 2); - rxbuf = rxpdu->om_data; - - acl_hdr = (llid << 12) | connsm->conn_handle; - put_le16(rxbuf, acl_hdr); - put_le16(rxbuf + 2, acl_len); - ble_hci_trans_ll_acl_tx(rxpdu); - } - - /* NOTE: we dont free the mbuf since we handed it off! */ - return; - - /* Free buffer */ -conn_rx_data_pdu_end: -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) - /* Need to give credit back if we allocated one for this PDU */ - if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_CONN_CREDIT) { - ble_ll_conn_cth_flow_free_credit(connsm, 1); - } -#endif - - os_mbuf_free_chain(rxpdu); -} - -/** - * Called when a packet has been received while in the connection state. - * - * Context: Interrupt - * - * @param rxpdu - * @param crcok - * - * @return int - * < 0: Disable the phy after reception. - * == 0: Success. Do not disable the PHY. - * > 0: Do not disable PHY as that has already been done. - */ -int -ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) -{ - int rc; - uint8_t hdr_byte; - uint8_t hdr_sn; - uint8_t hdr_nesn; - uint8_t conn_sn; - uint8_t conn_nesn; - uint8_t reply; - uint8_t rem_bytes; - uint8_t opcode = 0; - uint8_t rx_pyld_len; - uint32_t begtime; - uint32_t add_usecs; - struct os_mbuf *txpdu; - struct ble_ll_conn_sm *connsm; - struct os_mbuf *rxpdu = NULL; - struct ble_mbuf_hdr *txhdr; - int rx_phy_mode; - bool alloc_rxpdu = true; - - rc = -1; - connsm = g_ble_ll_conn_cur_sm; - - /* Retrieve the header and payload length */ - hdr_byte = rxbuf[0]; - rx_pyld_len = rxbuf[1]; - - /* - * No need to alloc rxpdu for packets with invalid CRC, we would throw them - * away instantly from LL anyway. - */ - if (!BLE_MBUF_HDR_CRC_OK(rxhdr)) { - alloc_rxpdu = false; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) - /* - * If flow control is enabled, we need to have credit available for each - * non-empty data packet that LL may send to host. If there are no credits - * available, we don't need to allocate buffer for this packet so LL will - * nak it. - */ - if (alloc_rxpdu && ble_ll_conn_cth_flow_is_enabled() && - BLE_LL_LLID_IS_DATA(hdr_byte) && (rx_pyld_len > 0)) { - if (ble_ll_conn_cth_flow_alloc_credit(connsm)) { - rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONN_CREDIT; - } else { - alloc_rxpdu = false; - } - } -#endif - - /* - * We need to attempt to allocate a buffer here. The reason we do this - * now is that we should not ack the packet if we have no receive - * buffers available. We want to free up our transmit PDU if it was - * acked, but we should not ack the received frame if we cant hand it up. - * NOTE: we hand up empty pdu's to the LL task! - */ - if (alloc_rxpdu) { - rxpdu = ble_ll_rxpdu_alloc(rx_pyld_len + BLE_LL_PDU_HDR_LEN); - } - - /* - * We should have a current connection state machine. If we dont, we just - * hand the packet to the higher layer to count it. - */ - if (!connsm) { - STATS_INC(ble_ll_conn_stats, rx_data_pdu_no_conn); - goto conn_exit; - } - - /* - * Calculate the end time of the received PDU. NOTE: this looks strange - * but for the 32768 crystal we add the time it takes to send the packet - * to the 'additional usecs' field to save some calculations. - */ - begtime = rxhdr->beg_cputime; -#if BLE_LL_BT5_PHY_SUPPORTED - rx_phy_mode = connsm->phy_data.rx_phy_mode; -#else - rx_phy_mode = BLE_PHY_MODE_1M; -#endif - add_usecs = rxhdr->rem_usecs + - ble_ll_pdu_tx_time_get(rx_pyld_len, rx_phy_mode); - - /* - * Check the packet CRC. A connection event can continue even if the - * received PDU does not pass the CRC check. If we receive two consecutive - * CRC errors we end the conection event. - */ - if (!BLE_MBUF_HDR_CRC_OK(rxhdr)) { - /* - * Increment # of consecutively received CRC errors. If more than - * one we will end the connection event. - */ - ++connsm->cons_rxd_bad_crc; - if (connsm->cons_rxd_bad_crc >= 2) { - reply = 0; - } else { - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - reply = CONN_F_LAST_TXD_MD(connsm); - } else { - /* A slave always responds with a packet */ - reply = 1; - } - } - } else { - /* Reset consecutively received bad crcs (since this one was good!) */ - connsm->cons_rxd_bad_crc = 0; - - /* Set last valid received pdu time (resets supervision timer) */ - connsm->last_rxd_pdu_cputime = begtime + - os_cputime_usecs_to_ticks(add_usecs); - - /* - * Check for valid LLID before proceeding. We have seen some weird - * things with the PHY where the CRC is OK but we dont have a valid - * LLID. This should really never happen but if it does we will just - * bail. An error stat will get incremented at the LL. - */ - if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == 0) { - goto conn_exit; - } - - /* Set last received header byte */ - connsm->last_rxd_hdr_byte = hdr_byte; - - if (BLE_LL_LLID_IS_CTRL(hdr_byte)) { - opcode = rxbuf[2]; - } - - /* - * If SN bit from header does not match NESN in connection, this is - * a resent PDU and should be ignored. - */ - hdr_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK; - conn_nesn = connsm->next_exp_seqnum; - if (rxpdu && ((hdr_sn && conn_nesn) || (!hdr_sn && !conn_nesn))) { - connsm->next_exp_seqnum ^= 1; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (CONN_F_ENCRYPTED(connsm) && !ble_ll_conn_is_empty_pdu(rxbuf)) { - ++connsm->enc_data.rx_pkt_cntr; - } -#endif - } - - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_CONN_RX, connsm->tx_seqnum, - !!(hdr_byte & BLE_LL_DATA_HDR_NESN_MASK)); - - /* - * Check NESN bit from header. If same as tx seq num, the transmission - * is acknowledged. Otherwise we need to resend this PDU. - */ - if (CONN_F_EMPTY_PDU_TXD(connsm) || connsm->cur_tx_pdu) { - hdr_nesn = hdr_byte & BLE_LL_DATA_HDR_NESN_MASK; - conn_sn = connsm->tx_seqnum; - if ((hdr_nesn && conn_sn) || (!hdr_nesn && !conn_sn)) { - /* We did not get an ACK. Must retry the PDU */ - STATS_INC(ble_ll_conn_stats, data_pdu_txf); - } else { - /* Transmit success */ - connsm->tx_seqnum ^= 1; - STATS_INC(ble_ll_conn_stats, data_pdu_txg); - - /* If we transmitted the empty pdu, clear flag */ - if (CONN_F_EMPTY_PDU_TXD(connsm)) { - CONN_F_EMPTY_PDU_TXD(connsm) = 0; - goto chk_rx_terminate_ind; - } - - /* - * Determine if we should remove packet from queue or if there - * are more fragments to send. - */ - txpdu = connsm->cur_tx_pdu; - if (txpdu) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (connsm->enc_data.tx_encrypted) { - ++connsm->enc_data.tx_pkt_cntr; - } -#endif - txhdr = BLE_MBUF_HDR_PTR(txpdu); - if ((txhdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) - == BLE_LL_LLID_CTRL) { - connsm->cur_tx_pdu = NULL; - /* Note: the mbuf is freed by this call */ - rc = ble_ll_ctrl_tx_done(txpdu, connsm); - if (rc) { - /* Means we transmitted a TERMINATE_IND */ - goto conn_exit; - } else { - goto chk_rx_terminate_ind; - } - } - - /* Increment offset based on number of bytes sent */ - txhdr->txinfo.offset += txhdr->txinfo.pyld_len; - if (txhdr->txinfo.offset >= OS_MBUF_PKTLEN(txpdu)) { - /* If l2cap pdu, increment # of completed packets */ - if (txhdr->txinfo.pyld_len != 0) { -#if (BLETEST_THROUGHPUT_TEST == 1) - bletest_completed_pkt(connsm->conn_handle); -#endif - ++connsm->completed_pkts; - if (connsm->completed_pkts > 2) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, - &g_ble_ll_data.ll_comp_pkt_ev); - } - } - os_mbuf_free_chain(txpdu); - connsm->cur_tx_pdu = NULL; - } else { - rem_bytes = OS_MBUF_PKTLEN(txpdu) - txhdr->txinfo.offset; - /* Adjust payload for max TX time and octets */ - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - if (BLE_LL_LLID_IS_CTRL(hdr_byte) && - (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && - (opcode == BLE_LL_CTRL_PHY_UPDATE_IND)) { - connsm->phy_tx_transition = - ble_ll_ctrl_phy_tx_transition_get(rxbuf[3]); - } -#endif - - rem_bytes = ble_ll_conn_adjust_pyld_len(connsm, rem_bytes); - txhdr->txinfo.pyld_len = rem_bytes; - } - } - } - } - - /* Should we continue connection event? */ - /* If this is a TERMINATE_IND, we have to reply */ -chk_rx_terminate_ind: - /* If we received a terminate IND, we must set some flags */ - if (BLE_LL_LLID_IS_CTRL(hdr_byte) && - (opcode == BLE_LL_CTRL_TERMINATE_IND) && - (rx_pyld_len == (1 + BLE_LL_CTRL_TERMINATE_IND_LEN))) { - connsm->csmflags.cfbit.terminate_ind_rxd = 1; - connsm->rxd_disconnect_reason = rxbuf[3]; - } - - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - reply = CONN_F_LAST_TXD_MD(connsm) || (hdr_byte & BLE_LL_DATA_HDR_MD_MASK); - } else { - /* A slave always replies */ - reply = 1; - } - } - - /* If reply flag set, send data pdu and continue connection event */ - rc = -1; - if (rx_pyld_len && CONN_F_ENCRYPTED(connsm)) { - rx_pyld_len += BLE_LL_DATA_MIC_LEN; - } - if (reply && ble_ll_conn_can_send_next_pdu(connsm, begtime, add_usecs)) { - rc = ble_ll_conn_tx_pdu(connsm); - } - -conn_exit: - /* Copy the received pdu and hand it up */ - if (rxpdu) { - ble_phy_rxpdu_copy(rxbuf, rxpdu); - ble_ll_rx_pdu_in(rxpdu); - } - - /* Send link layer a connection end event if over */ - if (rc) { - ble_ll_conn_current_sm_over(connsm); - } - - return rc; -} - -/** - * Called to adjust payload length to fit into max effective octets and TX time - * on current PHY. - */ -/** - * Called to enqueue a packet on the transmit queue of a connection. Should - * only be called by the controller. - * - * Context: Link Layer - * - * - * @param connsm - * @param om - */ -void -ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om, - uint8_t hdr_byte, uint8_t length) -{ - os_sr_t sr; - struct os_mbuf_pkthdr *pkthdr; - struct ble_mbuf_hdr *ble_hdr; - int lifo; - - /* Set mbuf length and packet length if a control PDU */ - if (hdr_byte == BLE_LL_LLID_CTRL) { - om->om_len = length; - OS_MBUF_PKTHDR(om)->omp_len = length; - } - - /* Set BLE transmit header */ - ble_hdr = BLE_MBUF_HDR_PTR(om); - ble_hdr->txinfo.flags = 0; - ble_hdr->txinfo.offset = 0; - ble_hdr->txinfo.hdr_byte = hdr_byte; - - /* - * Initial payload length is calculate when packet is dequeued, there's no - * need to do this now. - */ - - lifo = 0; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) { - uint8_t llid; - - /* - * If this is one of the following types we need to insert it at - * head of queue. - */ - llid = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK; - if (llid == BLE_LL_LLID_CTRL) { - switch (om->om_data[0]) { - case BLE_LL_CTRL_TERMINATE_IND: - case BLE_LL_CTRL_REJECT_IND: - case BLE_LL_CTRL_REJECT_IND_EXT: - case BLE_LL_CTRL_START_ENC_REQ: - case BLE_LL_CTRL_START_ENC_RSP: - lifo = 1; - break; - case BLE_LL_CTRL_PAUSE_ENC_RSP: - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - lifo = 1; - } - break; - case BLE_LL_CTRL_ENC_REQ: - case BLE_LL_CTRL_ENC_RSP: - /* If encryption has been paused, we don't want to send any packets from the - * TX queue, as they would go unencrypted. - */ - if (connsm->enc_data.enc_state == CONN_ENC_S_PAUSED) { - lifo = 1; - } - break; - default: - break; - } - } - } -#endif - - /* Add to transmit queue for the connection */ - pkthdr = OS_MBUF_PKTHDR(om); - OS_ENTER_CRITICAL(sr); - if (lifo) { - STAILQ_INSERT_HEAD(&connsm->conn_txq, pkthdr, omp_next); - } else { - STAILQ_INSERT_TAIL(&connsm->conn_txq, pkthdr, omp_next); - } - OS_EXIT_CRITICAL(sr); -} - -/** - * Data packet from host. - * - * Context: Link Layer task - * - * @param om - * @param handle - * @param length - * - * @return int - */ -void -ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t length) -{ - uint8_t hdr_byte; - uint16_t conn_handle; - uint16_t pb; - struct ble_ll_conn_sm *connsm; - - /* See if we have an active matching connection handle */ - conn_handle = handle & 0x0FFF; - connsm = ble_ll_conn_find_active_conn(conn_handle); - if (connsm) { - /* Construct LL header in buffer (NOTE: pb already checked) */ - pb = handle & 0x3000; - if (pb == 0) { - hdr_byte = BLE_LL_LLID_DATA_START; - } else { - hdr_byte = BLE_LL_LLID_DATA_FRAG; - } - - /* Add to total l2cap pdus enqueue */ - STATS_INC(ble_ll_conn_stats, l2cap_enqueued); - - /* Clear flags field in BLE header */ - ble_ll_conn_enqueue_pkt(connsm, om, hdr_byte, length); - } else { - /* No connection found! */ - STATS_INC(ble_ll_conn_stats, handle_not_found); - os_mbuf_free_chain(om); - } -} - -/** - * Called to set the global channel mask that we use for all connections. - * - * @param num_used_chans - * @param chanmap - */ -void -ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, const uint8_t *chanmap) -{ - struct ble_ll_conn_sm *connsm; - struct ble_ll_conn_global_params *conn_params; - - /* Do nothing if same channel map */ - conn_params = &g_ble_ll_conn_params; - if (!memcmp(conn_params->master_chan_map, chanmap, BLE_LL_CONN_CHMAP_LEN)) { - return; - } - - /* Change channel map and cause channel map update procedure to start */ - conn_params->num_used_chans = num_used_chans; - memcpy(conn_params->master_chan_map, chanmap, BLE_LL_CONN_CHMAP_LEN); - - /* Perform channel map update */ - SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_CHAN_MAP_UPD); - } - } -} - -/** - * Called when a device has received a connect request while advertising and - * the connect request has passed the advertising filter policy and is for - * us. This will start a connection in the slave role assuming that we dont - * already have a connection with this device and that the connect request - * parameters are valid. - * - * Context: Link Layer - * - * @param rxbuf Pointer to received Connect Request PDU - * - * @return 0: connection not started; 1 connecton started - */ -int -ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr, - bool force_csa2) -{ - int rc; - uint32_t temp; - uint32_t crcinit; - uint8_t *inita; - uint8_t *dptr; - struct ble_ll_conn_sm *connsm; - - /* Ignore the connection request if we are already connected*/ - inita = rxbuf + BLE_LL_PDU_HDR_LEN; - SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) { - if (!memcmp(&connsm->peer_addr, inita, BLE_DEV_ADDR_LEN)) { - if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) { - if (connsm->peer_addr_type & 1) { - return 0; - } - } else { - if ((connsm->peer_addr_type & 1) == 0) { - return 0; - } - } - } - } - - /* Allocate a connection. If none available, dont do anything */ - connsm = ble_ll_conn_sm_get(); - if (connsm == NULL) { - return 0; - } - - /* Set the pointer at the start of the connection data */ - dptr = rxbuf + BLE_LL_CONN_REQ_ADVA_OFF + BLE_DEV_ADDR_LEN; - - /* Set connection state machine information */ - connsm->access_addr = get_le32(dptr); - crcinit = dptr[6]; - crcinit = (crcinit << 8) | dptr[5]; - crcinit = (crcinit << 8) | dptr[4]; - connsm->crcinit = crcinit; - connsm->tx_win_size = dptr[7]; - connsm->tx_win_off = get_le16(dptr + 8); - connsm->conn_itvl = get_le16(dptr + 10); - connsm->slave_latency = get_le16(dptr + 12); - connsm->supervision_tmo = get_le16(dptr + 14); - memcpy(&connsm->chanmap, dptr + 16, BLE_LL_CONN_CHMAP_LEN); - connsm->hop_inc = dptr[21] & 0x1F; - connsm->master_sca = dptr[21] >> 5; - - /* Error check parameters */ - if ((connsm->tx_win_off > connsm->conn_itvl) || - (connsm->conn_itvl < BLE_HCI_CONN_ITVL_MIN) || - (connsm->conn_itvl > BLE_HCI_CONN_ITVL_MAX) || - (connsm->tx_win_size < BLE_LL_CONN_TX_WIN_MIN) || - (connsm->slave_latency > BLE_LL_CONN_SLAVE_LATENCY_MAX)) { - goto err_slave_start; - } - - /* Slave latency cannot cause a supervision timeout */ - temp = (connsm->slave_latency + 1) * (connsm->conn_itvl * 2) * - BLE_LL_CONN_ITVL_USECS; - if ((connsm->supervision_tmo * 10000) <= temp ) { - goto err_slave_start; - } - - /* - * The transmit window must be less than or equal to the lesser of 10 - * msecs or the connection interval minus 1.25 msecs. - */ - temp = connsm->conn_itvl - 1; - if (temp > 8) { - temp = 8; - } - if (connsm->tx_win_size > temp) { - goto err_slave_start; - } - - /* Set the address of device that we are connecting with */ - memcpy(&connsm->peer_addr, inita, BLE_DEV_ADDR_LEN); - connsm->peer_addr_type = pat; - - /* Calculate number of used channels; make sure it meets min requirement */ - connsm->num_used_chans = ble_ll_utils_calc_num_used_chans(connsm->chanmap); - if (connsm->num_used_chans < 2) { - goto err_slave_start; - } - - /* Start the connection state machine */ - connsm->conn_role = BLE_LL_CONN_ROLE_SLAVE; - ble_ll_conn_sm_new(connsm); - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - /* Use the same PHY as we received CONNECT_REQ on */ - ble_ll_conn_init_phy(connsm, rxhdr->rxinfo.phy); -#endif - - ble_ll_conn_set_csa(connsm, - force_csa2 || (rxbuf[0] & BLE_ADV_PDU_HDR_CHSEL_MASK)); - - /* Set initial schedule callback */ - connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb; - rc = ble_ll_conn_created(connsm, rxhdr); - if (!rc) { - SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, act_sle); - STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); - } - return rc; - -err_slave_start: - STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); - STATS_INC(ble_ll_conn_stats, slave_rxd_bad_conn_req_params); - return 0; -} - -#define MAX_TIME_UNCODED(_maxbytes) \ - ble_ll_pdu_tx_time_get(_maxbytes + BLE_LL_DATA_MIC_LEN, \ - BLE_PHY_MODE_1M); -#define MAX_TIME_CODED(_maxbytes) \ - ble_ll_pdu_tx_time_get(_maxbytes + BLE_LL_DATA_MIC_LEN, \ - BLE_PHY_MODE_CODED_125KBPS); - -/** - * Called to reset the connection module. When this function is called the - * scheduler has been stopped and the phy has been disabled. The LL should - * be in the standby state. - * - * Context: Link Layer task - */ -void -ble_ll_conn_module_reset(void) -{ - uint8_t max_phy_pyld; - uint16_t maxbytes; - struct ble_ll_conn_sm *connsm; - struct ble_ll_conn_global_params *conn_params; - - /* Kill the current one first (if one is running) */ - if (g_ble_ll_conn_cur_sm) { - connsm = g_ble_ll_conn_cur_sm; - g_ble_ll_conn_cur_sm = NULL; - ble_ll_conn_end(connsm, BLE_ERR_SUCCESS); - } - - /* Free the global connection complete event if there is one */ - if (g_ble_ll_conn_comp_ev) { - ble_hci_trans_buf_free(g_ble_ll_conn_comp_ev); - g_ble_ll_conn_comp_ev = NULL; - } - - /* Reset connection we are attempting to create */ - g_ble_ll_conn_create_sm = NULL; - - /* Now go through and end all the connections */ - while (1) { - connsm = SLIST_FIRST(&g_ble_ll_conn_active_list); - if (!connsm) { - break; - } - ble_ll_conn_end(connsm, BLE_ERR_SUCCESS); - } - - /* Get the maximum supported PHY PDU size from the PHY */ - max_phy_pyld = ble_phy_max_data_pdu_pyld(); - - /* Configure the global LL parameters */ - conn_params = &g_ble_ll_conn_params; - - maxbytes = min(MYNEWT_VAL(BLE_LL_SUPP_MAX_RX_BYTES), max_phy_pyld); - conn_params->supp_max_rx_octets = maxbytes; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - conn_params->supp_max_rx_time = MAX_TIME_CODED(maxbytes); -#else - conn_params->supp_max_rx_time = MAX_TIME_UNCODED(maxbytes); -#endif - - maxbytes = min(MYNEWT_VAL(BLE_LL_SUPP_MAX_TX_BYTES), max_phy_pyld); - conn_params->supp_max_tx_octets = maxbytes; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - conn_params->supp_max_tx_time = MAX_TIME_CODED(maxbytes); -#else - conn_params->supp_max_tx_time = MAX_TIME_UNCODED(maxbytes); -#endif - - maxbytes = min(MYNEWT_VAL(BLE_LL_CONN_INIT_MAX_TX_BYTES), max_phy_pyld); - conn_params->conn_init_max_tx_octets = maxbytes; - conn_params->conn_init_max_tx_time = MAX_TIME_UNCODED(maxbytes); - conn_params->conn_init_max_tx_time_uncoded = MAX_TIME_UNCODED(maxbytes); - conn_params->conn_init_max_tx_time_coded = MAX_TIME_CODED(maxbytes); - - conn_params->sugg_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; - conn_params->sugg_tx_time = BLE_LL_CONN_SUPP_TIME_MIN; - - /* Mask in all channels by default */ - conn_params->num_used_chans = BLE_PHY_NUM_DATA_CHANS; - memset(conn_params->master_chan_map, 0xff, BLE_LL_CONN_CHMAP_LEN - 1); - conn_params->master_chan_map[4] = 0x1f; - - /* Reset statistics */ - STATS_RESET(ble_ll_conn_stats); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - /* reset default sync transfer params */ - g_ble_ll_conn_sync_transfer_params.max_skip = 0; - g_ble_ll_conn_sync_transfer_params.mode = 0; - g_ble_ll_conn_sync_transfer_params.sync_timeout_us = 0; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) - g_ble_ll_conn_cth_flow.enabled = false; - g_ble_ll_conn_cth_flow.max_buffers = 1; - g_ble_ll_conn_cth_flow.num_buffers = 1; -#endif -} - -/* Initialize the connection module */ -void -ble_ll_conn_module_init(void) -{ - int rc; - uint16_t i; - struct ble_ll_conn_sm *connsm; - - /* Initialize list of active conections */ - SLIST_INIT(&g_ble_ll_conn_active_list); - STAILQ_INIT(&g_ble_ll_conn_free_list); - - /* - * Take all the connections off the free memory pool and add them to - * the free connection list, assigning handles in linear order. Note: - * the specification allows a handle of zero; we just avoid using it. - */ - connsm = &g_ble_ll_conn_sm[0]; - for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) { - - memset(connsm, 0, sizeof(struct ble_ll_conn_sm)); - connsm->conn_handle = i + 1; - STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); - - /* Initialize fixed schedule elements */ - connsm->conn_sch.sched_type = BLE_LL_SCHED_TYPE_CONN; - connsm->conn_sch.cb_arg = connsm; - ++connsm; - } - - /* Register connection statistics */ - rc = stats_init_and_reg(STATS_HDR(ble_ll_conn_stats), - STATS_SIZE_INIT_PARMS(ble_ll_conn_stats, STATS_SIZE_32), - STATS_NAME_INIT_PARMS(ble_ll_conn_stats), - "ble_ll_conn"); - BLE_LL_ASSERT(rc == 0); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) - ble_npl_event_init(&g_ble_ll_conn_cth_flow_error_ev, - ble_ll_conn_cth_flow_error_fn, NULL); -#endif - - /* Call reset to finish reset of initialization */ - ble_ll_conn_module_reset(); -} - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_conn_hci.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_conn_hci.c deleted file mode 100644 index 78cac66f5..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_conn_hci.c +++ /dev/null @@ -1,1921 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "nimble/nimble/include/nimble/ble_hci_trans.h" -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_utils.h" -#include "../include/controller/ble_ll_hci.h" -#include "../include/controller/ble_ll_conn.h" -#include "../include/controller/ble_ll_ctrl.h" -#include "../include/controller/ble_ll_scan.h" -#include "../include/controller/ble_ll_adv.h" -#include "ble_ll_conn_priv.h" - -/* - * Used to limit the rate at which we send the number of completed packets - * event to the host. This is the os time at which we can send an event. - */ -static ble_npl_time_t g_ble_ll_last_num_comp_pkt_evt; -extern uint8_t *g_ble_ll_conn_comp_ev; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static const uint8_t ble_ll_valid_conn_phy_mask = (BLE_HCI_LE_PHY_1M_PREF_MASK -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - | BLE_HCI_LE_PHY_2M_PREF_MASK -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - | BLE_HCI_LE_PHY_CODED_PREF_MASK -#endif - ); -static const uint8_t ble_ll_conn_required_phy_mask = (BLE_HCI_LE_PHY_1M_PREF_MASK -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - | BLE_HCI_LE_PHY_CODED_PREF_MASK -#endif - ); -#endif - -/** - * Allocate an event to send a connection complete event when initiating - * - * @return int 0: success -1: failure - */ -static int -ble_ll_init_alloc_conn_comp_ev(void) -{ - int rc; - uint8_t *evbuf; - - rc = 0; - evbuf = g_ble_ll_conn_comp_ev; - if (evbuf == NULL) { - evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (!evbuf) { - rc = -1; - } else { - g_ble_ll_conn_comp_ev = evbuf; - } - } - - return rc; -} - -/** - * Called to check that the connection parameters are within range - * - * @param itvl_min - * @param itvl_max - * @param latency - * @param spvn_tmo - * - * @return int BLE_ERR_INV_HCI_CMD_PARMS if invalid parameters, 0 otherwise - */ -int -ble_ll_conn_hci_chk_conn_params(uint16_t itvl_min, uint16_t itvl_max, - uint16_t latency, uint16_t spvn_tmo) -{ - uint32_t spvn_tmo_usecs; - uint32_t min_spvn_tmo_usecs; - - if ((itvl_min > itvl_max) || - (itvl_min < BLE_HCI_CONN_ITVL_MIN) || - (itvl_max > BLE_HCI_CONN_ITVL_MAX) || - (latency > BLE_HCI_CONN_LATENCY_MAX) || - (spvn_tmo < BLE_HCI_CONN_SPVN_TIMEOUT_MIN) || - (spvn_tmo > BLE_HCI_CONN_SPVN_TIMEOUT_MAX)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* - * Supervision timeout (in msecs) must be more than: - * (1 + connLatency) * connIntervalMax * 1.25 msecs * 2. - */ - spvn_tmo_usecs = spvn_tmo; - spvn_tmo_usecs *= (BLE_HCI_CONN_SPVN_TMO_UNITS * 1000); - min_spvn_tmo_usecs = (uint32_t)itvl_max * 2 * BLE_LL_CONN_ITVL_USECS; - min_spvn_tmo_usecs *= (1 + latency); - if (spvn_tmo_usecs <= min_spvn_tmo_usecs) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return BLE_ERR_SUCCESS; -} - -/** - * Send a connection complete event - * - * @param status The BLE error code associated with the event - */ -void -ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status, - uint8_t *evbuf, struct ble_ll_adv_sm *advsm) -{ - struct ble_hci_ev_le_subev_enh_conn_complete *enh_ev; - struct ble_hci_ev_le_subev_conn_complete *ev; - struct ble_hci_ev *hci_ev = (void *) evbuf; - uint8_t *rpa; - - BLE_LL_ASSERT(evbuf); - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE)) { - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*enh_ev); - enh_ev = (void *) hci_ev->data; - - memset(enh_ev, 0, sizeof(*enh_ev)); - - enh_ev->subev_code = BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE; - enh_ev->status = status; - - if (connsm) { - enh_ev->conn_handle = htole16(connsm->conn_handle); - enh_ev->role = connsm->conn_role - 1; - enh_ev->peer_addr_type = connsm->peer_addr_type; - memcpy(enh_ev->peer_addr, connsm->peer_addr, BLE_DEV_ADDR_LEN); - - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - if (connsm->inita_identity_used) { - /* We used identity address in CONNECT_IND which can be just - * fine if - * a) it was direct advertising we replied to and remote uses - * its identity address in device privacy mode or IRK is all - * zeros. - * b) peer uses RPA and this is first time we connect to him - */ - rpa = NULL; - } else if (connsm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { - rpa = ble_ll_scan_get_local_rpa(); - } else { - rpa = NULL; - } - } else { - rpa = ble_ll_adv_get_local_rpa(advsm); - } - - if (rpa) { - memcpy(enh_ev->local_rpa, rpa, BLE_DEV_ADDR_LEN); - } - - /* We need to adjust peer type if device connected using RPA - * and was resolved since RPA needs to be added to HCI event. - */ - if (connsm->peer_addr_type < BLE_HCI_CONN_PEER_ADDR_PUBLIC_IDENT - && (connsm->rpa_index > -1)) { - enh_ev->peer_addr_type += 2; - } - - if (enh_ev->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_RANDOM) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - rpa = ble_ll_scan_get_peer_rpa(); - } else { - rpa = ble_ll_adv_get_peer_rpa(advsm); - } - memcpy(enh_ev->peer_rpa, rpa, BLE_DEV_ADDR_LEN); - } - - enh_ev->conn_itvl = htole16(connsm->conn_itvl); - enh_ev->conn_latency = htole16(connsm->slave_latency); - enh_ev->supervision_timeout = htole16(connsm->supervision_tmo); - enh_ev->mca = connsm->master_sca; - } - - ble_ll_hci_event_send(hci_ev); - return; - } - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CONN_COMPLETE)) { - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - memset(ev, 0, sizeof(*ev)); - - ev->subev_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; - ev->status = status; - - if (connsm) { - ev->conn_handle = htole16(connsm->conn_handle); - ev->role = connsm->conn_role - 1; - ev->peer_addr_type = connsm->peer_addr_type; - - if (ev->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_RANDOM) { - ev->peer_addr_type -= 2; - } - memcpy(ev->peer_addr, connsm->peer_addr, BLE_DEV_ADDR_LEN); - ev->conn_itvl = htole16(connsm->conn_itvl); - ev->conn_latency = htole16(connsm->slave_latency); - ev->supervision_timeout = htole16(connsm->supervision_tmo); - ev->mca = connsm->master_sca; - } - - ble_ll_hci_event_send(hci_ev); - return; - } - - ble_hci_trans_buf_free(evbuf); -} - -/** - * Called to create and send the number of completed packets event to the - * host. - */ -void -ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm) -{ - /** The maximum number of handles that will fit in an event buffer. */ - static const int max_handles = - (BLE_LL_MAX_EVT_LEN - sizeof(struct ble_hci_ev_num_comp_pkts) - 1) / 4; - struct ble_hci_ev_num_comp_pkts *ev; - struct ble_hci_ev *hci_ev; - int event_sent; - - if (connsm == NULL) { - goto skip_conn; - } - - /* - * At some periodic rate, make sure we go through all active connections - * and send the number of completed packet events. We do this mainly - * because the spec says we must update the host even though no packets - * have completed but there are data packets in the controller buffers - * (i.e. enqueued in a connection state machine). - */ - if ((ble_npl_stime_t)(ble_npl_time_get() - g_ble_ll_last_num_comp_pkt_evt) < - ble_npl_time_ms_to_ticks32(MYNEWT_VAL(BLE_LL_NUM_COMP_PKT_ITVL_MS))) { - /* - * If this connection has completed packets, send an event right away. - * We do this to increase throughput but we dont want to search the - * entire active list every time. - */ - if (connsm->completed_pkts) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_NUM_COMP_PKTS; - hci_ev->length = sizeof(*ev); - ev = (void *)hci_ev->data; - - ev->count = 1; - ev->completed[0].handle = htole16(connsm->conn_handle); - ev->completed[0].packets = htole16(connsm->completed_pkts); - hci_ev->length += sizeof(ev->completed[0]); - - connsm->completed_pkts = 0; - - ble_ll_hci_event_send(hci_ev); - } - } - return; - } - - /* Iterate through all the active, created connections */ -skip_conn: - hci_ev = NULL; - ev = NULL; - - event_sent = 0; - SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) { - /* - * Only look at connections that we have sent a connection complete - * event and that either has packets enqueued or has completed packets. - */ - if ((connsm->conn_state != BLE_LL_CONN_STATE_IDLE) && - (connsm->completed_pkts || !STAILQ_EMPTY(&connsm->conn_txq))) { - /* If no buffer, get one, If cant get one, leave. */ - if (!hci_ev) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (!hci_ev) { - break; - } - - hci_ev->opcode = BLE_HCI_EVCODE_NUM_COMP_PKTS; - hci_ev->length = sizeof(*ev); - ev = (void *)hci_ev->data; - - ev->count = 0; - } - - /* Add handle and complete packets */ - ev->completed[ev->count].handle = htole16(connsm->conn_handle); - ev->completed[ev->count].packets = htole16(connsm->completed_pkts); - hci_ev->length += sizeof(ev->completed[ev->count]); - ev->count++; - - connsm->completed_pkts = 0; - - /* Send now if the buffer is full. */ - if (ev->count == max_handles) { - ble_ll_hci_event_send(hci_ev); - hci_ev = NULL; - event_sent = 1; - } - } - } - - /* Send event if there is an event to send */ - if (hci_ev) { - ble_ll_hci_event_send(hci_ev); - event_sent = 1; - } - - if (event_sent) { - g_ble_ll_last_num_comp_pkt_evt = ble_npl_time_get(); - } -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) -/** - * Send a authenticated payload timeout event - * - * NOTE: we currently only send this event when we have a reason to send it; - * not when it fails. - * - * @param reason The BLE error code to send as a disconnect reason - */ -void -ble_ll_auth_pyld_tmo_event_send(struct ble_ll_conn_sm *connsm) -{ - struct ble_hci_ev_auth_pyld_tmo *ev; - struct ble_hci_ev *hci_ev; - - if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_AUTH_PYLD_TMO)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_AUTH_PYLD_TMO; - hci_ev->length = sizeof(*ev); - - ev = (void *) hci_ev->data; - ev->conn_handle = htole16(connsm->conn_handle); - - ble_ll_hci_event_send(hci_ev); - } - } -} -#endif - -/** - * Send a disconnection complete event. - * - * NOTE: we currently only send this event when we have a reason to send it; - * not when it fails. - * - * @param reason The BLE error code to send as a disconnect reason - */ -void -ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t reason) -{ - struct ble_hci_ev_disconn_cmp *ev; - struct ble_hci_ev *hci_ev; - - if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_DISCONN_CMP)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_DISCONN_CMP; - hci_ev->length = sizeof(*ev); - - ev = (void *) hci_ev->data; - - ev->status = BLE_ERR_SUCCESS; - ev->conn_handle = htole16(connsm->conn_handle); - ev->reason = reason; - - ble_ll_hci_event_send(hci_ev); - } - } -} - -static int -ble_ll_conn_hci_chk_scan_params(uint16_t itvl, uint16_t window) -{ - /* Check interval and window */ - if ((itvl < BLE_HCI_SCAN_ITVL_MIN) || - (itvl > BLE_HCI_SCAN_ITVL_MAX) || - (window < BLE_HCI_SCAN_WINDOW_MIN) || - (window > BLE_HCI_SCAN_WINDOW_MAX) || - (itvl < window)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return 0; -} - -/** - * Process the HCI command to create a connection. - * - * Context: Link Layer task (HCI command processing) - * - * @param cmdbuf - * - * @return int - */ -int -ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_create_conn_cp *cmd = (const void *) cmdbuf; - struct ble_ll_conn_sm *connsm; - struct hci_create_conn hcc = { 0 }; - int rc; - - if (len < sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* If we are already creating a connection we should leave */ - if (g_ble_ll_conn_create_sm) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* If already enabled, we return an error */ - if (ble_ll_scan_enabled()) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* Retrieve command data */ - hcc.scan_itvl = le16toh(cmd->scan_itvl); - hcc.scan_window = le16toh(cmd->scan_window); - - rc = ble_ll_conn_hci_chk_scan_params(hcc.scan_itvl, hcc.scan_window); - if (rc) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check filter policy */ - hcc.filter_policy = cmd->filter_policy; - if (hcc.filter_policy > BLE_HCI_INITIATOR_FILT_POLICY_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Get peer address type and address only if no whitelist used */ - if (hcc.filter_policy == 0) { - hcc.peer_addr_type = cmd->peer_addr_type; - if (hcc.peer_addr_type > BLE_HCI_CONN_PEER_ADDR_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - memcpy(&hcc.peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); - } - - /* Get own address type (used in connection request) */ - hcc.own_addr_type = cmd->own_addr_type; - if (hcc.own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check connection interval, latency and supervision timeoout */ - hcc.conn_itvl_min = le16toh(cmd->min_conn_itvl); - hcc.conn_itvl_max = le16toh(cmd->max_conn_itvl); - hcc.conn_latency = le16toh(cmd->conn_latency); - hcc.supervision_timeout = le16toh(cmd->tmo); - rc = ble_ll_conn_hci_chk_conn_params(hcc.conn_itvl_min, - hcc.conn_itvl_max, - hcc.conn_latency, - hcc.supervision_timeout); - if (rc) { - return rc; - } - - /* Min/max connection event lengths */ - hcc.min_ce_len = le16toh(cmd->min_ce); - hcc.max_ce_len = le16toh(cmd->max_ce); - if (hcc.min_ce_len > hcc.max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Make sure we can allocate an event to send the connection complete */ - if (ble_ll_init_alloc_conn_comp_ev()) { - return BLE_ERR_MEM_CAPACITY; - } - - /* Make sure we can accept a connection! */ - connsm = ble_ll_conn_sm_get(); - if (connsm == NULL) { - return BLE_ERR_CONN_LIMIT; - } - - /* Initialize state machine in master role and start state machine */ - ble_ll_conn_master_init(connsm, &hcc); - ble_ll_conn_sm_new(connsm); - /* CSA will be selected when advertising is received */ - - /* Start scanning */ - rc = ble_ll_scan_initiator_start(&hcc, &connsm->scansm); - if (rc) { - SLIST_REMOVE(&g_ble_ll_conn_active_list,connsm,ble_ll_conn_sm,act_sle); - STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); - } else { - /* Set the connection state machine we are trying to create. */ - g_ble_ll_conn_create_sm = connsm; - } - - return rc; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_conn_hcc_params_set_fallback(struct hci_ext_create_conn *hcc, - const struct hci_ext_conn_params *fallback) -{ - BLE_LL_ASSERT(fallback); - - if (!(hcc->init_phy_mask & BLE_PHY_MASK_1M)) { - hcc->params[0] = *fallback; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - if (!(hcc->init_phy_mask & BLE_PHY_MASK_2M)) { - hcc->params[1] = *fallback; - } -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - if (!(hcc->init_phy_mask & BLE_PHY_MASK_CODED)) { - hcc->params[2] = *fallback; - } -#endif -} - -int -ble_ll_ext_conn_create(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_ext_create_conn_cp *cmd = (const void *) cmdbuf; - const struct conn_params *params = cmd->conn_params; - const struct hci_ext_conn_params *fallback_params = NULL; - struct hci_ext_create_conn hcc = { 0 }; - struct ble_ll_conn_sm *connsm; - int rc; - - /* validate length */ - if (len < sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - len -= sizeof(*cmd); - - /* If we are already creating a connection we should leave */ - if (g_ble_ll_conn_create_sm) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* If already enabled, we return an error */ - if (ble_ll_scan_enabled()) { - return BLE_ERR_CMD_DISALLOWED; - } - - hcc.filter_policy = cmd->filter_policy; - if (hcc.filter_policy > BLE_HCI_INITIATOR_FILT_POLICY_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - hcc.own_addr_type = cmd->own_addr_type; - if (hcc.own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Validate peer address type only if no whitelist used */ - if (hcc.filter_policy == 0) { - hcc.peer_addr_type = cmd->peer_addr_type; - - if (hcc.peer_addr_type > BLE_HCI_CONN_PEER_ADDR_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - memcpy(hcc.peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); - } - - hcc.init_phy_mask = cmd->init_phy_mask; - if (hcc.init_phy_mask & ~ble_ll_valid_conn_phy_mask) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (!(hcc.init_phy_mask & ble_ll_conn_required_phy_mask)) { - /* At least one of those need to be set */ - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (hcc.init_phy_mask & BLE_PHY_MASK_1M) { - if (len < sizeof(*params)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - len -= sizeof(*params); - - hcc.params[0].scan_itvl = le16toh(params->scan_itvl); - hcc.params[0].scan_window = le16toh(params->scan_window); - - rc = ble_ll_conn_hci_chk_scan_params(hcc.params[0].scan_itvl, - hcc.params[0].scan_window); - if (rc) { - return rc; - } - - hcc.params[0].conn_itvl_min = le16toh(params->conn_min_itvl); - hcc.params[0].conn_itvl_max = le16toh(params->conn_min_itvl); - hcc.params[0].conn_latency = le16toh(params->conn_latency); - hcc.params[0].supervision_timeout = le16toh(params->supervision_timeout); - - rc = ble_ll_conn_hci_chk_conn_params(hcc.params[0].conn_itvl_min, - hcc.params[0].conn_itvl_max, - hcc.params[0].conn_latency, - hcc.params[0].supervision_timeout); - if (rc) { - return rc; - } - - /* Min/max connection event lengths */ - hcc.params[0].min_ce_len = le16toh(params->min_ce); - hcc.params[0].max_ce_len = le16toh(params->max_ce); - if (hcc.params[0].min_ce_len > hcc.params[0].max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - fallback_params = &hcc.params[0]; - params++; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - if (hcc.init_phy_mask & BLE_PHY_MASK_2M) { - if (len < sizeof(*params)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - len -= sizeof(*params); - - hcc.params[1].conn_itvl_min = le16toh(params->conn_min_itvl); - hcc.params[1].conn_itvl_max = le16toh(params->conn_min_itvl); - hcc.params[1].conn_latency = le16toh(params->conn_latency); - hcc.params[1].supervision_timeout = le16toh(params->supervision_timeout); - - rc = ble_ll_conn_hci_chk_conn_params(hcc.params[1].conn_itvl_min, - hcc.params[1].conn_itvl_max, - hcc.params[1].conn_latency, - hcc.params[1].supervision_timeout); - if (rc) { - return rc; - } - - /* Min/max connection event lengths */ - hcc.params[1].min_ce_len = le16toh(params->min_ce); - hcc.params[1].max_ce_len = le16toh(params->max_ce); - if (hcc.params[1].min_ce_len > hcc.params[1].max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - params++; - } -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - if (hcc.init_phy_mask & BLE_PHY_MASK_CODED) { - if (len < sizeof(*params)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - len -= sizeof(*params); - - hcc.params[2].scan_itvl = le16toh(params->scan_itvl); - hcc.params[2].scan_window = le16toh(params->scan_window); - - rc = ble_ll_conn_hci_chk_scan_params(hcc.params[2].scan_itvl, - hcc.params[2].scan_window); - if (rc) { - return rc; - } - - hcc.params[2].conn_itvl_min = le16toh(params->conn_min_itvl); - hcc.params[2].conn_itvl_max = le16toh(params->conn_min_itvl); - hcc.params[2].conn_latency = le16toh(params->conn_latency); - hcc.params[2].supervision_timeout = le16toh(params->supervision_timeout); - - rc = ble_ll_conn_hci_chk_conn_params(hcc.params[2].conn_itvl_min, - hcc.params[2].conn_itvl_max, - hcc.params[2].conn_latency, - hcc.params[2].supervision_timeout); - if (rc) { - return rc; - } - - /* Min/max connection event lengths */ - hcc.params[2].min_ce_len = le16toh(params->min_ce); - hcc.params[2].max_ce_len = le16toh(params->max_ce); - if (hcc.params[2].min_ce_len > hcc.params[2].max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (!fallback_params) { - fallback_params = &hcc.params[2]; - } - params++; - } -#endif - - /* Make sure we can allocate an event to send the connection complete */ - if (ble_ll_init_alloc_conn_comp_ev()) { - return BLE_ERR_MEM_CAPACITY; - } - - /* Make sure we can accept a connection! */ - connsm = ble_ll_conn_sm_get(); - if (connsm == NULL) { - return BLE_ERR_CONN_LIMIT; - } - - ble_ll_conn_hcc_params_set_fallback(&hcc, fallback_params); - - /* Initialize state machine in master role and start state machine */ - ble_ll_conn_ext_master_init(connsm, &hcc); - ble_ll_conn_sm_new(connsm); - - /* CSA will be selected when advertising is received */ - - /* Start scanning */ - rc = ble_ll_scan_ext_initiator_start(&hcc, &connsm->scansm); - if (rc) { - SLIST_REMOVE(&g_ble_ll_conn_active_list,connsm,ble_ll_conn_sm,act_sle); - STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); - } else { - /* Set the connection state machine we are trying to create. */ - g_ble_ll_conn_create_sm = connsm; - } - - return rc; -} -#endif - -static int -ble_ll_conn_process_conn_params(const struct ble_hci_le_rem_conn_param_rr_cp *cmd, - struct ble_ll_conn_sm *connsm) -{ - int rc; - struct hci_conn_update *hcu; - - /* Retrieve command data */ - hcu = &connsm->conn_param_req; - hcu->handle = connsm->conn_handle; - - BLE_LL_ASSERT(connsm->conn_handle == le16toh(cmd->conn_handle)); - - hcu->conn_itvl_min = le16toh(cmd->conn_itvl_min); - hcu->conn_itvl_max = le16toh(cmd->conn_itvl_max); - hcu->conn_latency = le16toh(cmd->conn_latency); - hcu->supervision_timeout = le16toh(cmd->supervision_timeout); - hcu->min_ce_len = le16toh(cmd->min_ce); - hcu->max_ce_len = le16toh(cmd->max_ce); - - /* Check that parameter values are in range */ - rc = ble_ll_conn_hci_chk_conn_params(hcu->conn_itvl_min, - hcu->conn_itvl_max, - hcu->conn_latency, - hcu->supervision_timeout); - - /* Check valid min/max ce length */ - if (rc || (hcu->min_ce_len > hcu->max_ce_len)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - return rc; -} - -/** - * Called when the host issues the read remote features command - * - * @param cmdbuf - * - * @return int - */ -int -ble_ll_conn_hci_read_rem_features(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_rd_rem_feat_cp *cmd = (const void *) cmdbuf; - struct ble_ll_conn_sm *connsm; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* If no connection handle exit with error */ - connsm = ble_ll_conn_find_active_conn(le16toh(cmd->conn_handle)); - if (!connsm) { - return BLE_ERR_UNK_CONN_ID; - } - - /* If already pending exit with error */ - if (connsm->csmflags.cfbit.pending_hci_rd_features) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* - * Start control procedure if we did not receive peer's features and did not - * start procedure already. - */ - if (!connsm->csmflags.cfbit.rxd_features && - !IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG)) { - if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && - !(ble_ll_read_supp_features() & BLE_LL_FEAT_SLAVE_INIT)) { - return BLE_ERR_CMD_DISALLOWED; - } - - ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG); - } - - connsm->csmflags.cfbit.pending_hci_rd_features = 1; - - return BLE_ERR_SUCCESS; -} - -/** - * Called to process a connection update command. - * - * @param cmdbuf - * - * @return int - */ -int -ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_conn_update_cp *cmd = (const void *) cmdbuf; - int rc; - uint8_t ctrl_proc; - uint16_t handle; - struct ble_ll_conn_sm *connsm; - struct hci_conn_update *hcu; - - /* - * XXX: must deal with slave not supporting this feature and using - * conn update! Right now, we only check if WE support the connection - * parameters request procedure. We dont check if the remote does. - * We should also be able to deal with sending the parameter request, - * getting an UNKOWN_RSP ctrl pdu and resorting to use normal - * connection update procedure. - */ - - /* If no connection handle exit with error */ - handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); - if (!connsm) { - return BLE_ERR_UNK_CONN_ID; - } - - /* Better not have this procedure ongoing! */ - if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ) || - IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* See if this feature is supported on both sides */ - if ((connsm->conn_features & BLE_LL_FEAT_CONN_PARM_REQ) == 0) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - return BLE_ERR_UNSUPP_REM_FEATURE; - } - ctrl_proc = BLE_LL_CTRL_PROC_CONN_UPDATE; - } else { - ctrl_proc = BLE_LL_CTRL_PROC_CONN_PARAM_REQ; - } - - /* - * If we are a slave and the master has initiated the procedure already - * we should deny the slave request for now. If we are a master and the - * slave has initiated the procedure, we need to send a reject to the - * slave. - */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - return BLE_ERR_LMP_COLLISION; - } else { - connsm->csmflags.cfbit.awaiting_host_reply = 0; - - /* XXX: If this fails no reject ind will be sent! */ - ble_ll_ctrl_reject_ind_send(connsm, connsm->host_reply_opcode, - BLE_ERR_LMP_COLLISION); - } - } - - /* - * If we are a slave and the master has initiated the channel map - * update procedure we should deny the slave request for now. - */ - if (connsm->csmflags.cfbit.chanmap_update_scheduled) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - return BLE_ERR_DIFF_TRANS_COLL; - } - } - - /* Retrieve command data */ - hcu = &connsm->conn_param_req; - hcu->conn_itvl_min = le16toh(cmd->conn_itvl_min); - hcu->conn_itvl_max = le16toh(cmd->conn_itvl_max); - hcu->conn_latency = le16toh(cmd->conn_latency); - hcu->supervision_timeout = le16toh(cmd->supervision_timeout); - hcu->min_ce_len = le16toh(cmd->min_ce_len); - hcu->max_ce_len = le16toh(cmd->max_ce_len); - if (hcu->min_ce_len > hcu->max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check that parameter values are in range */ - rc = ble_ll_conn_hci_chk_conn_params(hcu->conn_itvl_min, - hcu->conn_itvl_max, - hcu->conn_latency, - hcu->supervision_timeout); - if (!rc) { - hcu->handle = handle; - - /* Start the control procedure */ - ble_ll_ctrl_proc_start(connsm, ctrl_proc); - } - - return rc; -} - -int -ble_ll_conn_hci_param_rr(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_rem_conn_param_rr_cp *cmd = (const void *) cmdbuf; - struct ble_hci_le_rem_conn_param_rr_rp *rsp = (void *) rspbuf; - int rc; - uint8_t *dptr; - uint8_t rsp_opcode; - uint16_t handle; - struct os_mbuf *om; - struct ble_ll_conn_sm *connsm; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - handle = le16toh(cmd->conn_handle); - - /* See if we support this feature */ - if ((ble_ll_read_supp_features() & BLE_LL_FEAT_CONN_PARM_REQ) == 0) { - rc = BLE_ERR_UNKNOWN_HCI_CMD; - goto done; - } - - /* If we dont have a handle we cant do anything */ - connsm = ble_ll_conn_find_active_conn(handle); - if (!connsm) { - rc = BLE_ERR_UNK_CONN_ID; - goto done; - } - - /* Make sure connection parameters are valid */ - rc = ble_ll_conn_process_conn_params(cmd, connsm); - - /* The connection should be awaiting a reply. If not, just discard */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { - /* Get a control packet buffer */ - if (rc == BLE_ERR_SUCCESS) { - om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN, - sizeof(struct ble_mbuf_hdr)); - if (om) { - dptr = om->om_data; - rsp_opcode = ble_ll_ctrl_conn_param_reply(connsm, dptr, - &connsm->conn_cp); - dptr[0] = rsp_opcode; - len = g_ble_ll_ctrl_pkt_lengths[rsp_opcode] + 1; - ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len); - } - } else { - /* XXX: check return code and deal */ - ble_ll_ctrl_reject_ind_send(connsm, connsm->host_reply_opcode, - BLE_ERR_CONN_PARMS); - } - connsm->csmflags.cfbit.awaiting_host_reply = 0; - - /* XXX: if we cant get a buffer, what do we do? We need to remember - * reason if it was a negative reply. We also would need to have - * some state to tell us this happened - */ - } - -done: - rsp->conn_handle = htole16(handle); - - *rsplen = sizeof(*rsp); - return rc; -} - -int -ble_ll_conn_hci_param_nrr(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_rem_conn_params_nrr_cp *cmd = (const void *) cmdbuf; - struct ble_hci_le_rem_conn_params_nrr_rp *rsp = (void *) rspbuf; - struct ble_ll_conn_sm *connsm; - uint16_t handle; - int rc; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - handle = le16toh(cmd->conn_handle); - - /* See if we support this feature */ - if ((ble_ll_read_supp_features() & BLE_LL_FEAT_CONN_PARM_REQ) == 0) { - rc = BLE_ERR_UNKNOWN_HCI_CMD; - goto done; - } - - /* If we dont have a handle we cant do anything */ - connsm = ble_ll_conn_find_active_conn(handle); - if (!connsm) { - rc = BLE_ERR_UNK_CONN_ID; - goto done; - } - - rc = BLE_ERR_SUCCESS; - - /* The connection should be awaiting a reply. If not, just discard */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { - /* XXX: check return code and deal */ - ble_ll_ctrl_reject_ind_send(connsm, connsm->host_reply_opcode, - cmd->reason); - connsm->csmflags.cfbit.awaiting_host_reply = 0; - - /* XXX: if we cant get a buffer, what do we do? We need to remember - * reason if it was a negative reply. We also would need to have - * some state to tell us this happened - */ - } - -done: - rsp->conn_handle = htole16(handle); - - *rsplen = sizeof(*rsp); - return rc; -} - -/* this is called from same context after cmd complete is send so it is - * safe to use g_ble_ll_conn_comp_ev - */ -static void -ble_ll_conn_hci_cancel_conn_complete_event(void) -{ - BLE_LL_ASSERT(g_ble_ll_conn_comp_ev); - - ble_ll_conn_comp_event_send(NULL, BLE_ERR_UNK_CONN_ID, - g_ble_ll_conn_comp_ev, NULL); - g_ble_ll_conn_comp_ev = NULL; -} - -/** - * Called when HCI command to cancel a create connection command has been - * received. - * - * Context: Link Layer (HCI command parser) - * - * @return int - */ -int -ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) -{ - int rc; - struct ble_ll_conn_sm *connsm; - os_sr_t sr; - - /* - * If we receive this command and we have not got a connection - * create command, we have to return disallowed. The spec does not say - * what happens if the connection has already been established. We - * return disallowed as well - */ - OS_ENTER_CRITICAL(sr); - connsm = g_ble_ll_conn_create_sm; - if (connsm && (connsm->conn_state == BLE_LL_CONN_STATE_IDLE)) { - /* stop scanning and end the connection event */ - g_ble_ll_conn_create_sm = NULL; - ble_ll_scan_sm_stop(1); - ble_ll_conn_end(connsm, BLE_ERR_UNK_CONN_ID); - - *post_cmd_cb = ble_ll_conn_hci_cancel_conn_complete_event; - - rc = BLE_ERR_SUCCESS; - } else { - /* If we are not attempting to create a connection*/ - rc = BLE_ERR_CMD_DISALLOWED; - } - OS_EXIT_CRITICAL(sr); - - return rc; -} - -/** - * Called to process a HCI disconnect command - * - * Context: Link Layer task (HCI command parser). - * - * @param cmdbuf - * - * @return int - */ -int -ble_ll_conn_hci_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd) -{ - int rc; - uint16_t handle; - struct ble_ll_conn_sm *connsm; - - /* Check for valid parameters */ - handle = le16toh(cmd->conn_handle); - - rc = BLE_ERR_INV_HCI_CMD_PARMS; - if (handle <= BLE_LL_CONN_MAX_CONN_HANDLE) { - /* Make sure reason is valid */ - switch (cmd->reason) { - case BLE_ERR_AUTH_FAIL: - case BLE_ERR_REM_USER_CONN_TERM: - case BLE_ERR_RD_CONN_TERM_RESRCS: - case BLE_ERR_RD_CONN_TERM_PWROFF: - case BLE_ERR_UNSUPP_REM_FEATURE: - case BLE_ERR_UNIT_KEY_PAIRING: - case BLE_ERR_CONN_PARMS: - connsm = ble_ll_conn_find_active_conn(handle); - if (connsm) { - /* Do not allow command if we are in process of disconnecting */ - if (connsm->disconnect_reason) { - rc = BLE_ERR_CMD_DISALLOWED; - } else { - /* This control procedure better not be pending! */ - BLE_LL_ASSERT(CONN_F_TERMINATE_STARTED(connsm) == 0); - - /* Record the disconnect reason */ - connsm->disconnect_reason = cmd->reason; - - /* Start this control procedure */ - ble_ll_ctrl_terminate_start(connsm); - - rc = BLE_ERR_SUCCESS; - } - } else { - rc = BLE_ERR_UNK_CONN_ID; - } - break; - default: - break; - } - } - - return rc; -} - -/** - * Called to process a HCI disconnect command - * - * Context: Link Layer task (HCI command parser). - * - * @param cmdbuf - * - * @return int - */ -int -ble_ll_conn_hci_rd_rem_ver_cmd(const uint8_t *cmdbuf, uint8_t len) -{ - struct ble_ll_conn_sm *connsm; - const struct ble_hci_rd_rem_ver_info_cp *cmd = (const void *) cmdbuf; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check for valid parameters */ - connsm = ble_ll_conn_find_active_conn(le16toh(cmd->conn_handle)); - if (!connsm) { - return BLE_ERR_UNK_CONN_ID; - } - - /* Return error if in progress */ - if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG)) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* - * Start this control procedure. If we have already done this control - * procedure we set the pending bit so that the host gets an event because - * it is obviously expecting one (or would not have sent the command). - * NOTE: we cant just send the event here. That would cause the event to - * be queued before the command status. - */ - if (!connsm->csmflags.cfbit.version_ind_sent) { - ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG); - } else { - connsm->pending_ctrl_procs |= (1 << BLE_LL_CTRL_PROC_VERSION_XCHG); - } - - return BLE_ERR_SUCCESS; -} - -/** - * Called to read the RSSI for a given connection handle - * - * @param cmdbuf - * @param rspbuf - * @param rsplen - * - * @return int - */ -int -ble_ll_conn_hci_rd_rssi(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen) -{ - - const struct ble_hci_rd_rssi_cp *cmd = (const void *) cmdbuf; - struct ble_hci_rd_rssi_rp *rsp = (void *) rspbuf; - struct ble_ll_conn_sm *connsm; - int rc; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - rsp->handle = cmd->handle; - - connsm = ble_ll_conn_find_active_conn(le16toh(cmd->handle)); - if (!connsm) { - rsp->rssi = 127; - rc = BLE_ERR_UNK_CONN_ID; - } else { - rsp->rssi = connsm->conn_rssi; - rc = BLE_ERR_SUCCESS; - } - - *rsplen = sizeof(*rsp); - return rc; -} - -/** - * Called to read the current channel map of a connection - * - * @param cmdbuf - * @param rspbuf - * @param rsplen - * - * @return int - */ -int -ble_ll_conn_hci_rd_chan_map(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_rd_chan_map_cp *cmd = (const void *) cmdbuf; - struct ble_hci_le_rd_chan_map_rp *rsp = (void *) rspbuf; - struct ble_ll_conn_sm *connsm; - uint16_t handle; - int rc; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); - if (!connsm) { - rc = BLE_ERR_UNK_CONN_ID; - memset(rsp->chan_map, 0, sizeof(rsp->chan_map)); - } else { - if (connsm->csmflags.cfbit.chanmap_update_scheduled) { - memcpy(rsp->chan_map, connsm->req_chanmap, BLE_LL_CONN_CHMAP_LEN); - } else { - memcpy(rsp->chan_map, connsm->chanmap, BLE_LL_CONN_CHMAP_LEN); - } - rc = BLE_ERR_SUCCESS; - } - - rsp->conn_handle = htole16(handle); - - *rsplen = sizeof(*rsp); - return rc; -} - -/** - * Called when the host issues the LE command "set host channel classification" - * - * @param cmdbuf - * - * @return int - */ -int -ble_ll_conn_hci_set_chan_class(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_host_chan_class_cp *cmd = (const void *) cmdbuf; - uint8_t num_used_chans; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* - * The HCI command states that the host is allowed to mask in just one - * channel but the Link Layer needs minimum two channels to operate. So - * I will not allow this command if there are less than 2 channels masked. - */ - num_used_chans = ble_ll_utils_calc_num_used_chans(cmd->chan_map); - if ((num_used_chans < 2) || ((cmd->chan_map[4] & 0xe0) != 0)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Set the host channel mask */ - ble_ll_conn_set_global_chanmap(num_used_chans, cmd->chan_map); - return BLE_ERR_SUCCESS; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) -int -ble_ll_conn_hci_set_data_len(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_set_data_len_cp *cmd = (const void *) cmdbuf; - struct ble_hci_le_set_data_len_rp *rsp = (void *) rspbuf; - int rc; - uint16_t handle; - uint16_t txoctets; - uint16_t txtime; - struct ble_ll_conn_sm *connsm; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Find connection */ - handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); - if (!connsm) { - rc = BLE_ERR_UNK_CONN_ID; - goto done; - } - - txoctets = le16toh(cmd->tx_octets); - txtime = le16toh(cmd->tx_time); - - /* Make sure it is valid */ - if (!ble_ll_chk_txrx_octets(txoctets) || - !ble_ll_chk_txrx_time(txtime)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - /* - * Keep original value requested by host since we may want to recalculate - * MaxTxTime after PHY changes between coded and uncoded. - */ - connsm->host_req_max_tx_time = txtime; - - /* If peer does not support coded, we cannot use value larger than 2120us */ - if (!(connsm->remote_features[0] & (BLE_LL_FEAT_LE_CODED_PHY >> 8))) { - txtime = min(txtime, BLE_LL_CONN_SUPP_TIME_MAX_UNCODED); - } -#endif - - rc = BLE_ERR_SUCCESS; - if (connsm->max_tx_time != txtime || - connsm->max_tx_octets != txoctets) { - - connsm->max_tx_time = txtime; - connsm->max_tx_octets = txoctets; - - ble_ll_ctrl_initiate_dle(connsm); - } - -done: - rsp->conn_handle = htole16(handle); - *rsplen = sizeof(*rsp); - return rc; -} -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/** - * LE start encrypt command - * - * @param cmdbuf - * - * @return int - */ -int -ble_ll_conn_hci_le_start_encrypt(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_start_encrypt_cp *cmd = (const void *) cmdbuf; - struct ble_ll_conn_sm *connsm; - int rc; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - connsm = ble_ll_conn_find_active_conn(le16toh(cmd->conn_handle)); - if (!connsm) { - rc = BLE_ERR_UNK_CONN_ID; - } else if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - rc = BLE_ERR_UNSPECIFIED; - } else if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_ENCRYPT) { - /* - * The specification does not say what to do here but the host should - * not be telling us to start encryption while we are in the process - * of honoring a previous start encrypt. - */ - rc = BLE_ERR_CMD_DISALLOWED; - } else { - /* Start the control procedure */ - connsm->enc_data.host_rand_num = le64toh(cmd->rand); - connsm->enc_data.enc_div = le16toh(cmd->div); - swap_buf(connsm->enc_data.enc_block.key, cmd->ltk, 16); - ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_ENCRYPT); - rc = BLE_ERR_SUCCESS; - } - - return rc; -} - -/** - * Called to process the LE long term key reply. - * - * Context: Link Layer Task. - * - * @param cmdbuf - * @param rspbuf - * @param ocf - * - * @return int - */ -int -ble_ll_conn_hci_le_ltk_reply(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_lt_key_req_reply_cp *cmd = (const void *) cmdbuf; - struct ble_hci_le_lt_key_req_reply_rp *rsp = (void *) rspbuf; - struct ble_ll_conn_sm *connsm; - uint16_t handle; - int rc; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Find connection handle */ - handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); - if (!connsm) { - rc = BLE_ERR_UNK_CONN_ID; - goto ltk_key_cmd_complete; - } - - /* Should never get this if we are a master! */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - rc = BLE_ERR_UNSPECIFIED; - goto ltk_key_cmd_complete; - } - - /* The connection should be awaiting a reply. If not, just discard */ - if (connsm->enc_data.enc_state != CONN_ENC_S_LTK_REQ_WAIT) { - rc = BLE_ERR_CMD_DISALLOWED; - goto ltk_key_cmd_complete; - } - - swap_buf(connsm->enc_data.enc_block.key, cmd->ltk, 16); - ble_ll_calc_session_key(connsm); - ble_ll_ctrl_start_enc_send(connsm); - rc = BLE_ERR_SUCCESS; - -ltk_key_cmd_complete: - rsp->conn_handle = htole16(handle); - - *rsplen = sizeof(*rsp); - return rc; -} - -/** - * Called to process the LE long term key negative reply. - * - * Context: Link Layer Task. - * - * @param cmdbuf - * @param rspbuf - * @param ocf - * - * @return int - */ -int -ble_ll_conn_hci_le_ltk_neg_reply(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_lt_key_req_neg_reply_cp *cmd = (const void *) cmdbuf; - struct ble_hci_le_lt_key_req_neg_reply_rp *rsp = (void *) rspbuf; - struct ble_ll_conn_sm *connsm; - uint16_t handle; - int rc; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Find connection handle */ - handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); - if (!connsm) { - rc = BLE_ERR_UNK_CONN_ID; - goto ltk_key_cmd_complete; - } - - /* Should never get this if we are a master! */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - rc = BLE_ERR_UNSPECIFIED; - goto ltk_key_cmd_complete; - } - - /* The connection should be awaiting a reply. If not, just discard */ - if (connsm->enc_data.enc_state != CONN_ENC_S_LTK_REQ_WAIT) { - rc = BLE_ERR_CMD_DISALLOWED; - goto ltk_key_cmd_complete; - } - - /* We received a negative reply! Send REJECT_IND */ - ble_ll_ctrl_reject_ind_send(connsm, BLE_LL_CTRL_ENC_REQ, - BLE_ERR_PINKEY_MISSING); - connsm->enc_data.enc_state = CONN_ENC_S_LTK_NEG_REPLY; - - rc = BLE_ERR_SUCCESS; - -ltk_key_cmd_complete: - rsp->conn_handle = htole16(handle); - - *rsplen = sizeof(*rsp); - return rc; -} -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) -int -ble_ll_conn_req_peer_sca(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_request_peer_sca_cp *params = (const void *)cmdbuf; - struct ble_ll_conn_sm *connsm; - - connsm = ble_ll_conn_find_active_conn(params->conn_handle); - if (!connsm) { - return BLE_ERR_UNK_CONN_ID; - } - - if (!(connsm->remote_features[2] & (BLE_LL_FEAT_SCA_UPDATE >> 24))) { - return BLE_ERR_UNSUPP_REM_FEATURE; - } - - if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE)) { - /* Not really specified what we should return */ - return BLE_ERR_CTLR_BUSY; - } - - ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE); - - return 0; -} -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) -/** - * Read authenticated payload timeout (OGF=3, OCF==0x007B) - * - * @param cmdbuf - * @param rsplen - * - * @return int - */ -int -ble_ll_conn_hci_rd_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_cb_rd_auth_pyld_tmo_cp *cmd = (const void *) cmdbuf; - struct ble_hci_cb_rd_auth_pyld_tmo_rp *rsp = (void *) rspbuf; - struct ble_ll_conn_sm *connsm; - uint16_t handle; - int rc; - - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); - if (!connsm) { - rc = BLE_ERR_UNK_CONN_ID; - rsp->tmo = 0; - } else { - rc = BLE_ERR_SUCCESS; - rsp->tmo = htole16(connsm->auth_pyld_tmo); - } - - rsp->conn_handle = htole16(handle); - - *rsplen = sizeof(*rsp); - return rc; -} - -/** - * Write authenticated payload timeout (OGF=3, OCF=00x7C) - * - * @param cmdbuf - * @param rsplen - * - * @return int - */ -int -ble_ll_conn_hci_wr_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_cb_wr_auth_pyld_tmo_cp *cmd = (const void *) cmdbuf; - struct ble_hci_cb_wr_auth_pyld_tmo_rp *rsp = (void *) rspbuf; - struct ble_ll_conn_sm *connsm; - uint32_t min_tmo; - uint16_t handle; - uint16_t tmo; - int rc; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - rc = BLE_ERR_SUCCESS; - - handle = le16toh(cmd->conn_handle); - - connsm = ble_ll_conn_find_active_conn(handle); - if (!connsm) { - rc = BLE_ERR_UNK_CONN_ID; - } else { - /* - * The timeout is in units of 10 msecs. We need to make sure that the - * timeout is greater than or equal to connItvl * (1 + slaveLatency) - */ - tmo = le16toh(cmd->tmo); - min_tmo = (uint32_t)connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS; - min_tmo *= (connsm->slave_latency + 1); - min_tmo /= 10000; - - if (tmo < min_tmo) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - } else { - connsm->auth_pyld_tmo = tmo; - if (ble_npl_callout_is_active(&connsm->auth_pyld_timer)) { - ble_ll_conn_auth_pyld_timer_start(connsm); - } - } - } - - rsp->conn_handle = htole16(handle); - *rsplen = sizeof(*rsp); - return rc; -} -#endif - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) -/** - * Read current phy for connection (OGF=8, OCF==0x0030) - * - * @param cmdbuf - * @param rsplen - * - * @return int - */ -int -ble_ll_conn_hci_le_rd_phy(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_rd_phy_cp *cmd = (const void *) cmdbuf; - struct ble_hci_le_rd_phy_rp *rsp = (void *) rspbuf; - int rc; - uint16_t handle; - struct ble_ll_conn_sm *connsm; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); - if (!connsm) { - rsp->tx_phy = 0; - rsp->rx_phy = 0; - rc = BLE_ERR_UNK_CONN_ID; - } else { - rsp->tx_phy = connsm->phy_data.cur_tx_phy; - rsp->rx_phy = connsm->phy_data.cur_rx_phy; - rc = BLE_ERR_SUCCESS; - } - - rsp->conn_handle = htole16(handle); - - *rsplen = sizeof(*rsp); - return rc; -} - -/** - * Set PHY preferences for connection - * - * @param cmdbuf - * - * @return int - */ -int -ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_phy_cp *cmd = (const void *) cmdbuf; - int rc; - uint16_t phy_options; - uint8_t tx_phys; - uint8_t rx_phys; - uint16_t handle; - struct ble_ll_conn_sm *connsm; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); - if (!connsm) { - return BLE_ERR_UNK_CONN_ID; - } - - /* - * If host has requested a PHY update and we are not finished do - * not allow another one - */ - if (CONN_F_HOST_PHY_UPDATE(connsm)) { - return BLE_ERR_CMD_DISALLOWED; - } - - phy_options = le16toh(cmd->phy_options); - if (phy_options > BLE_HCI_LE_PHY_CODED_S8_PREF) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check valid parameters */ - rc = ble_ll_hci_chk_phy_masks(cmd->all_phys, cmd->tx_phys, cmd->rx_phys, - &tx_phys, &rx_phys); - if (rc) { - goto phy_cmd_param_err; - } - - connsm->phy_data.phy_options = phy_options & 0x03; - connsm->phy_data.host_pref_tx_phys_mask = tx_phys, - connsm->phy_data.host_pref_rx_phys_mask = rx_phys; - - /* - * The host preferences override the default phy preferences. Currently, - * the only reason the controller will initiate a procedure on its own - * is due to the fact that the host set default preferences. So if there - * is a pending control procedure and it has not yet started, we do not - * need to perform the default controller procedure. - */ - if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE)) { - if (connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_PHY_UPDATE) { - CONN_F_CTRLR_PHY_UPDATE(connsm) = 0; - } - CONN_F_HOST_PHY_UPDATE(connsm) = 1; - } else { - /* - * We could be doing a peer-initiated PHY update procedure. If this - * is the case the requested phy preferences will not both be 0. If - * we are not done with a peer-initiated procedure we just set the - * pending bit but do not start the control procedure. - */ - if (CONN_F_PEER_PHY_UPDATE(connsm)) { - connsm->pending_ctrl_procs |= (1 << BLE_LL_CTRL_PROC_PHY_UPDATE); - CONN_F_HOST_PHY_UPDATE(connsm) = 1; - } else { - /* Check if we should start phy update procedure */ - if (!ble_ll_conn_chk_phy_upd_start(connsm)) { - CONN_F_HOST_PHY_UPDATE(connsm) = 1; - } else { - /* - * Set flag to send a PHY update complete event. We set flag - * even if we do not do an update procedure since we have to - * inform the host even if we decide not to change anything. - */ - CONN_F_PHY_UPDATE_EVENT(connsm) = 1; - } - } - } - -phy_cmd_param_err: - return rc; -} -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -int -ble_ll_set_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_periodic_adv_sync_transfer_params_cp *cmd = (const void *)cmdbuf; - struct ble_hci_le_periodic_adv_sync_transfer_params_rp *rsp = (void *) rspbuf; - struct ble_ll_conn_sm *connsm; - uint16_t sync_timeout; - uint16_t skip; - int rc; - - if (len != sizeof(*cmd)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - if (cmd->mode > 0x02) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - skip = le16toh(cmd->skip); - if (skip > 0x01f3) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - sync_timeout = le16toh(cmd->sync_timeout); - if ((sync_timeout < 0x000a) || (sync_timeout > 0x4000)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - /* we don't support any CTE yet */ - if (cmd->sync_cte_type) { - rc = BLE_ERR_UNSUPPORTED; - goto done; - } - - connsm = ble_ll_conn_find_active_conn(le16toh(cmd->conn_handle)); - if (!connsm) { - rc = BLE_ERR_UNK_CONN_ID; - goto done; - } - - /* timeout in 10ms units */ - connsm->sync_transfer_sync_timeout = sync_timeout * 10000; - connsm->sync_transfer_mode = cmd->mode; - connsm->sync_transfer_skip = skip; - - rc = BLE_ERR_SUCCESS; - -done: - rsp->conn_handle = cmd->conn_handle; - *rsplen = sizeof(*rsp); - return rc; -} - -int -ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_default_periodic_sync_transfer_params_cp *cmd = (const void *)cmdbuf; - uint16_t sync_timeout; - uint16_t skip; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (cmd->mode > 0x02) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - skip = le16toh(cmd->skip); - if (skip > 0x01f3) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - sync_timeout = le16toh(cmd->sync_timeout); - if ((sync_timeout < 0x000a) || (sync_timeout > 0x4000)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* we don't support any CTE yet */ - if (cmd->sync_cte_type) { - return BLE_ERR_UNSUPPORTED; - } - - /* timeout in 10ms units */ - g_ble_ll_conn_sync_transfer_params.sync_timeout_us = sync_timeout * 10000; - g_ble_ll_conn_sync_transfer_params.mode = cmd->mode; - g_ble_ll_conn_sync_transfer_params.max_skip = skip; - - return BLE_ERR_SUCCESS; -} -#endif -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_conn_priv.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_conn_priv.h deleted file mode 100644 index 93a478c42..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_conn_priv.h +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_CONN_PRIV_ -#define H_BLE_LL_CONN_PRIV_ - -#include "../include/controller/ble_ll_conn.h" -#include "../include/controller/ble_ll_hci.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Definitions for min/max RX/TX time/bytes values allowed for connections. - * Source: Core 5.0 specification, Vol 6, Part B, section 4.5.10 - */ -#define BLE_LL_CONN_SUPP_TIME_MIN (328) /* usecs */ -#define BLE_LL_CONN_SUPP_TIME_MAX (17040) /* usecs */ -#define BLE_LL_CONN_SUPP_TIME_MIN_UNCODED (328) /* usecs */ -#define BLE_LL_CONN_SUPP_TIME_MAX_UNCODED (2120) /* usecs */ -#define BLE_LL_CONN_SUPP_TIME_MIN_CODED (2704) /* usecs */ -#define BLE_LL_CONN_SUPP_TIME_MAX_CODED (17040) /* usecs */ -#define BLE_LL_CONN_SUPP_BYTES_MIN (27) /* bytes */ -#define BLE_LL_CONN_SUPP_BYTES_MAX (251) /* bytes */ - -/* Connection event timing */ -#define BLE_LL_CONN_INITIAL_OFFSET (1250) -#define BLE_LL_CONN_ITVL_USECS (1250) -#define BLE_LL_CONN_TX_WIN_USECS (1250) -#define BLE_LL_CONN_TX_OFF_USECS (1250) -#define BLE_LL_CONN_CE_USECS (625) -#define BLE_LL_CONN_TX_WIN_MIN (1) /* in tx win units */ -#define BLE_LL_CONN_SLAVE_LATENCY_MAX (499) - -/* Connection handle range */ -#define BLE_LL_CONN_MAX_CONN_HANDLE (0x0EFF) - -/* Offset (in bytes) of advertising address in connect request */ -#define BLE_LL_CONN_REQ_ADVA_OFF (BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN) - -/* Default authenticated payload timeout (30 seconds; in 10 msecs increments) */ -#define BLE_LL_CONN_DEF_AUTH_PYLD_TMO (3000) -#define BLE_LL_CONN_AUTH_PYLD_OS_TMO(x) ble_npl_time_ms_to_ticks32((x) * 10) - -/* Global Link Layer connection parameters */ -struct ble_ll_conn_global_params -{ - uint8_t master_chan_map[BLE_LL_CONN_CHMAP_LEN]; - uint8_t num_used_chans; - uint8_t supp_max_tx_octets; - uint8_t supp_max_rx_octets; - uint8_t conn_init_max_tx_octets; - uint8_t sugg_tx_octets; - uint16_t sugg_tx_time; - uint16_t conn_init_max_tx_time; - uint16_t conn_init_max_tx_time_uncoded; - uint16_t conn_init_max_tx_time_coded; - uint16_t supp_max_tx_time; - uint16_t supp_max_rx_time; -}; -extern struct ble_ll_conn_global_params g_ble_ll_conn_params; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -struct ble_ll_conn_sync_transfer_params -{ - uint32_t sync_timeout_us; - uint16_t max_skip; - uint8_t mode; -}; -extern struct ble_ll_conn_sync_transfer_params g_ble_ll_conn_sync_transfer_params; -#endif - -/* Some data structures used by other LL routines */ -SLIST_HEAD(ble_ll_conn_active_list, ble_ll_conn_sm); -STAILQ_HEAD(ble_ll_conn_free_list, ble_ll_conn_sm); -extern struct ble_ll_conn_active_list g_ble_ll_conn_active_list; -extern struct ble_ll_conn_free_list g_ble_ll_conn_free_list; - -/* Pointer to connection state machine we are trying to create */ -extern struct ble_ll_conn_sm *g_ble_ll_conn_create_sm; - -/* Generic interface */ -struct ble_ll_len_req; -struct ble_mbuf_hdr; -struct ble_ll_adv_sm; - -struct hci_create_conn -{ - uint16_t scan_itvl; - uint16_t scan_window; - uint8_t filter_policy; - uint8_t peer_addr_type; - uint8_t peer_addr[BLE_DEV_ADDR_LEN]; - uint8_t own_addr_type; - uint16_t conn_itvl_min; - uint16_t conn_itvl_max; - uint16_t conn_latency; - uint16_t supervision_timeout; - uint16_t min_ce_len; - uint16_t max_ce_len; -}; - -void ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm); -void ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err); -void ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om, - uint8_t hdr_byte, uint8_t length); -struct ble_ll_conn_sm *ble_ll_conn_sm_get(void); -void ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm, - struct hci_create_conn *hcc); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -void ble_ll_conn_ext_master_init(struct ble_ll_conn_sm *connsm, - struct hci_ext_create_conn *hcc); - -void ble_ll_conn_ext_set_params(struct ble_ll_conn_sm *connsm, - struct hci_ext_conn_params *hcc_params, - int phy); -#endif - -struct ble_ll_conn_sm *ble_ll_conn_find_active_conn(uint16_t handle); -void ble_ll_conn_update_eff_data_len(struct ble_ll_conn_sm *connsm); - -/* Advertising interface */ -int ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, - struct ble_mbuf_hdr *rxhdr, bool force_csa2); - -/* Link Layer interface */ -void ble_ll_conn_module_init(void); -void ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, const uint8_t *chanmap); -void ble_ll_conn_module_reset(void); -void ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t len); -int ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa); -int ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr); -void ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr); -void ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *ble_hdr); -int ble_ll_init_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *ble_hdr); -int ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok, - struct ble_mbuf_hdr *ble_hdr); -void ble_ll_conn_wfr_timer_exp(void); -void ble_ll_conn_init_wfr_timer_exp(void); -int ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2); -uint32_t ble_ll_conn_get_ce_end_time(void); -void ble_ll_conn_event_halt(void); -void ble_ll_conn_reset_pending_aux_conn_rsp(void); -bool ble_ll_conn_init_pending_aux_conn_rsp(void); -/* HCI */ -void ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm, - uint8_t reason); -void ble_ll_auth_pyld_tmo_event_send(struct ble_ll_conn_sm *connsm); -int ble_ll_conn_hci_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd); -int ble_ll_conn_hci_rd_rem_ver_cmd(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_conn_hci_set_chan_class(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_conn_hci_param_rr(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_conn_hci_param_nrr(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb); -void ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm); -void ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status, - uint8_t *evbuf, struct ble_ll_adv_sm *advsm); -void ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err); -int ble_ll_conn_hci_chk_conn_params(uint16_t itvl_min, uint16_t itvl_max, - uint16_t latency, uint16_t spvn_tmo); -int ble_ll_conn_hci_read_rem_features(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_conn_hci_rd_rssi(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, - uint8_t *rsplen); -int ble_ll_conn_hci_rd_chan_map(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_conn_hci_set_data_len(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_conn_hci_le_start_encrypt(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_conn_hci_le_ltk_reply(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_conn_hci_le_ltk_neg_reply(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_conn_hci_wr_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_conn_hci_rd_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) -int ble_ll_conn_req_peer_sca(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) -void ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm); -#else -#define ble_ll_conn_auth_pyld_timer_start(x) -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) -void ble_ll_conn_cth_flow_set_buffers(uint16_t num_buffers); -bool ble_ll_conn_cth_flow_enable(bool enabled); -void ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf); -#endif - -int ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg); -int ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg); - -int ble_ll_conn_hci_le_rd_phy(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rsp, uint8_t *rsplen); -int ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_conn_chk_phy_upd_start(struct ble_ll_conn_sm *connsm); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int ble_ll_ext_conn_create(const uint8_t *cmdbuf, uint8_t cmdlen); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -int ble_ll_set_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_LL_CONN_PRIV_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_ctrl.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_ctrl.c deleted file mode 100644 index 64bd1543c..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_ctrl.c +++ /dev/null @@ -1,2879 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_hci.h" -#include "../include/controller/ble_ll_ctrl.h" -#include "../include/controller/ble_ll_trace.h" -#include "../include/controller/ble_hw.h" -#include "../include/controller/ble_ll_sync.h" -#include "ble_ll_conn_priv.h" - -/* To use spec sample data for testing */ -#undef BLE_LL_ENCRYPT_USE_TEST_DATA - -/* - * For console debug to show session key calculation. NOTE: if you define - * this the stack requirements for the LL task go up considerably. The - * default stack will not be enough and must be increased. - */ -#undef BLE_LL_ENCRYPT_DEBUG -#ifdef BLE_LL_ENCRYPT_DEBUG -#include "console/console.h" -#endif - -/* - * XXX: - * 1) Do I need to keep track of which procedures have already been done? - * Do I need to worry about repeating procedures? - * 2) Should we create pool of control pdu's?. Dont need more - * than the # of connections and can probably deal with quite a few less - * if we have lots of connections. - * 3) What about procedures that have been completed but try to restart? - * 4) NOTE: there is a supported features procedure. However, in the case - * of data length extension, if the receiving device does not understand - * the pdu or it does not support data length extension, the LL_UNKNOWN_RSP - * pdu is sent. That needs to be processed... - * 5) We are supposed to remember when we do the data length update proc if - * the device sent us an unknown rsp. We should not send it another len req. - * Implement this how? Through remote supported features? - * 8) How to count control pdus sent. DO we count enqueued + sent, or only - * sent (actually attempted to tx). Do we count failures? How? - */ - -/* - * XXX: I definitely have an issue with control procedures and connection - * param request procedure and connection update procedure. This was - * noted when receiving an unknown response. Right now, I am getting confused - * with connection parameter request and updates regarding which procedures - * are running. So I need to go look through all the code and see where I - * used the request procedure and the update procedure and make sure I am doing - * the correct thing. - */ - -/* - * This array contains the length of the CtrData field in LL control PDU's. - * Note that there is a one byte opcode which precedes this field in the LL - * control PDU, so total data channel payload length for the control pdu is - * one greater. - */ -const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES] = -{ - BLE_LL_CTRL_CONN_UPD_REQ_LEN, - BLE_LL_CTRL_CHAN_MAP_LEN, - BLE_LL_CTRL_TERMINATE_IND_LEN, - BLE_LL_CTRL_ENC_REQ_LEN, - BLE_LL_CTRL_ENC_RSP_LEN, - BLE_LL_CTRL_START_ENC_REQ_LEN, - BLE_LL_CTRL_START_ENC_RSP_LEN, - BLE_LL_CTRL_UNK_RSP_LEN, - BLE_LL_CTRL_FEATURE_LEN, - BLE_LL_CTRL_FEATURE_LEN, - BLE_LL_CTRL_PAUSE_ENC_REQ_LEN, - BLE_LL_CTRL_PAUSE_ENC_RSP_LEN, - BLE_LL_CTRL_VERSION_IND_LEN, - BLE_LL_CTRL_REJ_IND_LEN, - BLE_LL_CTRL_SLAVE_FEATURE_REQ_LEN, - BLE_LL_CTRL_CONN_PARAMS_LEN, - BLE_LL_CTRL_CONN_PARAMS_LEN, - BLE_LL_CTRL_REJECT_IND_EXT_LEN, - BLE_LL_CTRL_PING_LEN, - BLE_LL_CTRL_PING_LEN, - BLE_LL_CTRL_LENGTH_REQ_LEN, - BLE_LL_CTRL_LENGTH_REQ_LEN, - BLE_LL_CTRL_PHY_REQ_LEN, - BLE_LL_CTRL_PHY_RSP_LEN, - BLE_LL_CTRL_PHY_UPD_IND_LEN, - BLE_LL_CTRL_MIN_USED_CHAN_LEN, - BLE_LL_CTRL_CTE_REQ_LEN, - BLE_LL_CTRL_CTE_RSP_LEN, - BLE_LL_CTRL_PERIODIC_SYNC_IND_LEN, - BLE_LL_CTRL_CLOCK_ACCURACY_REQ_LEN, - BLE_LL_CTRL_CLOCK_ACCURACY_RSP_LEN, - BLE_LL_CTRL_CIS_REQ_LEN, - BLE_LL_CTRL_CIS_RSP_LEN, - BLE_LL_CTRL_CIS_IND_LEN, - BLE_LL_CTRL_CIS_TERMINATE_LEN -}; - -/** - * Called to determine if a LL control procedure with an instant has - * been initiated. - * - * If the function returns a 0 it means no conflicting procedure has - * been initiated. Otherwise it returns the appropriate BLE error code to - * send. - * - * @param connsm Pointer to connection state machine. - * @param req_ctrl_proc The procedure that the peer is trying to initiate - * - * @return uint8_t - */ -uint8_t -ble_ll_ctrl_proc_with_instant_initiated(struct ble_ll_conn_sm *connsm, - uint8_t req_ctrl_proc) -{ - uint8_t err; - - switch (connsm->cur_ctrl_proc) { - case BLE_LL_CTRL_PROC_PHY_UPDATE: - case BLE_LL_CTRL_PROC_CONN_UPDATE: - case BLE_LL_CTRL_PROC_CONN_PARAM_REQ: - case BLE_LL_CTRL_PROC_CHAN_MAP_UPD: - if (req_ctrl_proc == connsm->cur_ctrl_proc) { - err = BLE_ERR_LMP_COLLISION; - } else if ((connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_UPDATE) && - (req_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) { - err = BLE_ERR_LMP_COLLISION; - } else { - err = BLE_ERR_DIFF_TRANS_COLL; - } - break; - default: - err = 0; - } - - return err; -} - -/** - * Create a LL_REJECT_EXT_IND pdu. - * - * @param rej_opcode Opcode to be rejected. - * @param err: error response - * @param ctrdata: Pointer to where CtrData starts in pdu - */ -void -ble_ll_ctrl_rej_ext_ind_make(uint8_t rej_opcode, uint8_t err, uint8_t *ctrdata) -{ - ctrdata[0] = rej_opcode; - ctrdata[1] = err; -} - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) -/** - * Called to cancel a phy update procedure. - * - * @param connsm - * @param ble_err - */ -void -ble_ll_ctrl_phy_update_cancel(struct ble_ll_conn_sm *connsm, uint8_t ble_err) -{ - /* cancel any pending phy update procedures */ - CLR_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); - - /* Check if the host wants an event */ - if (CONN_F_HOST_PHY_UPDATE(connsm)) { - ble_ll_hci_ev_phy_update(connsm, ble_err); - CONN_F_HOST_PHY_UPDATE(connsm) = 0; - } - - /* Clear any bits for phy updates that might be in progress */ - CONN_F_CTRLR_PHY_UPDATE(connsm) = 0; -} -#endif - -static int -ble_ll_ctrl_len_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr) -{ - int rc; - struct ble_ll_len_req ctrl_req; - - /* Extract parameters and check if valid */ - ctrl_req.max_rx_bytes = get_le16(dptr); - ctrl_req.max_rx_time = get_le16(dptr + 2); - ctrl_req.max_tx_bytes = get_le16(dptr + 4); - ctrl_req.max_tx_time = get_le16(dptr + 6); - - if ((ctrl_req.max_rx_bytes < BLE_LL_CONN_SUPP_BYTES_MIN) || - (ctrl_req.max_rx_time < BLE_LL_CONN_SUPP_TIME_MIN) || - (ctrl_req.max_tx_bytes < BLE_LL_CONN_SUPP_BYTES_MIN) || - (ctrl_req.max_tx_time < BLE_LL_CONN_SUPP_TIME_MIN)) { - rc = 1; - } else { - /* Update parameters */ - connsm->rem_max_rx_time = ctrl_req.max_rx_time; - connsm->rem_max_tx_time = ctrl_req.max_tx_time; - connsm->rem_max_rx_octets = ctrl_req.max_rx_bytes; - connsm->rem_max_tx_octets = ctrl_req.max_tx_bytes; - - /* Recalculate effective connection parameters */ - ble_ll_conn_update_eff_data_len(connsm); - rc = 0; - } - - return rc; -} - -/** - * Process a received LL_PING_RSP control pdu. - * - * NOTE: we dont have to reset the callout since this packet will have had a - * valid MIC and that will restart the authenticated payload timer - * - * @param connsm - */ -static void -ble_ll_ctrl_rx_ping_rsp(struct ble_ll_conn_sm *connsm) -{ - /* Stop the control procedure */ - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_LE_PING); -} - -/** - * Called when we receive either a connection parameter request or response. - * - * @param connsm - * @param dptr - * @param rspbuf - * @param opcode - * - * @return int - */ -static int -ble_ll_ctrl_conn_param_pdu_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *rspbuf, uint8_t opcode) -{ - int rc; - int indicate; - uint8_t rsp_opcode; - uint8_t ble_err; - struct ble_ll_conn_params *req; - struct hci_conn_update *hcu; - - /* Extract parameters and check if valid */ - req = &connsm->conn_cp; - req->interval_min = get_le16(dptr); - req->interval_max = get_le16(dptr + 2); - req->latency = get_le16(dptr + 4); - req->timeout = get_le16(dptr + 6); - req->pref_periodicity = dptr[8]; - req->ref_conn_event_cnt = get_le16(dptr + 9); - req->offset0 = get_le16(dptr + 11); - req->offset1 = get_le16(dptr + 13); - req->offset2 = get_le16(dptr + 15); - req->offset3 = get_le16(dptr + 17); - req->offset4 = get_le16(dptr + 19); - req->offset5 = get_le16(dptr + 21); - - /* Check if parameters are valid */ - ble_err = BLE_ERR_SUCCESS; - rc = ble_ll_conn_hci_chk_conn_params(req->interval_min, - req->interval_max, - req->latency, - req->timeout); - if (rc) { - ble_err = BLE_ERR_INV_LMP_LL_PARM; - goto conn_param_pdu_exit; - } - - /* - * Check if there is a requested change to either the interval, timeout - * or latency. If not, this may just be an anchor point change and we do - * not have to notify the host. - * XXX: what if we dont like the parameters? When do we check that out? - */ - indicate = 1; - if (opcode == BLE_LL_CTRL_CONN_PARM_REQ) { - if ((connsm->conn_itvl >= req->interval_min) && - (connsm->conn_itvl <= req->interval_max) && - (connsm->supervision_tmo == req->timeout) && - (connsm->slave_latency == req->latency)) { - indicate = 0; - goto conn_parm_req_do_indicate; - } - } - - /* - * A change has been requested. Is it within the values specified by - * the host? Note that for a master we will not be processing a - * connect param request from a slave if we are currently trying to - * update the connection parameters. This means that the previous - * check is all we need for a master (when receiving a request). - */ - if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) || - (opcode == BLE_LL_CTRL_CONN_PARM_RSP)) { - /* - * Not sure what to do about the slave. It is possible that the - * current connection parameters are not the same ones as the local host - * has provided? Not sure what to do here. Do we need to remember what - * host sent us? For now, I will assume that we need to remember what - * the host sent us and check it out. - */ - hcu = &connsm->conn_param_req; - if (hcu->handle != 0) { - if (!((req->interval_min < hcu->conn_itvl_min) || - (req->interval_min > hcu->conn_itvl_max) || - (req->interval_max < hcu->conn_itvl_min) || - (req->interval_max > hcu->conn_itvl_max) || - (req->latency != hcu->conn_latency) || - (req->timeout != hcu->supervision_timeout))) { - indicate = 0; - } - } - } - -conn_parm_req_do_indicate: - /* - * XXX: are the connection update parameters acceptable? If not, we will - * need to know before we indicate to the host that they are acceptable. - */ - if (indicate) { - /* If Host masked out Remote Connection Parameter Request Event, we need to - * send Reject back to the remote device - */ - if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ)){ - ble_err = BLE_ERR_UNSUPP_REM_FEATURE; - goto conn_param_pdu_exit; - } - - /* - * Send event to host. At this point we leave and wait to get - * an answer. - */ - ble_ll_hci_ev_rem_conn_parm_req(connsm, req); - connsm->host_reply_opcode = opcode; - connsm->csmflags.cfbit.awaiting_host_reply = 1; - rsp_opcode = 255; - } else { - /* Create reply to connection request */ - rsp_opcode = ble_ll_ctrl_conn_param_reply(connsm, rspbuf, req); - } - -conn_param_pdu_exit: - if (ble_err) { - rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT; - rspbuf[1] = opcode; - rspbuf[2] = ble_err; - } - return rsp_opcode; -} - -/** - * Called to make a connection update request LL control PDU - * - * Context: Link Layer - * - * @param connsm - * @param rsp - */ -static void -ble_ll_ctrl_conn_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld, - struct ble_ll_conn_params *cp) -{ - uint16_t instant; - uint32_t dt; - uint32_t num_old_ce; - uint32_t new_itvl_usecs; - uint32_t old_itvl_usecs; - struct hci_conn_update *hcu; - struct ble_ll_conn_upd_req *req; - - /* - * Set instant. We set the instant to the current event counter plus - * the amount of slave latency as the slave may not be listening - * at every connection interval and we are not sure when the connect - * request will actually get sent. We add one more event plus the - * minimum as per the spec of 6 connection events. - */ - instant = connsm->event_cntr + connsm->slave_latency + 6 + 1; - - /* - * XXX: This should change in the future, but for now we will just - * start the new instant at the same anchor using win offset 0. - */ - /* Copy parameters in connection update structure */ - hcu = &connsm->conn_param_req; - req = &connsm->conn_update_req; - if (cp) { - /* XXX: so we need to make the new anchor point some time away - * from txwinoffset by some amount of msecs. Not sure how to do - that here. We dont need to, but we should. */ - /* Calculate offset from requested offsets (if any) */ - if (cp->offset0 != 0xFFFF) { - new_itvl_usecs = cp->interval_max * BLE_LL_CONN_ITVL_USECS; - old_itvl_usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS; - if ((int16_t)(cp->ref_conn_event_cnt - instant) >= 0) { - num_old_ce = cp->ref_conn_event_cnt - instant; - dt = old_itvl_usecs * num_old_ce; - dt += (cp->offset0 * BLE_LL_CONN_ITVL_USECS); - dt = dt % new_itvl_usecs; - } else { - num_old_ce = instant - cp->ref_conn_event_cnt; - dt = old_itvl_usecs * num_old_ce; - dt -= (cp->offset0 * BLE_LL_CONN_ITVL_USECS); - dt = dt % new_itvl_usecs; - dt = new_itvl_usecs - dt; - } - req->winoffset = dt / BLE_LL_CONN_TX_WIN_USECS; - } else { - req->winoffset = 0; - } - req->interval = cp->interval_max; - req->timeout = cp->timeout; - req->latency = cp->latency; - req->winsize = 1; - } else { - req->interval = hcu->conn_itvl_max; - req->timeout = hcu->supervision_timeout; - req->latency = hcu->conn_latency; - req->winoffset = 0; - req->winsize = connsm->tx_win_size; - } - req->instant = instant; - - /* XXX: make sure this works for the connection parameter request proc. */ - pyld[0] = req->winsize; - put_le16(pyld + 1, req->winoffset); - put_le16(pyld + 3, req->interval); - put_le16(pyld + 5, req->latency); - put_le16(pyld + 7, req->timeout); - put_le16(pyld + 9, instant); - - /* Set flag in state machine to denote we have scheduled an update */ - connsm->csmflags.cfbit.conn_update_sched = 1; -} - -/** - * Called to process and UNKNOWN_RSP LL control packet. - * - * Context: Link Layer Task - * - * @param dptr - */ -static int -ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t *rspdata) -{ - uint8_t ctrl_proc; - uint8_t opcode; - - /* Get opcode of unknown LL control frame */ - opcode = dptr[0]; - - /* Convert opcode to control procedure id */ - switch (opcode) { - case BLE_LL_CTRL_LENGTH_REQ: - ctrl_proc = BLE_LL_CTRL_PROC_DATA_LEN_UPD; - BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_DATA_LEN_EXT); - break; - case BLE_LL_CTRL_CONN_UPDATE_IND: - ctrl_proc = BLE_LL_CTRL_PROC_CONN_UPDATE; - break; - case BLE_LL_CTRL_SLAVE_FEATURE_REQ: - ctrl_proc = BLE_LL_CTRL_PROC_FEATURE_XCHG; - BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_SLAVE_INIT); - break; - case BLE_LL_CTRL_CONN_PARM_REQ: - BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_CONN_PARM_REQ); - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - ble_ll_ctrl_conn_upd_make(connsm, rspdata, NULL); - connsm->reject_reason = BLE_ERR_SUCCESS; - return BLE_LL_CTRL_CONN_UPDATE_IND; - } - /* Else falls through. */ - /* note: fall-through intentional */ - case BLE_LL_CTRL_CONN_PARM_RSP: - ctrl_proc = BLE_LL_CTRL_PROC_CONN_PARAM_REQ; - break; - case BLE_LL_CTRL_PING_REQ: - /* LL can authenticate remote device even if remote device does not - * support LE Ping feature. - */ - ctrl_proc = BLE_LL_CTRL_PROC_LE_PING; - BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_LE_PING); - break; -#if (BLE_LL_BT5_PHY_SUPPORTED ==1) - case BLE_LL_CTRL_PHY_REQ: - ble_ll_ctrl_phy_update_cancel(connsm, BLE_ERR_UNSUPP_REM_FEATURE); - ctrl_proc = BLE_LL_CTRL_PROC_PHY_UPDATE; - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) - case BLE_LL_CTRL_CLOCK_ACCURACY_REQ: - ble_ll_hci_ev_sca_update(connsm, BLE_ERR_UNSUPPORTED, 0); - ctrl_proc = BLE_LL_CTRL_PROC_SCA_UPDATE; - break; -#endif - default: - ctrl_proc = BLE_LL_CTRL_PROC_NUM; - break; - } - - /* If we are running this one currently, stop it */ - if (connsm->cur_ctrl_proc == ctrl_proc) { - /* Stop the control procedure */ - ble_ll_ctrl_proc_stop(connsm, ctrl_proc); - if (ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) { - ble_ll_hci_ev_conn_update(connsm, BLE_ERR_UNSUPP_REM_FEATURE); - } else if (ctrl_proc == BLE_LL_CTRL_PROC_FEATURE_XCHG) { - if (connsm->csmflags.cfbit.pending_hci_rd_features) { - ble_ll_hci_ev_rd_rem_used_feat(connsm, - BLE_ERR_UNSUPP_REM_FEATURE); - } - connsm->csmflags.cfbit.pending_hci_rd_features = 0; - } - } - - return BLE_ERR_MAX; -} - -/** - * Callback when LL control procedure times out (for a given connection). If - * this is called, it means that we need to end the connection because it - * has not responded to a LL control request. - * - * Context: Link Layer - * - * @param arg Pointer to connection state machine. - */ -static void -ble_ll_ctrl_proc_rsp_timer_cb(struct ble_npl_event *ev) -{ - /* Control procedure has timed out. Kill the connection */ - ble_ll_conn_timeout((struct ble_ll_conn_sm *)ble_npl_event_get_arg(ev), - BLE_ERR_LMP_LL_RSP_TMO); -} - -static void -ble_ll_ctrl_start_rsp_timer(struct ble_ll_conn_sm *connsm) -{ - ble_npl_callout_init(&connsm->ctrl_proc_rsp_timer, - &g_ble_ll_data.ll_evq, - ble_ll_ctrl_proc_rsp_timer_cb, - connsm); - - /* Re-start timer. Control procedure timeout is 40 seconds */ - ble_npl_callout_reset(&connsm->ctrl_proc_rsp_timer, - ble_npl_time_ms_to_ticks32(BLE_LL_CTRL_PROC_TIMEOUT_MS)); -} - -/** - * Convert a phy mask to a numeric phy value. - * - * NOTE: only one bit should be set here and there should be at least one. - * If this function returns a 0 it is an error! - * - * @param phy_mask Bitmask of phy - * - * @return uint8_t The numeric value associated with the phy mask - * - * BLE_HCI_LE_PHY_1M (1) - * BLE_HCI_LE_PHY_2M (2) - * BLE_HCI_LE_PHY_CODED (3) - */ -uint8_t -ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask) -{ - uint8_t phy; - - /* - * NOTE: wipe out unsupported PHYs. There should not be an unsupported - * in this mask if the other side is working correctly. - */ -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - phy_mask &= ~BLE_HCI_LE_PHY_2M_PREF_MASK; -#endif -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - phy_mask &= ~BLE_HCI_LE_PHY_CODED_PREF_MASK; -#endif - - if (phy_mask & BLE_PHY_MASK_1M) { - phy = BLE_PHY_1M; - phy_mask &= ~BLE_PHY_MASK_1M; - } else if (phy_mask & BLE_PHY_MASK_2M) { - phy = BLE_PHY_2M; - phy_mask &= ~BLE_PHY_MASK_2M; - } else if (phy_mask & BLE_PHY_MASK_CODED) { - phy = BLE_PHY_CODED; - phy_mask &= ~BLE_PHY_MASK_CODED; - } else { - phy = 0; - } - - if (phy_mask != 0) { - phy = 0; - } - - return phy; -} - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) -uint8_t -ble_ll_ctrl_phy_tx_transition_get(uint8_t phy_mask) -{ - /* - * Evaluate PHYs in transition starting from the one with longest TX time - * so we select the one that allows shortest payload to be sent. This is - * to make sure we do not violate timing restriction on new PHY. - */ - if (phy_mask & BLE_PHY_MASK_CODED) { - return BLE_PHY_CODED; - } else if (phy_mask & BLE_PHY_MASK_1M) { - return BLE_PHY_1M; - } else if (phy_mask & BLE_PHY_MASK_2M) { - return BLE_PHY_2M; - } - - return 0; -} - -void -ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm) -{ - int chk_proc_stop; - int chk_host_phy; - - chk_proc_stop = 1; - chk_host_phy = 1; - - connsm->phy_tx_transition = 0; - - if (CONN_F_PEER_PHY_UPDATE(connsm)) { - CONN_F_PEER_PHY_UPDATE(connsm) = 0; - } else if (CONN_F_CTRLR_PHY_UPDATE(connsm)) { - CONN_F_CTRLR_PHY_UPDATE(connsm) = 0; - } else { - /* Must be a host-initiated update */ - CONN_F_HOST_PHY_UPDATE(connsm) = 0; - chk_host_phy = 0; - if (CONN_F_PHY_UPDATE_EVENT(connsm) == 0) { - ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS); - } - } - - /* Must check if we need to start host procedure */ - if (chk_host_phy) { - if (CONN_F_HOST_PHY_UPDATE(connsm)) { - if (ble_ll_conn_chk_phy_upd_start(connsm)) { - CONN_F_HOST_PHY_UPDATE(connsm) = 0; - } else { - chk_proc_stop = 0; - } - } - } - - if (chk_proc_stop) { - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); - } -} - -/** - * - * There is probably a better way for the controller to choose which PHY use. - * There are no BER metrics and RSSI does not give you S/N so for now we will - * choose this heirarchy: - * -> if 2Mbps available, use it. - * -> If 1Mbps available, use it. - * -> otherwise use coded phy. - * - * @param prefs The mask of preferred phys - * @return uint8_t The phy to use (not a mask) - */ -static uint8_t -ble_ll_ctrl_find_new_phy(uint8_t phy_mask_prefs) -{ - uint8_t new_phy; - - new_phy = phy_mask_prefs; - if (new_phy) { - if (new_phy & BLE_PHY_MASK_2M) { - new_phy = BLE_PHY_2M; - } else if (new_phy & BLE_PHY_MASK_1M) { - new_phy = BLE_PHY_1M; - } else { - new_phy = BLE_PHY_CODED; - } - } - - return new_phy; -} - -/** - * Create a LL_PHY_UPDATE_IND pdu - * - * @param connsm Pointer to connection state machine - * @param dptr Pointer to PHY_REQ or PHY_RSP data. - * @param ctrdata: Pointer to where CtrData of UPDATE_IND pdu starts - * @param slave_req flag denoting if slave requested this. 0: no 1:yes - */ -static void -ble_ll_ctrl_phy_update_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *ctrdata, int slave_req) -{ - uint8_t m_to_s; - uint8_t s_to_m; - uint8_t tx_phys; - uint8_t rx_phys; - uint16_t instant; - uint8_t is_slave_sym = 0; - - /* Get preferences from PDU */ - tx_phys = dptr[0]; - rx_phys = dptr[1]; - - /* If we are master, check if slave requested symmetric PHY */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - is_slave_sym = tx_phys == rx_phys; - is_slave_sym &= __builtin_popcount(tx_phys) == 1; - } - - /* Get m_to_s and s_to_m masks */ - if (slave_req) { - m_to_s = connsm->phy_data.host_pref_tx_phys_mask & rx_phys; - s_to_m = connsm->phy_data.host_pref_rx_phys_mask & tx_phys; - } else { - m_to_s = connsm->phy_data.req_pref_tx_phys_mask & rx_phys; - s_to_m = connsm->phy_data.req_pref_rx_phys_mask & tx_phys; - } - - if (is_slave_sym) { - /* - * If either s_to_m or m_to_s is 0, it means for at least one direction - * requested PHY is not our preferred one so make sure we keep current - * PHY in both directions - * - * Core 5.2, Vol 6, PartB, 5.1.10 - * If the slave specified a single PHY in both the TX_PHYS and - * RX_PHYS fields and both fields are the same, the master shall - * either select the PHY specified by the slave for both directions - * or shall leave both directions unchanged. - */ - if ((s_to_m == 0) || (m_to_s == 0)) { - s_to_m = 0; - m_to_s = 0; - } else { - BLE_LL_ASSERT(s_to_m == m_to_s); - } - } - - /* Calculate new PHYs to use */ - m_to_s = ble_ll_ctrl_find_new_phy(m_to_s); - s_to_m = ble_ll_ctrl_find_new_phy(s_to_m); - - /* Make sure we do not indicate PHY change if the same as current one */ - if (m_to_s == connsm->phy_data.cur_tx_phy) { - m_to_s = 0; - } - if (s_to_m == connsm->phy_data.cur_rx_phy) { - s_to_m = 0; - } - - /* At this point, m_to_s and s_to_m are not masks; they are numeric */ - - /* - * If not changing we still send update ind. Check if hosts expects - * the event and if so send it. Stop control procedure if it is the - * one running. - */ - if ((m_to_s == 0) && (s_to_m == 0)) { - if (CONN_F_PEER_PHY_UPDATE(connsm)) { - CONN_F_PEER_PHY_UPDATE(connsm) = 0; - } else if (CONN_F_CTRLR_PHY_UPDATE(connsm)) { - CONN_F_CTRLR_PHY_UPDATE(connsm) = 0; - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); - } else { - ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS); - CONN_F_HOST_PHY_UPDATE(connsm) = 0; - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); - } - instant = 0; - } else { - /* Determine instant we will use. 6 more is minimum */ - instant = connsm->event_cntr + connsm->slave_latency + 6 + 1; - connsm->phy_instant = instant; - CONN_F_PHY_UPDATE_SCHED(connsm) = 1; - - /* Set new phys to use when instant occurs */ - connsm->phy_data.new_tx_phy = m_to_s; - connsm->phy_data.new_rx_phy = s_to_m; - - /* Convert m_to_s and s_to_m to masks */ - if (m_to_s) { - m_to_s = 1 << (m_to_s - 1); - } - - if (s_to_m) { - s_to_m = 1 << (s_to_m - 1); - } - } - - ctrdata[0] = m_to_s; - ctrdata[1] = s_to_m; - put_le16(ctrdata + 2, instant); -} - -/** - * Create a LL_PHY_REQ or LL_PHY_RSP pdu - * - * @param connsm Pointer to connection state machine - * @param ctrdata: Pointer to where CtrData starts in pdu - */ -static void -ble_ll_ctrl_phy_req_rsp_make(struct ble_ll_conn_sm *connsm, uint8_t *ctrdata) -{ - /* If no preference we use current phy */ - if (connsm->phy_data.host_pref_tx_phys_mask == 0) { - ctrdata[0] = CONN_CUR_TX_PHY_MASK(connsm); - } else { - ctrdata[0] = connsm->phy_data.host_pref_tx_phys_mask; - } - if (connsm->phy_data.host_pref_rx_phys_mask == 0) { - ctrdata[1] = CONN_CUR_RX_PHY_MASK(connsm); - } else { - ctrdata[1] = connsm->phy_data.host_pref_rx_phys_mask; - } -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) -/** - * Create a LL_CLOCK_ACCURACY_REQ or LL_CLOCK_ACCURACY_RSP pdu - * - * @param connsm Pointer to connection state machine - * @param ctrdata: Pointer to where CtrData starts in pdu - */ -static void -ble_ll_ctrl_sca_req_rsp_make(struct ble_ll_conn_sm *connsm, uint8_t *ctrdata) -{ - ctrdata[0] = BLE_LL_SCA_ENUM; -} -#endif - -static uint8_t -ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req, - uint8_t *rsp) -{ - uint8_t rsp_opcode; - uint8_t err; - - /* - * XXX: TODO if we have an instant in progress we should end connection. - * At least it seems that is the case. Need to figure out more from - * the spec here. - */ - - /* Check if we have already initiated a procedure with an instant */ - err = ble_ll_ctrl_proc_with_instant_initiated(connsm, - BLE_LL_CTRL_PROC_PHY_UPDATE); - - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - if (err) { - ble_ll_ctrl_rej_ext_ind_make(BLE_LL_CTRL_PHY_REQ, err, rsp); - rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT; - } else { - /* - * NOTE: do not change order of these two lines as the call to - * make the LL_PHY_UPDATE_IND pdu might clear the flag. - */ - CONN_F_PEER_PHY_UPDATE(connsm) = 1; - ble_ll_ctrl_phy_update_ind_make(connsm, req, rsp, 1); - rsp_opcode = BLE_LL_CTRL_PHY_UPDATE_IND; - } - } else { - /* XXX: deal with other control procedures that we need to stop */ - if (err) { - if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_PHY_UPDATE) { - ble_npl_callout_stop(&connsm->ctrl_proc_rsp_timer); - connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE; - } - - /* If there is a PHY update procedure pending cancel it */ - ble_ll_ctrl_phy_update_cancel(connsm, err); - - /* XXX: ? Should not be any phy update events */ - CONN_F_PHY_UPDATE_EVENT(connsm) = 0; - } - - /* XXX: TODO: if we started another procedure with an instant - * why are we doing this? Need to look into this.*/ - - /* Respond to master's phy update procedure */ - CONN_F_PEER_PHY_UPDATE(connsm) = 1; - ble_ll_ctrl_phy_req_rsp_make(connsm, rsp); - rsp_opcode = BLE_LL_CTRL_PHY_RSP; - - connsm->phy_tx_transition = ble_ll_ctrl_phy_tx_transition_get(req[1] | rsp[0]); - - /* Start response timer */ - connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_PHY_UPDATE; - ble_ll_ctrl_start_rsp_timer(connsm); - } - return rsp_opcode; -} - -/** - * Process a received LL_PHY_RSP pdu - * - * @param connsm - * @param dptr Pointer to LL_PHY_RSP ctrdata - * @param rsp Pointer to CtrData of PHY_UPDATE_IND. - * - * @return uint8_t - */ -static uint8_t -ble_ll_ctrl_rx_phy_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *rsp) -{ - uint8_t rsp_opcode; - - rsp_opcode = BLE_ERR_MAX; - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_PHY_UPDATE) { - ble_ll_ctrl_phy_update_ind_make(connsm, dptr, rsp, 0); - ble_npl_callout_stop(&connsm->ctrl_proc_rsp_timer); - rsp_opcode = BLE_LL_CTRL_PHY_UPDATE_IND; - } - - /* - * If not in the process of doing this control procedure something - * is wrong. End connection? Assert? - * - * XXX: TODO count some stat? - */ - } else { - rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP; - } - - /* NOTE: slave should never receive one of these */ - - return rsp_opcode; -} - -/** - * Called when a LL_PHY_UPDATE_IND pdu is received - * - * NOTE: slave is the only device that should receive this. - * - * @param connsm - * @param dptr - * - * @return uint8_t - */ -static uint8_t -ble_ll_ctrl_rx_phy_update_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr) -{ - int no_change; - uint8_t new_m_to_s_mask; - uint8_t new_s_to_m_mask; - uint8_t new_tx_phy; - uint8_t new_rx_phy; - uint16_t instant; - uint16_t delta; - - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - return BLE_LL_CTRL_UNKNOWN_RSP; - } - - /* - * Reception stops the procedure response timer but does not - * complete the procedure - */ - if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_PHY_UPDATE) { - ble_npl_callout_stop(&connsm->ctrl_proc_rsp_timer); - } - - /* - * XXX: Should we check to see if we are expecting to receive one - * of these, and if not, kill connection? Meaning we better be - * doing either a PEER, CTRLR, or HOST phy update. - */ - /* get the new phy masks and see if we need to change */ - new_m_to_s_mask = dptr[0]; - new_s_to_m_mask = dptr[1]; - instant = get_le16(dptr + 2); - - if ((new_m_to_s_mask == 0) && (new_s_to_m_mask == 0)) { - /* No change in phy */ - no_change = 1; - } else { - no_change = 0; - /* - * NOTE: from the slaves perspective, the m to s phy is the one - * that the slave will receive on; s to m is the one it will - * transmit on - */ - new_rx_phy = ble_ll_ctrl_phy_from_phy_mask(new_m_to_s_mask); - new_tx_phy = ble_ll_ctrl_phy_from_phy_mask(new_s_to_m_mask); - - if ((new_tx_phy == 0) && (new_rx_phy == 0)) { - /* XXX: this is an error! What to do??? */ - no_change = 1; - } - - if ((new_tx_phy == connsm->phy_data.cur_tx_phy) && - (new_rx_phy == connsm->phy_data.cur_rx_phy)) { - no_change = 1; - } - } - - if (!no_change) { - /* If instant is in the past, we have to end the connection */ - delta = (instant - connsm->event_cntr) & 0xFFFF; - if (delta >= 32767) { - ble_ll_conn_timeout(connsm, BLE_ERR_INSTANT_PASSED); - } else { - connsm->phy_data.new_tx_phy = new_tx_phy; - connsm->phy_data.new_rx_phy = new_rx_phy; - connsm->phy_instant = instant; - CONN_F_PHY_UPDATE_SCHED(connsm) = 1; - } - return BLE_ERR_MAX; - } - - ble_ll_ctrl_phy_update_proc_complete(connsm); - - return BLE_ERR_MAX; -} -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -/** - * Called when a BLE_LL_CTRL_PERIODIC_SYNC_IND PDU is received - * - * @param connsm - * @param dptr - * - * @return uint8_t - */ -static uint8_t -ble_ll_ctrl_rx_periodic_sync_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr) -{ - if (connsm->sync_transfer_mode) { - ble_ll_sync_periodic_ind(connsm, dptr, connsm->sync_transfer_mode == 1, - connsm->sync_transfer_skip, - connsm->sync_transfer_sync_timeout); - } - return BLE_ERR_MAX; -} -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) -/** - * Called when a BLE_LL_CTRL_CLOCK_ACCURACY_REQ PDU is received - * - * @param connsm - * @param dptr - * @param rsp Pointer to CtrData of BLE_LL_CTRL_CLOCK_ACCURACY_RSP. - * - * @return uint8_t - */ -static uint8_t -ble_ll_ctrl_rx_sca_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *rsp) -{ - ble_ll_ctrl_sca_req_rsp_make(connsm, rsp); - return BLE_LL_CTRL_CLOCK_ACCURACY_RSP; -} - -/** - * Called when a BLE_LL_CTRL_CLOCK_ACCURACY_RSP PDU is received - * - * @param connsm - * @param dptr - * - * @return uint8_t - */ -static uint8_t -ble_ll_ctrl_rx_sca_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr) -{ - if (connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_SCA_UPDATE) { - return BLE_LL_CTRL_UNKNOWN_RSP; - } - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE); - ble_ll_hci_ev_sca_update(connsm, BLE_ERR_SUCCESS, dptr[0]); - return BLE_ERR_MAX; -} - -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) -static uint8_t -ble_ll_ctrl_rx_cis_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *rspdata) -{ - return BLE_LL_CTRL_UNKNOWN_RSP; -} - -static uint8_t -ble_ll_ctrl_rx_cis_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *rspdata) -{ - return BLE_LL_CTRL_UNKNOWN_RSP; -} - -static uint8_t -ble_ll_ctrl_rx_cis_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr) -{ - return BLE_LL_CTRL_UNKNOWN_RSP; -} -#endif -/** - * Create a link layer length request or length response PDU. - * - * NOTE: this function does not set the LL data pdu header nor does it - * set the opcode in the buffer. - * - * @param connsm - * @param dptr: Pointer to where control pdu payload starts - */ -static void -ble_ll_ctrl_datalen_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr) -{ - put_le16(dptr + 1, connsm->max_rx_octets); - put_le16(dptr + 3, connsm->max_rx_time); - put_le16(dptr + 5, connsm->max_tx_octets); - put_le16(dptr + 7, connsm->max_tx_time); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -void -ble_ll_calc_session_key(struct ble_ll_conn_sm *connsm) -{ -#ifdef BLE_LL_ENCRYPT_DEBUG - int cnt; -#endif - - /* XXX: possibly have some way out of this if this locks up */ - while (1) { - if (!ble_hw_encrypt_block(&connsm->enc_data.enc_block)) { - break; - } - } - -#ifdef BLE_LL_ENCRYPT_DEBUG - console_printf("Calculating Session Key for handle=%u", - connsm->conn_handle); - - console_printf("\nLTK:"); - for (cnt = 0; cnt < 16; ++cnt) { - console_printf("%02x", connsm->enc_data.enc_block.key[cnt]); - } - console_printf("\nSKD:"); - for (cnt = 0; cnt < 16; ++cnt) { - console_printf("%02x", connsm->enc_data.enc_block.plain_text[cnt]); - } - console_printf("\nSession Key:"); - for (cnt = 0; cnt < 16; ++cnt) { - console_printf("%02x", connsm->enc_data.enc_block.cipher_text[cnt]); - } - console_printf("\nIV:"); - for (cnt = 0; cnt < 8; ++ cnt) { - console_printf("%02x", connsm->enc_data.iv[cnt]); - } - console_printf("\n"); -#endif -} - -/** - * Called to determine if this is a control PDU we are allowed to send. This - * is called when a link is being encrypted, as only certain control PDU's - * area lowed to be sent. - * - * XXX: the current code may actually allow some control pdu's to be sent - * in states where they shouldnt. I dont expect those states to occur so I - * dont try to check for them but we could do more... for example there are - * different PDUs allowed for master/slave and TX/RX - * - * @param llid - * @param opcode - * @param len - * - * @return int - */ -static int -ble_ll_ctrl_enc_allowed_pdu(uint8_t llid, uint8_t len, uint8_t opcode) -{ - int allowed; - - allowed = 0; - - switch (llid) { - case BLE_LL_LLID_CTRL: - switch (opcode) { - case BLE_LL_CTRL_REJECT_IND: - case BLE_LL_CTRL_REJECT_IND_EXT: - case BLE_LL_CTRL_START_ENC_RSP: - case BLE_LL_CTRL_START_ENC_REQ: - case BLE_LL_CTRL_ENC_REQ: - case BLE_LL_CTRL_ENC_RSP: - case BLE_LL_CTRL_PAUSE_ENC_REQ: - case BLE_LL_CTRL_PAUSE_ENC_RSP: - case BLE_LL_CTRL_TERMINATE_IND: - allowed = 1; - break; - } - break; - case BLE_LL_LLID_DATA_FRAG: - if (len == 0) { - /* Empty PDUs are allowed */ - allowed = 1; - } - break; - } - - return allowed; -} - -int -ble_ll_ctrl_enc_allowed_pdu_rx(struct os_mbuf *rxpdu) -{ - uint8_t llid; - uint8_t len; - uint8_t opcode; - - llid = rxpdu->om_data[0] & BLE_LL_DATA_HDR_LLID_MASK; - len = rxpdu->om_data[1]; - if (llid == BLE_LL_LLID_CTRL) { - opcode = rxpdu->om_data[2]; - } else { - opcode = 0; - } - - return ble_ll_ctrl_enc_allowed_pdu(llid, len, opcode); -} - -int -ble_ll_ctrl_enc_allowed_pdu_tx(struct os_mbuf_pkthdr *pkthdr) -{ - struct os_mbuf *m; - struct ble_mbuf_hdr *ble_hdr; - uint8_t llid; - uint8_t len; - uint8_t opcode; - - m = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); - ble_hdr = BLE_MBUF_HDR_PTR(m); - - llid = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK; - len = ble_hdr->txinfo.pyld_len; - if (llid == BLE_LL_LLID_CTRL) { - opcode = m->om_data[0]; - } else { - opcode = 0; - } - - return ble_ll_ctrl_enc_allowed_pdu(llid, len, opcode); -} - -int -ble_ll_ctrl_is_start_enc_rsp(struct os_mbuf *txpdu) -{ - int is_start_enc_rsp; - uint8_t opcode; - uint8_t llid; - struct ble_mbuf_hdr *ble_hdr; - - is_start_enc_rsp = 0; - ble_hdr = BLE_MBUF_HDR_PTR(txpdu); - - llid = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK; - if (llid == BLE_LL_LLID_CTRL) { - opcode = txpdu->om_data[0]; - if (opcode == BLE_LL_CTRL_START_ENC_RSP) { - is_start_enc_rsp = 1; - } - } - - return is_start_enc_rsp; -} - -/** - * Called to create and send a LL_START_ENC_REQ - * - * @param connsm - * @param err - * - * @return int - */ -int -ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm) -{ - int rc; - struct os_mbuf *om; - - om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN, - sizeof(struct ble_mbuf_hdr)); - if (om) { - om->om_data[0] = BLE_LL_CTRL_START_ENC_REQ; - ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, 1); - - /* Wait for LL_START_ENC_RSP. If there is already procedure in progress, - * LL response timer is already running. - */ - if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_IDLE) { - connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_ENCRYPT; - ble_ll_ctrl_start_rsp_timer(connsm); - } - - rc = 0; - } else { - rc = -1; - } - return rc; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) -static void -ble_ll_ctrl_cis_create(struct ble_ll_conn_sm *connsm, uint8_t *dptr) -{ - /* TODO Implement */ - return; -} -#endif - -/** - * Create a link layer control "encrypt request" PDU. - * - * The LL_ENC_REQ PDU format is: - * Rand (8) - * EDIV (2) - * SKDm (8) - * IVm (4) - * - * The random number and encrypted diversifier come from the host command. - * Controller generates master portion of SDK and IV. - * - * NOTE: this function does not set the LL data pdu header nor does it - * set the opcode in the buffer. - * - * @param connsm - * @param dptr: Pointer to where control pdu payload starts - */ -static void -ble_ll_ctrl_enc_req_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr) -{ - put_le64(dptr, connsm->enc_data.host_rand_num); - put_le16(dptr + 8, connsm->enc_data.enc_div); - -#ifdef BLE_LL_ENCRYPT_USE_TEST_DATA - /* IV stored LSB to MSB, IVm is LSB, IVs is MSB */ - put_le64(dptr + 10, g_bletest_SKDm); - swap_buf(connsm->enc_data.enc_block.plain_text + 8, dptr + 10, 8); - put_le32(dptr + 18, g_bletest_IVm); - memcpy(connsm->enc_data.iv, dptr + 18, 4); - return; -#endif - - ble_ll_rand_data_get(connsm->enc_data.enc_block.plain_text + 8, 8); - swap_buf(dptr + 10, connsm->enc_data.enc_block.plain_text + 8, 8); - ble_ll_rand_data_get(connsm->enc_data.iv, 4); - memcpy(dptr + 18, connsm->enc_data.iv, 4); -} - -/** - * Called when LL_ENC_RSP is received by the master. - * - * Context: Link Layer Task. - * - * Format of the LL_ENC_RSP is: - * SKDs (8) - * IVs (4) - * - * The master now has the long term key (from the start encrypt command) - * and the SKD (stored in the plain text encryption block). From this the - * sessionKey is generated. - * - * @param connsm - * @param dptr - */ -static void -ble_ll_ctrl_rx_enc_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr) -{ - /* Calculate session key now that we have received the ENC_RSP */ - if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_ENCRYPT) { - /* In case we were already encrypted we need to reset packet counters */ - connsm->enc_data.rx_pkt_cntr = 0; - connsm->enc_data.tx_pkt_cntr = 0; - connsm->enc_data.tx_encrypted = 0; - - swap_buf(connsm->enc_data.enc_block.plain_text, dptr, 8); - memcpy(connsm->enc_data.iv + 4, dptr + 8, 4); - ble_ll_calc_session_key(connsm); - connsm->enc_data.enc_state = CONN_ENC_S_START_ENC_REQ_WAIT; - } -} - -/** - * Called when we have received a LL control encryption request PDU. This - * should only be received by a slave. - * - * The LL_ENC_REQ PDU format is: - * Rand (8) - * EDIV (2) - * SKDm (8) - * IVm (4) - * - * This function returns the response opcode. Typically this will be ENC_RSP - * but it could be a reject ind. Note that the caller of this function - * will send the REJECT_IND_EXT if supported by remote. - * - * NOTE: if this is received by a master we will silently discard the PDU - * (denoted by return BLE_ERR_MAX). - * - * @param connsm - * @param dptr Pointer to start of encrypt request data. - * @param rspbuf - */ -static uint8_t -ble_ll_ctrl_rx_enc_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *rspdata) -{ - if (connsm->conn_role != BLE_LL_CONN_ROLE_SLAVE) { - return BLE_LL_CTRL_UNKNOWN_RSP; - } - - connsm->enc_data.enc_state = CONN_ENC_S_ENC_RSP_TO_BE_SENT; - - /* In case we were already encrypted we need to reset packet counters */ - connsm->enc_data.rx_pkt_cntr = 0; - connsm->enc_data.tx_pkt_cntr = 0; - connsm->enc_data.tx_encrypted = 0; - - /* Extract information from request */ - connsm->enc_data.host_rand_num = get_le64(dptr); - connsm->enc_data.enc_div = get_le16(dptr + 8); - -#if BLE_LL_ENCRYPT_USE_TEST_DATA - swap_buf(connsm->enc_data.enc_block.plain_text + 8, dptr + 10, 8); - memcpy(connsm->enc_data.iv, dptr + 18, 4); - - put_le64(rspdata, g_bletest_SKDs); - swap_buf(connsm->enc_data.enc_block.plain_text, rspdata, 8); - put_le32(rspdata + 8, g_bletest_IVs); - memcpy(connsm->enc_data.iv + 4, rspdata + 8, 4); - return BLE_LL_CTRL_ENC_RSP; -#endif - - swap_buf(connsm->enc_data.enc_block.plain_text + 8, dptr + 10, 8); - memcpy(connsm->enc_data.iv, dptr + 18, 4); - - /* Create the ENC_RSP. Concatenate our SKD and IV */ - ble_ll_rand_data_get(connsm->enc_data.enc_block.plain_text, 8); - swap_buf(rspdata, connsm->enc_data.enc_block.plain_text, 8); - ble_ll_rand_data_get(connsm->enc_data.iv + 4, 4); - memcpy(rspdata + 8, connsm->enc_data.iv + 4, 4); - - return BLE_LL_CTRL_ENC_RSP; -} - -static uint8_t -ble_ll_ctrl_rx_start_enc_req(struct ble_ll_conn_sm *connsm) -{ - int rc; - - /* Only master should receive start enc request */ - rc = BLE_ERR_MAX; - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - /* We only want to send a START_ENC_RSP if we havent yet */ - if (connsm->enc_data.enc_state == CONN_ENC_S_START_ENC_REQ_WAIT) { - connsm->enc_data.enc_state = CONN_ENC_S_START_ENC_RSP_WAIT; - rc = BLE_LL_CTRL_START_ENC_RSP; - } - } else { - rc = BLE_LL_CTRL_UNKNOWN_RSP; - } - return rc; -} - -static uint8_t -ble_ll_ctrl_rx_pause_enc_req(struct ble_ll_conn_sm *connsm) -{ - int rc; - - /* - * The spec does not say what to do here, but if we receive a pause - * encryption request and we are not encrypted, what do we do? We - * ignore it... - */ - rc = BLE_ERR_MAX; - if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && - (connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED)) { - rc = BLE_LL_CTRL_PAUSE_ENC_RSP; - } else { - rc = BLE_LL_CTRL_UNKNOWN_RSP; - } - - return rc; -} - -/** - * Called when a LL control pdu with opcode PAUSE_ENC_RSP is received. - * - * - * @param connsm - * - * @return uint8_t - */ -static uint8_t -ble_ll_ctrl_rx_pause_enc_rsp(struct ble_ll_conn_sm *connsm) -{ - int rc; - - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - rc = BLE_LL_CTRL_PAUSE_ENC_RSP; - } else if (connsm->enc_data.enc_state == CONN_ENC_S_PAUSE_ENC_RSP_WAIT) { - /* Master sends back unencrypted LL_PAUSE_ENC_RSP. - * From this moment encryption is paused. - */ - rc = BLE_ERR_MAX; - connsm->enc_data.enc_state = CONN_ENC_S_PAUSED; - } else { - rc = BLE_LL_CTRL_UNKNOWN_RSP; - } - - return rc; -} - -/** - * Called when we have received a LL_CTRL_START_ENC_RSP. - * - * Context: Link-layer task - * - * @param connsm - * - * @return uint8_t - */ -static uint8_t -ble_ll_ctrl_rx_start_enc_rsp(struct ble_ll_conn_sm *connsm) -{ - int rc; - - /* Not in proper state. Discard */ - if (connsm->enc_data.enc_state != CONN_ENC_S_START_ENC_RSP_WAIT) { - return BLE_ERR_MAX; - } - - /* If master, we are done. Stop control procedure and sent event to host */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_ENCRYPT); - - /* We are encrypted */ - connsm->enc_data.enc_state = CONN_ENC_S_ENCRYPTED; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) - ble_ll_conn_auth_pyld_timer_start(connsm); -#endif - rc = BLE_ERR_MAX; - } else { - /* Procedure has completed but slave needs to send START_ENC_RSP */ - rc = BLE_LL_CTRL_START_ENC_RSP; - - /* Stop timer if it was started when sending START_ENC_REQ */ - if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_ENCRYPT) { - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_ENCRYPT); - } - } - - /* - * XXX: for now, a Slave sends this event when it receivest the - * START_ENC_RSP from the master. It might be technically incorrect - * to send it before we transmit our own START_ENC_RSP. - */ - ble_ll_hci_ev_encrypt_chg(connsm, BLE_ERR_SUCCESS); - - return rc; -} - -#endif - -/** - * Called to make a connection parameter request or response control pdu. - * - * @param connsm - * @param dptr Pointer to start of data. NOTE: the opcode is not part - * of the data. - */ -static void -ble_ll_ctrl_conn_param_pdu_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - struct ble_ll_conn_params *req) -{ - uint16_t offset; - struct hci_conn_update *hcu; - - /* If we were passed in a request, we use the parameters from the request */ - if (req) { - put_le16(dptr, req->interval_min); - put_le16(dptr + 2, req->interval_max); - put_le16(dptr + 4, req->latency); - put_le16(dptr + 6, req->timeout); - } else { - hcu = &connsm->conn_param_req; - /* The host should have provided the parameters! */ - BLE_LL_ASSERT(hcu->handle != 0); - put_le16(dptr, hcu->conn_itvl_min); - put_le16(dptr + 2, hcu->conn_itvl_max); - put_le16(dptr + 4, hcu->conn_latency); - put_le16(dptr + 6, hcu->supervision_timeout); - } - - /* XXX: NOTE: if interval min and interval max are != to each - * other this value should be set to non-zero. I think this - * applies only when an offset field is set. See section 5.1.7.1 pg 103 - * Vol 6 Part B. - */ - /* XXX: for now, set periodicity to 0 */ - dptr[8] = 0; - - /* XXX: deal with reference event count. what to put here? */ - put_le16(dptr + 9, connsm->event_cntr); - - /* XXX: For now, dont use offsets */ - offset = 0xFFFF; - put_le16(dptr + 11, offset); - put_le16(dptr + 13, offset); - put_le16(dptr + 15, offset); - put_le16(dptr + 17, offset); - put_le16(dptr + 19, offset); - put_le16(dptr + 21, offset); -} - -static void -ble_ll_ctrl_version_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld) -{ - /* Set flag to denote we have sent/received this */ - connsm->csmflags.cfbit.version_ind_sent = 1; - - /* Fill out response */ - pyld[0] = BLE_HCI_VER_BCS; - put_le16(pyld + 1, MYNEWT_VAL(BLE_LL_MFRG_ID)); - put_le16(pyld + 3, BLE_LL_SUB_VERS_NR); -} - -/** - * Called to make a LL control channel map request PDU. - * - * @param connsm Pointer to connection state machine - * @param pyld Pointer to payload of LL control PDU - */ -static void -ble_ll_ctrl_chanmap_req_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld) -{ - /* Copy channel map that host desires into request */ - memcpy(pyld, g_ble_ll_conn_params.master_chan_map, BLE_LL_CONN_CHMAP_LEN); - memcpy(connsm->req_chanmap, pyld, BLE_LL_CONN_CHMAP_LEN); - - /* Place instant into request */ - connsm->chanmap_instant = connsm->event_cntr + connsm->slave_latency + 6 + 1; - put_le16(pyld + BLE_LL_CONN_CHMAP_LEN, connsm->chanmap_instant); - - /* Set scheduled flag */ - connsm->csmflags.cfbit.chanmap_update_scheduled = 1; -} - -/** - * Called to respond to a LL control PDU connection parameter request or - * response. - * - * @param connsm - * @param rsp - * @param req - * - * @return uint8_t - */ -uint8_t -ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm, uint8_t *rsp, - struct ble_ll_conn_params *req) -{ - uint8_t rsp_opcode; - - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - /* Create a connection parameter response */ - ble_ll_ctrl_conn_param_pdu_make(connsm, rsp + 1, req); - rsp_opcode = BLE_LL_CTRL_CONN_PARM_RSP; - } else { - /* Create a connection update pdu */ - ble_ll_ctrl_conn_upd_make(connsm, rsp + 1, req); - rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_IND; - } - - return rsp_opcode; -} - -/** - * Called when we have received a LL_REJECT_IND or LL_REJECT_IND_EXT link - * layer control Data Channel pdu. - * - * @param connsm - * @param dptr - * @param opcode - */ -static int -ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t opcode, uint8_t *rspdata) -{ - uint8_t ble_error; - uint8_t rsp_opcode = BLE_ERR_MAX; - - /* Get error out of received PDU */ - if (opcode == BLE_LL_CTRL_REJECT_IND) { - ble_error = dptr[0]; - } else { - ble_error = dptr[1]; - } - - /* XXX: should I check to make sure the rejected opcode is sane - if we receive ind ext? */ - switch (connsm->cur_ctrl_proc) { - case BLE_LL_CTRL_PROC_CONN_PARAM_REQ: - if (opcode == BLE_LL_CTRL_REJECT_IND_EXT) { - /* As a master we should send connection update indication in this point */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_IND; - ble_ll_ctrl_conn_upd_make(connsm, rspdata, NULL); - connsm->reject_reason = BLE_ERR_SUCCESS; - } else { - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ); - ble_ll_hci_ev_conn_update(connsm, ble_error); - } - } - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - case BLE_LL_CTRL_PROC_ENCRYPT: - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_ENCRYPT); - ble_ll_hci_ev_encrypt_chg(connsm, ble_error); - connsm->enc_data.enc_state = CONN_ENC_S_UNENCRYPTED; - break; -#endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - case BLE_LL_CTRL_PROC_PHY_UPDATE: - ble_ll_ctrl_phy_update_cancel(connsm, ble_error); - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); - break; -#endif - case BLE_LL_CTRL_PROC_DATA_LEN_UPD: - /* That should not happen according to Bluetooth 5.0 Vol6 Part B, 5.1.9 - * However we need this workaround as there are devices on the market - * which do send LL_REJECT on LL_LENGTH_REQ when collision happens - */ - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD); - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) - case BLE_LL_CTRL_PROC_SCA_UPDATE: - ble_ll_hci_ev_sca_update(connsm, ble_error, 0); - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE); - break; -#endif - default: - break; - } - - return rsp_opcode; -} - -/** - * Called when we receive a connection update event - * - * @param connsm - * @param dptr - * - * @return int - */ -static int -ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm *connsm, uint8_t *dptr) -{ - uint8_t rsp_opcode; - uint16_t conn_events; - struct ble_ll_conn_upd_req *reqdata; - - /* Only a slave should receive this */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - return BLE_LL_CTRL_UNKNOWN_RSP; - } - - /* Retrieve parameters */ - reqdata = &connsm->conn_update_req; - reqdata->winsize = dptr[0]; - reqdata->winoffset = get_le16(dptr + 1); - reqdata->interval = get_le16(dptr + 3); - reqdata->latency = get_le16(dptr + 5); - reqdata->timeout = get_le16(dptr + 7); - reqdata->instant = get_le16(dptr + 9); - - /* XXX: validate them at some point. If they dont check out, we - return the unknown response */ - rsp_opcode = BLE_ERR_MAX; - - /* If instant is in the past, we have to end the connection */ - conn_events = (reqdata->instant - connsm->event_cntr) & 0xFFFF; - if (conn_events >= 32767) { - ble_ll_conn_timeout(connsm, BLE_ERR_INSTANT_PASSED); - } else { - connsm->csmflags.cfbit.conn_update_sched = 1; - - /* - * Errata says that receiving a connection update when the event - * counter is equal to the instant means wesimply ignore the window - * offset and window size. Anchor point has already been set based on - * first packet received in connection event. Given that we increment - * the event counter BEFORE checking to see if the instant is equal to - * the event counter what we do here is increment the instant and set - * the window offset and size to 0. - */ - if (conn_events == 0) { - reqdata->winoffset = 0; - reqdata->winsize = 0; - reqdata->instant += 1; - } - } - - return rsp_opcode; -} - -void -ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm) -{ - if (!(connsm->conn_features & BLE_LL_FEAT_DATA_LEN_EXT)) { - return; - } - - /* - * Section 4.5.10 Vol 6 PART B. If the max tx/rx time or octets - * exceeds the minimum, data length procedure needs to occur - */ - if ((connsm->max_tx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) && - (connsm->max_rx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) && - (connsm->max_tx_time <= BLE_LL_CONN_SUPP_TIME_MIN) && - (connsm->max_rx_time <= BLE_LL_CONN_SUPP_TIME_MIN)) { - return; - } - - ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD); -} - -static void -ble_ll_ctrl_update_features(struct ble_ll_conn_sm *connsm, uint8_t *feat) -{ - connsm->conn_features = feat[0]; - memcpy(connsm->remote_features, feat + 1, 7); - - /* If we received peer's features for the 1st time, we should try DLE */ - if (!connsm->csmflags.cfbit.rxd_features) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - /* - * If connection was established on uncoded PHY, by default we use - * MaxTxTime and MaxRxTime applicable for that PHY since we are not - * allowed to indicate longer supported time if peer does not support - * LE Coded PHY. However, once we know that peer does support it we can - * update those values to ones applicable for coded PHY. - */ - if (connsm->remote_features[0] & (BLE_LL_FEAT_LE_CODED_PHY >> 8)) { - if (connsm->host_req_max_tx_time) { - connsm->max_tx_time = max(connsm->max_tx_time, - connsm->host_req_max_tx_time); - } else { - connsm->max_tx_time = g_ble_ll_conn_params.conn_init_max_tx_time_coded; - } - connsm->max_rx_time = BLE_LL_CONN_SUPP_TIME_MAX_CODED; - } -#endif - - connsm->csmflags.cfbit.pending_initiate_dle = 1; - connsm->csmflags.cfbit.rxd_features = 1; - } -} - -/** - * Called when we receive a feature request or a slave initiated feature - * request. - * - * - * @param connsm - * @param dptr - * @param rspbuf - * @param opcode - * @param new_features - * - * @return int - */ -static int -ble_ll_ctrl_rx_feature_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *rspbuf, uint8_t opcode) -{ - uint8_t rsp_opcode; - uint64_t our_feat; - - /* - * Only accept slave feature requests if we are a master and feature - * requests if we are a slave. - */ - if (opcode == BLE_LL_CTRL_SLAVE_FEATURE_REQ) { - if (connsm->conn_role != BLE_LL_CONN_ROLE_MASTER) { - return BLE_LL_CTRL_UNKNOWN_RSP; - } - } else { - /* XXX: not sure this is correct but do it anyway */ - if (connsm->conn_role != BLE_LL_CONN_ROLE_SLAVE) { - return BLE_LL_CTRL_UNKNOWN_RSP; - } - } - - our_feat = ble_ll_read_supp_features(); - - rsp_opcode = BLE_LL_CTRL_FEATURE_RSP; - - ble_ll_ctrl_update_features(connsm, dptr); - - /* - * 1st octet of features should be common features of local and remote - * controller - we call this 'connection features' - * remaining octets are features of controller which sends PDU, in this case - * it's our controller - * - * See: Vol 6, Part B, section 2.4.2.10 - */ - connsm->conn_features &= our_feat; - - put_le64(rspbuf + 1, our_feat); - rspbuf[1] = connsm->conn_features; - - return rsp_opcode; -} - -/** - * Called when we receive a feature response - * - * @param connsm - * @param dptr - * @param new_features - * - */ -static void -ble_ll_ctrl_rx_feature_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr) -{ - ble_ll_ctrl_update_features(connsm, dptr); - - /* Stop the control procedure */ - if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG)) { - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG); - } - - /* Send event to host if pending features read */ - if (connsm->csmflags.cfbit.pending_hci_rd_features) { - ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; - } -} - -/** - * - * - * Context: Link Layer task - * - * @param connsm - * @param dptr - * @param rspbuf - * - * @return int - */ -static int -ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *rspbuf) -{ - uint8_t rsp_opcode; - - /* - * This is not in the specification per se but it simplifies the - * implementation. If we get a connection parameter request and we - * are awaiting a reply from the host, simply ignore the request. This - * might not be a good idea if the parameters are different, but oh - * well. This is not expected to happen anyway. A return of BLE_ERR_MAX - * means that we will simply discard the connection parameter request - */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { - return BLE_ERR_MAX; - } - - /* XXX: remember to deal with this on the master: if the slave has - * initiated a procedure we may have received its connection parameter - * update request and have signaled the host with an event. If that - * is the case, we will need to drop the host command when we get it - and also clear any applicable states. */ - - /* XXX: Read 5.3 again. There are multiple control procedures that might - * be pending (a connection update) that will cause collisions and the - behavior below. */ - /* - * Check for procedure collision (Vol 6 PartB 5.3). If we are a slave - * and we receive a request we "consider the slave initiated - * procedure as complete". This means send a connection update complete - * event (with error). - * - * If a master, we send reject with a - * transaction collision error code. - */ - if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ); - ble_ll_hci_ev_conn_update(connsm, BLE_ERR_LMP_COLLISION); - } else { - /* The master sends reject ind ext w/error code 0x23 */ - rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT; - rspbuf[1] = BLE_LL_CTRL_CONN_PARM_REQ; - rspbuf[2] = BLE_ERR_LMP_COLLISION; - return rsp_opcode; - } - } - - /* - * If we are a master and we currently performing a channel map - * update procedure we need to return an error - */ - if ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) && - (connsm->csmflags.cfbit.chanmap_update_scheduled)) { - rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT; - rspbuf[1] = BLE_LL_CTRL_CONN_PARM_REQ; - rspbuf[2] = BLE_ERR_DIFF_TRANS_COLL; - return rsp_opcode; - } - - /* Process the received connection parameter request */ - rsp_opcode = ble_ll_ctrl_conn_param_pdu_proc(connsm, dptr, rspbuf, - BLE_LL_CTRL_CONN_PARM_REQ); - return rsp_opcode; -} - -static int -ble_ll_ctrl_rx_conn_param_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *rspbuf) -{ - uint8_t rsp_opcode; - - /* A slave should never receive this response */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - return BLE_LL_CTRL_UNKNOWN_RSP; - } - - /* - * This case should never happen! It means that the slave initiated a - * procedure and the master initiated one as well. If we do get in this - * state just clear the awaiting reply. The slave will hopefully stop its - * procedure when we reply. - */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { - connsm->csmflags.cfbit.awaiting_host_reply = 0; - } - - /* If we receive a response and no procedure is pending, just leave */ - if (!IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) { - return BLE_ERR_MAX; - } - - /* Process the received connection parameter response */ - rsp_opcode = ble_ll_ctrl_conn_param_pdu_proc(connsm, dptr, rspbuf, - BLE_LL_CTRL_CONN_PARM_RSP); - return rsp_opcode; -} - -/** - * Called to process the LL control PDU VERSION_IND - * - * Context: Link Layer task - * - * @param connsm - * @param dptr - * @param rspbuf - * - * @return int - */ -static int -ble_ll_ctrl_rx_version_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *rspbuf) -{ - uint8_t rsp_opcode; - - /* Process the packet */ - connsm->vers_nr = dptr[0]; - connsm->comp_id = get_le16(dptr + 1); - connsm->sub_vers_nr = get_le16(dptr + 3); - connsm->csmflags.cfbit.rxd_version_ind = 1; - - rsp_opcode = BLE_ERR_MAX; - if (!connsm->csmflags.cfbit.version_ind_sent) { - rsp_opcode = BLE_LL_CTRL_VERSION_IND; - ble_ll_ctrl_version_ind_make(connsm, rspbuf); - } - - /* Stop the control procedure */ - if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG)) { - ble_ll_hci_ev_rd_rem_ver(connsm, BLE_ERR_SUCCESS); - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG); - } - return rsp_opcode; -} - -/** - * Called to process a received channel map request control pdu. - * - * Context: Link Layer task - * - * @param connsm - * @param dptr - */ -static int -ble_ll_ctrl_rx_chanmap_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr) -{ - uint16_t instant; - uint16_t conn_events; - - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - return BLE_LL_CTRL_UNKNOWN_RSP; - } - - /* If instant is in the past, we have to end the connection */ - instant = get_le16(dptr + BLE_LL_CONN_CHMAP_LEN); - conn_events = (instant - connsm->event_cntr) & 0xFFFF; - if (conn_events >= 32767) { - ble_ll_conn_timeout(connsm, BLE_ERR_INSTANT_PASSED); - } else { - connsm->chanmap_instant = instant; - memcpy(connsm->req_chanmap, dptr, BLE_LL_CONN_CHMAP_LEN); - connsm->csmflags.cfbit.chanmap_update_scheduled = 1; - } - - return BLE_ERR_MAX; -} - -/** - * Initiate LL control procedure. - * - * This function is called to obtain a mbuf to send a LL control PDU. The data - * channel PDU header is not part of the mbuf data; it is part of the BLE - * header (which is part of the mbuf). - * - * Context: LL task. - * - * @param connsm - * @param ctrl_proc - */ -static struct os_mbuf * -ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc) -{ - uint8_t len; - uint8_t opcode; - uint8_t *dptr; - uint8_t *ctrdata; - struct os_mbuf *om; - - /* Get an mbuf for the control pdu */ - om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN, sizeof(struct ble_mbuf_hdr)); - - if (om) { - /* The control data starts after the opcode (1 byte) */ - dptr = om->om_data; - ctrdata = dptr + 1; - - switch (ctrl_proc) { - case BLE_LL_CTRL_PROC_CONN_UPDATE: - opcode = BLE_LL_CTRL_CONN_UPDATE_IND; - ble_ll_ctrl_conn_upd_make(connsm, ctrdata, NULL); - break; - case BLE_LL_CTRL_PROC_CHAN_MAP_UPD: - opcode = BLE_LL_CTRL_CHANNEL_MAP_REQ; - ble_ll_ctrl_chanmap_req_make(connsm, ctrdata); - break; - case BLE_LL_CTRL_PROC_FEATURE_XCHG: - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - opcode = BLE_LL_CTRL_FEATURE_REQ; - } else { - opcode = BLE_LL_CTRL_SLAVE_FEATURE_REQ; - } - put_le64(ctrdata, ble_ll_read_supp_features()); - break; - case BLE_LL_CTRL_PROC_VERSION_XCHG: - opcode = BLE_LL_CTRL_VERSION_IND; - ble_ll_ctrl_version_ind_make(connsm, ctrdata); - break; - case BLE_LL_CTRL_PROC_TERMINATE: - opcode = BLE_LL_CTRL_TERMINATE_IND; - ctrdata[0] = connsm->disconnect_reason; - break; - case BLE_LL_CTRL_PROC_CONN_PARAM_REQ: - opcode = BLE_LL_CTRL_CONN_PARM_REQ; - ble_ll_ctrl_conn_param_pdu_make(connsm, ctrdata, NULL); - break; - case BLE_LL_CTRL_PROC_LE_PING: - opcode = BLE_LL_CTRL_PING_REQ; - break; - case BLE_LL_CTRL_PROC_DATA_LEN_UPD: - opcode = BLE_LL_CTRL_LENGTH_REQ; - ble_ll_ctrl_datalen_upd_make(connsm, dptr); - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - /* XXX: deal with already encrypted connection.*/ - case BLE_LL_CTRL_PROC_ENCRYPT: - /* If we are already encrypted we do pause procedure */ - if (connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED) { - opcode = BLE_LL_CTRL_PAUSE_ENC_REQ; - } else { - opcode = BLE_LL_CTRL_ENC_REQ; - ble_ll_ctrl_enc_req_make(connsm, ctrdata); - } - break; -#endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - case BLE_LL_CTRL_PROC_PHY_UPDATE: - opcode = BLE_LL_CTRL_PHY_REQ; - ble_ll_ctrl_phy_req_rsp_make(connsm, ctrdata); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) - case BLE_LL_CTRL_PROC_SCA_UPDATE: - opcode = BLE_LL_CTRL_CLOCK_ACCURACY_REQ; - ble_ll_ctrl_sca_req_rsp_make(connsm, ctrdata); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) - case BLE_LL_CTRL_PROC_CIS_CREATE: - opcode = BLE_LL_CTRL_CIS_REQ; - ble_ll_ctrl_cis_create(connsm, ctrdata); - break; -#endif - default: - BLE_LL_ASSERT(0); - break; - } - - /* Set llid, length and opcode */ - dptr[0] = opcode; - len = g_ble_ll_ctrl_pkt_lengths[opcode] + 1; - - /* Add packet to transmit queue of connection */ - ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len); - } - - return om; -} - -/** - * Called to determine if the pdu is a TERMINATE_IND - * - * @param hdr - * @param opcode - * - * @return int - */ -int -ble_ll_ctrl_is_terminate_ind(uint8_t hdr, uint8_t opcode) -{ - int rc; - - rc = 0; - if ((hdr & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) { - if (opcode == BLE_LL_CTRL_TERMINATE_IND) { - rc = 1; - } - } - return rc; -} - -/** - * Stops the LL control procedure indicated by 'ctrl_proc'. - * - * Context: Link Layer task - * - * @param connsm - * @param ctrl_proc - */ -void -ble_ll_ctrl_proc_stop(struct ble_ll_conn_sm *connsm, int ctrl_proc) -{ - if (connsm->cur_ctrl_proc == ctrl_proc) { - ble_npl_callout_stop(&connsm->ctrl_proc_rsp_timer); - connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE; - } - CLR_PENDING_CTRL_PROC(connsm, ctrl_proc); - - /* If there are others, start them */ - ble_ll_ctrl_chk_proc_start(connsm); -} - -/** - * Called to start the terminate procedure. - * - * Context: Link Layer task. - * - * @param connsm - */ -void -ble_ll_ctrl_terminate_start(struct ble_ll_conn_sm *connsm) -{ - int ctrl_proc; - uint32_t usecs; - struct os_mbuf *om; - - BLE_LL_ASSERT(connsm->disconnect_reason != 0); - - ctrl_proc = BLE_LL_CTRL_PROC_TERMINATE; - om = ble_ll_ctrl_proc_init(connsm, ctrl_proc); - if (om) { - CONN_F_TERMINATE_STARTED(connsm) = 1; - - /* Set terminate "timeout" */ - usecs = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000; - connsm->terminate_timeout = os_cputime_get32() + - os_cputime_usecs_to_ticks(usecs); - } -} - -/** - * Called to start a LL control procedure except for the terminate procedure. We - * always set the control procedure pending bit even if the control procedure - * has been initiated. - * - * Context: Link Layer task. - * - * @param connsm Pointer to connection state machine. - */ -void -ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc) -{ - struct os_mbuf *om; - - BLE_LL_ASSERT(ctrl_proc != BLE_LL_CTRL_PROC_TERMINATE); - - om = NULL; - if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_IDLE) { - /* Initiate the control procedure. */ - om = ble_ll_ctrl_proc_init(connsm, ctrl_proc); - if (om) { - /* Set the current control procedure */ - connsm->cur_ctrl_proc = ctrl_proc; - - /* Initialize the procedure response timeout */ - if (ctrl_proc != BLE_LL_CTRL_PROC_CHAN_MAP_UPD) { - ble_ll_ctrl_start_rsp_timer(connsm); - } - } - } - - /* Set bitmask denoting control procedure is pending */ - connsm->pending_ctrl_procs |= (1 << ctrl_proc); -} - -/** - * Called to determine if we need to start a LL control procedure for the given - * connection. - * - * Context: Link Layer - * - * @param connsm Pointer to connection state machine. - */ -void -ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm) -{ - int i; - - /* XXX: TODO new rules! Cannot start certain control procedures if other - * ones are peer initiated. We need to wait. Deal with this. - */ - - /* - * If we are terminating, dont start any new procedures but start - * terminate if needed - */ - if (connsm->disconnect_reason) { - if (!CONN_F_TERMINATE_STARTED(connsm)) { - /* - * If the terminate procedure has not started it means we were not - * able to start it right away (no control pdu was available). - * Start it now. No need to start any other procedures. - */ - ble_ll_ctrl_terminate_start(connsm); - } - return; - } - - /* If there is a running procedure or no pending, do nothing */ - if ((connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_IDLE) && - (connsm->pending_ctrl_procs != 0)) { - /* - * The specification says there is no priority to control procedures - * so just start from the first one for now. - */ - for (i = 0; i < BLE_LL_CTRL_PROC_NUM; ++i) { - if (IS_PENDING_CTRL_PROC(connsm, i)) { - /* - * The version exchange is a special case. If we have already - * received the information dont start it. - */ - if ((i == BLE_LL_CTRL_PROC_VERSION_XCHG) && - (connsm->csmflags.cfbit.rxd_version_ind)) { - ble_ll_hci_ev_rd_rem_ver(connsm, BLE_ERR_SUCCESS); - CLR_PENDING_CTRL_PROC(connsm, i); - } else { - ble_ll_ctrl_proc_start(connsm, i); - break; - } - } - } - } -} - -/** - * Called when the Link Layer receives a LL control PDU. - * - * NOTE: this function uses the received PDU for the response in some cases. If - * the received PDU is not used it needs to be freed here. - * - * XXX: may want to check, for both master and slave, whether the control - * pdu should be received by that role. Might make for less code... - * Context: Link Layer - * - * @param om - * @param connsm - */ -int -ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) -{ - uint32_t features; - uint32_t feature; - uint8_t len; - uint8_t opcode; - uint8_t rsp_opcode; - uint8_t *dptr; - uint8_t *rspbuf; - uint8_t *rspdata; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - int restart_encryption; -#endif - int rc = 0; - - /* XXX: where do we validate length received and packet header length? - * do this in LL task when received. Someplace!!! What I mean - * is we should validate the over the air length with the mbuf length. - Should the PHY do that???? */ - - /* - * dptr points to om_data pointer. The first byte of om_data is the - * first byte of the Data Channel PDU header. Get length from header and - * opcode from LL control PDU. - */ - dptr = om->om_data; - len = dptr[1]; - opcode = dptr[2]; - - /* - * rspbuf points to first byte of response. The response buffer does not - * contain the Data Channel PDU. Thus, the first byte of rspbuf is the - * LL control PDU payload (the opcode of the control PDU). rspdata - * points to CtrData in the control PDU. - */ - rspbuf = dptr; - rspdata = rspbuf + 1; - - /* Move data pointer to start of control data (2 byte PDU hdr + opcode) */ - dptr += (BLE_LL_PDU_HDR_LEN + 1); - - /* - * Subtract the opcode from the length. Note that if the length was zero, - * which would be an error, we will fail the check against the length - * of the control packet. - */ - --len; - - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_CTRL_RX, opcode, len); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - restart_encryption = 0; -#endif - - /* If opcode comes from reserved value or CtrlData fields is invalid - * we shall respond with LL_UNKNOWN_RSP - */ - if ((opcode >= BLE_LL_CTRL_OPCODES) || - (len != g_ble_ll_ctrl_pkt_lengths[opcode])) { - rc = -1; - rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP; - goto ll_ctrl_send_rsp; - } - - /* Check if the feature is supported. */ - switch (opcode) { - case BLE_LL_CTRL_LENGTH_REQ: - feature = BLE_LL_FEAT_DATA_LEN_EXT; - break; - case BLE_LL_CTRL_SLAVE_FEATURE_REQ: - feature = BLE_LL_FEAT_SLAVE_INIT; - break; - case BLE_LL_CTRL_CONN_PARM_REQ: - case BLE_LL_CTRL_CONN_PARM_RSP: - feature = BLE_LL_FEAT_CONN_PARM_REQ; - break; - case BLE_LL_CTRL_ENC_REQ: - case BLE_LL_CTRL_START_ENC_REQ: - case BLE_LL_CTRL_PAUSE_ENC_REQ: - feature = BLE_LL_FEAT_LE_ENCRYPTION; - break; - case BLE_LL_CTRL_PING_REQ: - feature = BLE_LL_FEAT_LE_PING; - break; - case BLE_LL_CTRL_PHY_REQ: - feature = BLE_LL_FEAT_LE_2M_PHY | BLE_LL_FEAT_LE_CODED_PHY; - break; - case BLE_LL_CTRL_MIN_USED_CHAN_IND: - feature = BLE_LL_FEAT_MIN_USED_CHAN; - break; - case BLE_LL_CTRL_PERIODIC_SYNC_IND: - feature = BLE_LL_FEAT_SYNC_TRANS_RECV; - break; - default: - feature = 0; - break; - } - - if (feature) { - features = ble_ll_read_supp_features(); - if ((features & feature) == 0) { - if (opcode == BLE_LL_CTRL_ENC_REQ) { - if (connsm->conn_features & BLE_LL_FEAT_EXTENDED_REJ) { - rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT; - rspbuf[1] = opcode; - rspbuf[2] = BLE_ERR_UNSUPP_REM_FEATURE; - - } else { - rsp_opcode = BLE_LL_CTRL_REJECT_IND; - rspbuf[1] = BLE_ERR_UNSUPP_REM_FEATURE; - } - } else { - /* Construct unknown rsp pdu */ - rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP; - } - goto ll_ctrl_send_rsp; - } - } - - /* Process opcode */ - rsp_opcode = BLE_ERR_MAX; - switch (opcode) { - case BLE_LL_CTRL_CONN_UPDATE_IND: - rsp_opcode = ble_ll_ctrl_rx_conn_update(connsm, dptr); - break; - case BLE_LL_CTRL_CHANNEL_MAP_REQ: - rsp_opcode = ble_ll_ctrl_rx_chanmap_req(connsm, dptr); - break; - case BLE_LL_CTRL_LENGTH_REQ: - /* Extract parameters and check if valid */ - if (ble_ll_ctrl_len_proc(connsm, dptr)) { - rc = -1; - rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP; - goto ll_ctrl_send_rsp; - } - - /* - * If we have not started this procedure ourselves and it is - * pending, no need to perform it. - */ - if ((connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_DATA_LEN_UPD) && - IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD)) { - CLR_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD); - } - - /* Send a response */ - rsp_opcode = BLE_LL_CTRL_LENGTH_RSP; - ble_ll_ctrl_datalen_upd_make(connsm, rspbuf); - break; - case BLE_LL_CTRL_LENGTH_RSP: - /* According to specification, process this only if we asked for it. */ - if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_DATA_LEN_UPD) { - /* - * Process the received data. If received data is invalid, we'll - * reply with LL_UNKNOWN_RSP as per spec, but we still need to stop - * control procedure to avoid timeout. - */ - if (ble_ll_ctrl_len_proc(connsm, dptr)) { - rc = -1; - rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP; - } - - /* Stop the control procedure */ - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD); - } - break; - case BLE_LL_CTRL_UNKNOWN_RSP: - rsp_opcode = ble_ll_ctrl_proc_unk_rsp(connsm, dptr, rspdata); - break; - case BLE_LL_CTRL_FEATURE_REQ: - rsp_opcode = ble_ll_ctrl_rx_feature_req(connsm, dptr, rspbuf, opcode); - break; - /* XXX: check to see if ctrl procedure was running? Do we care? */ - case BLE_LL_CTRL_FEATURE_RSP: - ble_ll_ctrl_rx_feature_rsp(connsm, dptr); - break; - case BLE_LL_CTRL_VERSION_IND: - rsp_opcode = ble_ll_ctrl_rx_version_ind(connsm, dptr, rspdata); - break; - case BLE_LL_CTRL_SLAVE_FEATURE_REQ: - rsp_opcode = ble_ll_ctrl_rx_feature_req(connsm, dptr, rspbuf, opcode); - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - case BLE_LL_CTRL_ENC_REQ: - rsp_opcode = ble_ll_ctrl_rx_enc_req(connsm, dptr, rspdata); - break; - case BLE_LL_CTRL_ENC_RSP: - ble_ll_ctrl_rx_enc_rsp(connsm, dptr); - break; - case BLE_LL_CTRL_START_ENC_REQ: - rsp_opcode = ble_ll_ctrl_rx_start_enc_req(connsm); - break; - case BLE_LL_CTRL_START_ENC_RSP: - rsp_opcode = ble_ll_ctrl_rx_start_enc_rsp(connsm); - break; - case BLE_LL_CTRL_PAUSE_ENC_REQ: - rsp_opcode = ble_ll_ctrl_rx_pause_enc_req(connsm); - break; - case BLE_LL_CTRL_PAUSE_ENC_RSP: - rsp_opcode = ble_ll_ctrl_rx_pause_enc_rsp(connsm); - if (rsp_opcode == BLE_LL_CTRL_PAUSE_ENC_RSP) { - restart_encryption = 1; - } - break; -#endif - case BLE_LL_CTRL_PING_REQ: - rsp_opcode = BLE_LL_CTRL_PING_RSP; - break; - case BLE_LL_CTRL_PING_RSP: - ble_ll_ctrl_rx_ping_rsp(connsm); - break; - case BLE_LL_CTRL_CONN_PARM_REQ: - rsp_opcode = ble_ll_ctrl_rx_conn_param_req(connsm, dptr, rspbuf); - break; - case BLE_LL_CTRL_CONN_PARM_RSP: - rsp_opcode = ble_ll_ctrl_rx_conn_param_rsp(connsm, dptr, rspbuf); - break; - /* Fall-through intentional... */ - case BLE_LL_CTRL_REJECT_IND: - case BLE_LL_CTRL_REJECT_IND_EXT: - /* Sometimes reject triggers sending other LL CTRL msg */ - rsp_opcode = ble_ll_ctrl_rx_reject_ind(connsm, dptr, opcode, rspdata); - break; -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - case BLE_LL_CTRL_PHY_REQ: - rsp_opcode = ble_ll_ctrl_rx_phy_req(connsm, dptr, rspdata); - break; - case BLE_LL_CTRL_PHY_RSP: - rsp_opcode = ble_ll_ctrl_rx_phy_rsp(connsm, dptr, rspdata); - break; - case BLE_LL_CTRL_PHY_UPDATE_IND: - rsp_opcode = ble_ll_ctrl_rx_phy_update_ind(connsm, dptr); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) - case BLE_LL_CTRL_CLOCK_ACCURACY_REQ: - rsp_opcode = ble_ll_ctrl_rx_sca_req(connsm, dptr, rspdata); - break; - case BLE_LL_CTRL_CLOCK_ACCURACY_RSP: - rsp_opcode = ble_ll_ctrl_rx_sca_rsp(connsm, dptr); - break; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) - case BLE_LL_CTRL_CIS_REQ: - rsp_opcode = ble_ll_ctrl_rx_cis_req(connsm, dptr, rspdata); - break; - case BLE_LL_CTRL_CIS_RSP: - rsp_opcode = ble_ll_ctrl_rx_cis_rsp(connsm, dptr, rspdata); - break; - case BLE_LL_CTRL_CIS_IND: - rsp_opcode = ble_ll_ctrl_rx_cis_ind(connsm, dptr); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - case BLE_LL_CTRL_PERIODIC_SYNC_IND: - rsp_opcode = ble_ll_ctrl_rx_periodic_sync_ind(connsm, dptr); - break; -#endif - default: - /* Nothing to do here */ - break; - } - - /* Free mbuf or send response */ -ll_ctrl_send_rsp: - if (rsp_opcode == BLE_ERR_MAX) { - os_mbuf_free_chain(om); - } else { - /* - * Write the response opcode into the buffer. If this is an unknown - * response, put opcode of unknown pdu into buffer. - */ - rspbuf[0] = rsp_opcode; - if (rsp_opcode == BLE_LL_CTRL_UNKNOWN_RSP) { - rspbuf[1] = opcode; - } - len = g_ble_ll_ctrl_pkt_lengths[rsp_opcode] + 1; - ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (restart_encryption) { - /* XXX: what happens if this fails? Meaning we cant allocate - mbuf? */ - ble_ll_ctrl_proc_init(connsm, BLE_LL_CTRL_PROC_ENCRYPT); - } -#endif - } - - if (connsm->csmflags.cfbit.pending_initiate_dle) { - connsm->csmflags.cfbit.pending_initiate_dle = 0; - ble_ll_ctrl_initiate_dle(connsm); - } - - return rc; -} - -/** - * Called to create and send a REJECT_IND_EXT control PDU or a REJECT_IND - * - * @param connsm - * @param rej_opcode - * @param err - * - * @return int - */ -int -ble_ll_ctrl_reject_ind_send(struct ble_ll_conn_sm *connsm, uint8_t rej_opcode, - uint8_t err) -{ - int rc; - uint8_t len; - uint8_t opcode; - uint8_t *rspbuf; - struct os_mbuf *om; - - om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN, - sizeof(struct ble_mbuf_hdr)); - if (om) { - rspbuf = om->om_data; - opcode = BLE_LL_CTRL_REJECT_IND_EXT; - if (rej_opcode == BLE_LL_CTRL_ENC_REQ) { - if ((connsm->conn_features & BLE_LL_FEAT_EXTENDED_REJ) == 0) { - opcode = BLE_LL_CTRL_REJECT_IND; - } - } - rspbuf[0] = opcode; - if (opcode == BLE_LL_CTRL_REJECT_IND) { - rspbuf[1] = err; - len = BLE_LL_CTRL_REJ_IND_LEN + 1; - } else { - rspbuf[1] = rej_opcode; - rspbuf[2] = err; - len = BLE_LL_CTRL_REJECT_IND_EXT_LEN + 1; - } - ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len); - rc = 0; - } else { - rc = 1; - } - return rc; -} - -/** - * Called when a Link Layer Control pdu has been transmitted successfully. - * This is called when we have a received a PDU during the ISR. - * - * Context: ISR - * - * @param txpdu - * - * @return int - */ -int -ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) -{ - int rc; - uint8_t opcode; - - rc = 0; - opcode = txpdu->om_data[0]; - switch (opcode) { - case BLE_LL_CTRL_TERMINATE_IND: - connsm->csmflags.cfbit.terminate_ind_txd = 1; - rc = -1; - break; - case BLE_LL_CTRL_REJECT_IND_EXT: - if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) { - /* If rejecting opcode is BLE_LL_CTRL_PROC_CONN_PARAM_REQ and - * reason is LMP collision that means we are master on the link and - * peer wanted to start procedure which we already started. - * Let's wait for response and do not close procedure. */ - if (txpdu->om_data[1] == BLE_LL_CTRL_CONN_PARM_REQ && - txpdu->om_data[2] != BLE_ERR_LMP_COLLISION) { - connsm->reject_reason = txpdu->om_data[2]; - connsm->csmflags.cfbit.host_expects_upd_event = 1; - } - } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) { - connsm->enc_data.enc_state = CONN_ENC_S_UNENCRYPTED; - } -#endif - break; - case BLE_LL_CTRL_REJECT_IND: -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - connsm->enc_data.enc_state = CONN_ENC_S_UNENCRYPTED; -#endif - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - case BLE_LL_CTRL_PAUSE_ENC_REQ: - /* note: fall-through intentional */ - case BLE_LL_CTRL_ENC_REQ: - connsm->enc_data.enc_state = CONN_ENC_S_ENC_RSP_WAIT; - break; - case BLE_LL_CTRL_ENC_RSP: - connsm->enc_data.enc_state = CONN_ENC_S_LTK_REQ_WAIT; - connsm->csmflags.cfbit.send_ltk_req = 1; - break; - case BLE_LL_CTRL_START_ENC_RSP: - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - connsm->enc_data.enc_state = CONN_ENC_S_ENCRYPTED; - if (CONN_F_LE_PING_SUPP(connsm)) { - ble_ll_conn_auth_pyld_timer_start(connsm); - } - } - break; - case BLE_LL_CTRL_PAUSE_ENC_RSP: - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - connsm->enc_data.enc_state = CONN_ENC_S_PAUSE_ENC_RSP_WAIT; - } - break; -#endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - case BLE_LL_CTRL_PHY_REQ: - connsm->phy_tx_transition = - ble_ll_ctrl_phy_tx_transition_get(connsm->phy_data.req_pref_tx_phys_mask); - break; - case BLE_LL_CTRL_PHY_UPDATE_IND: - connsm->phy_tx_transition = - ble_ll_ctrl_phy_tx_transition_get(txpdu->om_data[2]); - break; -#endif - default: - break; - } - - os_mbuf_free_chain(txpdu); - return rc; -} -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_dtm.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_dtm.c deleted file mode 100644 index baf8c2570..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_dtm.c +++ /dev/null @@ -1,728 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/sysinit/sysinit.h" - -#if MYNEWT_VAL(BLE_LL_DTM) - -#include -#include "nimble/porting/nimble/include/os/os.h" -#include "nimble/nimble/porting/nimble/include/stats/stats.h" -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_phy.h" -#include "../include/controller/ble_ll_sched.h" -#include "../include/controller/ble_ll_rfmgmt.h" -#include "ble_ll_dtm_priv.h" - -STATS_SECT_START(ble_ll_dtm_stats) - STATS_SECT_ENTRY(rx_count) - STATS_SECT_ENTRY(tx_failed) - STATS_SECT_ENTRY(rx_failed) -STATS_SECT_END -STATS_SECT_DECL(ble_ll_dtm_stats) ble_ll_dtm_stats; - -STATS_NAME_START(ble_ll_dtm_stats) - STATS_NAME(ble_ll_dtm_stats, rx_count) - STATS_NAME(ble_ll_dtm_stats, tx_failed) - STATS_NAME(ble_ll_dtm_stats, rx_failed) -STATS_NAME_END(ble_phy_stats) - -struct dtm_ctx { - uint8_t payload_packet; - uint8_t itvl_rem_usec; - uint16_t num_of_packets; - uint32_t itvl_ticks; -#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) - uint16_t num_of_packets_max; -#endif - int active; - uint8_t rf_channel; - uint8_t phy_mode; - struct os_mbuf *om; - struct ble_npl_event evt; - struct ble_ll_sched_item sch; - uint32_t pdu_start_ticks; - uint8_t pdu_start_usecs; -}; - -static struct dtm_ctx g_ble_ll_dtm_ctx; - -static const uint8_t g_ble_ll_dtm_prbs9_data[] = -{ - 0xff, 0xc1, 0xfb, 0xe8, 0x4c, 0x90, 0x72, 0x8b, - 0xe7, 0xb3, 0x51, 0x89, 0x63, 0xab, 0x23, 0x23, - 0x02, 0x84, 0x18, 0x72, 0xaa, 0x61, 0x2f, 0x3b, - 0x51, 0xa8, 0xe5, 0x37, 0x49, 0xfb, 0xc9, 0xca, - 0x0c, 0x18, 0x53, 0x2c, 0xfd, 0x45, 0xe3, 0x9a, - 0xe6, 0xf1, 0x5d, 0xb0, 0xb6, 0x1b, 0xb4, 0xbe, - 0x2a, 0x50, 0xea, 0xe9, 0x0e, 0x9c, 0x4b, 0x5e, - 0x57, 0x24, 0xcc, 0xa1, 0xb7, 0x59, 0xb8, 0x87, - 0xff, 0xe0, 0x7d, 0x74, 0x26, 0x48, 0xb9, 0xc5, - 0xf3, 0xd9, 0xa8, 0xc4, 0xb1, 0xd5, 0x91, 0x11, - 0x01, 0x42, 0x0c, 0x39, 0xd5, 0xb0, 0x97, 0x9d, - 0x28, 0xd4, 0xf2, 0x9b, 0xa4, 0xfd, 0x64, 0x65, - 0x06, 0x8c, 0x29, 0x96, 0xfe, 0xa2, 0x71, 0x4d, - 0xf3, 0xf8, 0x2e, 0x58, 0xdb, 0x0d, 0x5a, 0x5f, - 0x15, 0x28, 0xf5, 0x74, 0x07, 0xce, 0x25, 0xaf, - 0x2b, 0x12, 0xe6, 0xd0, 0xdb, 0x2c, 0xdc, 0xc3, - 0x7f, 0xf0, 0x3e, 0x3a, 0x13, 0xa4, 0xdc, 0xe2, - 0xf9, 0x6c, 0x54, 0xe2, 0xd8, 0xea, 0xc8, 0x88, - 0x00, 0x21, 0x86, 0x9c, 0x6a, 0xd8, 0xcb, 0x4e, - 0x14, 0x6a, 0xf9, 0x4d, 0xd2, 0x7e, 0xb2, 0x32, - 0x03, 0xc6, 0x14, 0x4b, 0x7f, 0xd1, 0xb8, 0xa6, - 0x79, 0x7c, 0x17, 0xac, 0xed, 0x06, 0xad, 0xaf, - 0x0a, 0x94, 0x7a, 0xba, 0x03, 0xe7, 0x92, 0xd7, - 0x15, 0x09, 0x73, 0xe8, 0x6d, 0x16, 0xee, 0xe1, - 0x3f, 0x78, 0x1f, 0x9d, 0x09, 0x52, 0x6e, 0xf1, - 0x7c, 0x36, 0x2a, 0x71, 0x6c, 0x75, 0x64, 0x44, - 0x80, 0x10, 0x43, 0x4e, 0x35, 0xec, 0x65, 0x27, - 0x0a, 0xb5, 0xfc, 0x26, 0x69, 0x3f, 0x59, 0x99, - 0x01, 0x63, 0x8a, 0xa5, 0xbf, 0x68, 0x5c, 0xd3, - 0x3c, 0xbe, 0x0b, 0xd6, 0x76, 0x83, 0xd6, 0x57, - 0x05, 0x4a, 0x3d, 0xdd, 0x81, 0x73, 0xc9, 0xeb, - 0x8a, 0x84, 0x39, 0xf4, 0x36, 0x0b, 0xf7 -}; - -static const uint8_t g_ble_ll_dtm_prbs15_data[] = -{ - 0xff, 0x7f, 0xf0, 0x3e, 0x3a, 0x13, 0xa4, 0xdc, - 0xe2, 0xf9, 0x6c, 0x54, 0xe2, 0xd8, 0xea, 0xc8, - 0x88, 0x00, 0x21, 0x86, 0x9c, 0x6a, 0xd8, 0xcb, - 0x4e, 0x14, 0x6a, 0xf9, 0x4d, 0xd2, 0x7e, 0xb2, - 0x32, 0x03, 0xc6, 0x14, 0x4b, 0x7f, 0xd1, 0xb8, - 0xa6, 0x79, 0x7c, 0x17, 0xac, 0xed, 0x06, 0xad, - 0xaf, 0x0a, 0x94, 0x7a, 0xba, 0x03, 0xe7, 0x92, - 0xd7, 0x15, 0x09, 0x73, 0xe8, 0x6d, 0x16, 0xee, - 0xe1, 0x3f, 0x78, 0x1f, 0x9d, 0x09, 0x52, 0x6e, - 0xf1, 0x7c, 0x36, 0x2a, 0x71, 0x6c, 0x75, 0x64, - 0x44, 0x80, 0x10, 0x43, 0x4e, 0x35, 0xec, 0x65, - 0x27, 0x0a, 0xb5, 0xfc, 0x26, 0x69, 0x3f, 0x59, - 0x99, 0x01, 0x63, 0x8a, 0xa5, 0xbf, 0x68, 0x5c, - 0xd3, 0x3c, 0xbe, 0x0b, 0xd6, 0x76, 0x83, 0xd6, - 0x57, 0x05, 0x4a, 0x3d, 0xdd, 0x81, 0x73, 0xc9, - 0xeb, 0x8a, 0x84, 0x39, 0xf4, 0x36, 0x0b, 0xf7, - 0xf0, 0x1f, 0xbc, 0x8f, 0xce, 0x04, 0x29, 0xb7, - 0x78, 0x3e, 0x1b, 0x95, 0x38, 0xb6, 0x3a, 0x32, - 0x22, 0x40, 0x88, 0x21, 0xa7, 0x1a, 0xf6, 0xb2, - 0x13, 0x85, 0x5a, 0x7e, 0x93, 0xb4, 0x9f, 0xac, - 0xcc, 0x80, 0x31, 0xc5, 0xd2, 0x5f, 0x34, 0xae, - 0x69, 0x1e, 0xdf, 0x05, 0x6b, 0xbb, 0x41, 0xeb, - 0xab, 0x02, 0xa5, 0x9e, 0xee, 0xc0, 0xb9, 0xe4, - 0x75, 0x45, 0xc2, 0x1c, 0x7a, 0x9b, 0x85, 0x7b, - 0xf8, 0x0f, 0xde, 0x47, 0x67, 0x82, 0x94, 0x5b, - 0x3c, 0x9f, 0x8d, 0x4a, 0x1c, 0x5b, 0x1d, 0x19, - 0x11, 0x20, 0xc4, 0x90, 0x53, 0x0d, 0x7b, 0xd9, - 0x89, 0x42, 0x2d, 0xbf, 0x49, 0xda, 0x4f, 0x56, - 0x66, 0xc0, 0x98, 0x62, 0xe9, 0x2f, 0x1a, 0xd7, - 0x34, 0x8f, 0xef, 0x82, 0xb5, 0xdd, 0xa0, 0xf5, - 0x55, 0x81, 0x52, 0x4f, 0x77, 0xe0, 0x5c, 0xf2, - 0xba, 0x22, 0x61, 0x0e, 0xbd, 0xcd, 0xc2 -}; - -static const uint8_t channel_rf_to_index[] = { - 37, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 38, 11 ,12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 39 -}; - -#define BLE_DTM_SYNC_WORD (0x71764129) -#define BLE_DTM_CRC (0x555555) - -static void ble_ll_dtm_ctx_free(struct dtm_ctx * ctx); - -static void -ble_ll_dtm_set_next(struct dtm_ctx *ctx) -{ - struct ble_ll_sched_item *sch = &ctx->sch; - - ctx->pdu_start_ticks += ctx->itvl_ticks; - ctx->pdu_start_usecs += ctx->itvl_rem_usec; - if (ctx->pdu_start_usecs >= 31) { - ctx->pdu_start_ticks++; - ctx->pdu_start_usecs -= 31; - } - - sch->start_time = ctx->pdu_start_ticks; - sch->remainder = ctx->pdu_start_usecs; - - sch->start_time -= g_ble_ll_sched_offset_ticks; -} - -static void -ble_ll_dtm_ev_tx_resched_cb(struct ble_npl_event *evt) { - /* It is called in LL context */ - struct dtm_ctx *ctx = ble_npl_event_get_arg(evt); - int rc; - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - if (!ctx->active || !ctx->om) { - OS_EXIT_CRITICAL(sr); - return; - } - OS_EXIT_CRITICAL(sr); - -#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) - if (g_ble_ll_dtm_ctx.num_of_packets_max && - (g_ble_ll_dtm_ctx.num_of_packets == g_ble_ll_dtm_ctx.num_of_packets_max)) { - /* - * XXX do not send more packets, but also do not stop DTM - it shall be - * stopped as usual by HCI command since there is no standard way to - * signal end of test to host. - */ - return; - } -#endif - - ble_ll_dtm_set_next(ctx); - rc = ble_ll_sched_dtm(&ctx->sch); - BLE_LL_ASSERT(rc == 0); -} - -static int ble_ll_dtm_rx_start(void); - -static void -ble_ll_dtm_ev_rx_restart_cb(struct ble_npl_event *evt) { - if (ble_ll_dtm_rx_start() != 0) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt); - STATS_INC(ble_ll_dtm_stats, rx_failed); - } -} - -static void -ble_ll_dtm_tx_done(void *arg) -{ - struct dtm_ctx *ctx; - - ctx = arg; - if (!ctx->active) { - return; - } - - g_ble_ll_dtm_ctx.num_of_packets++; - - /* Reschedule event in LL context */ - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ctx->evt); - - ble_ll_state_set(BLE_LL_STATE_STANDBY); -} - -static int -ble_ll_dtm_tx_sched_cb(struct ble_ll_sched_item *sch) -{ - struct dtm_ctx *ctx = sch->cb_arg; - int rc; - - if (!ctx->active) { - return BLE_LL_SCHED_STATE_DONE; - } - - rc = ble_phy_setchan(channel_rf_to_index[ctx->rf_channel], - BLE_DTM_SYNC_WORD, BLE_DTM_CRC); - if (rc != 0) { - BLE_LL_ASSERT(0); - return BLE_LL_SCHED_STATE_DONE; - } - -#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)) - ble_phy_mode_set(ctx->phy_mode, ctx->phy_mode); -#endif - ble_phy_set_txend_cb(ble_ll_dtm_tx_done, ctx); - ble_phy_txpwr_set(0); - - sch->start_time += g_ble_ll_sched_offset_ticks; - - rc = ble_phy_tx_set_start_time(sch->start_time, sch->remainder); - if (rc) { - goto resched; - } - - rc = ble_phy_tx(ble_ll_tx_mbuf_pducb, ctx->om, BLE_PHY_TRANSITION_NONE); - if (rc) { - goto resched; - } - - ble_ll_state_set(BLE_LL_STATE_DTM); - - return BLE_LL_SCHED_STATE_DONE; - -resched: - /* Reschedule from LL task if late for this PDU */ - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ctx->evt); - - STATS_INC(ble_ll_dtm_stats, tx_failed); - - return BLE_LL_SCHED_STATE_DONE; -} - -static void -ble_ll_dtm_calculate_itvl(struct dtm_ctx *ctx, uint8_t len, - uint16_t cmd_interval, int phy_mode) -{ - uint32_t l; - uint32_t itvl_usec; - uint32_t itvl_ticks; - - /* Calculate interval as per spec Bluetooth 5.0 Vol 6. Part F, 4.1.6 */ - l = ble_ll_pdu_tx_time_get(len + BLE_LL_PDU_HDR_LEN, phy_mode); - itvl_usec = ((l + 249 + 624) / 625) * 625; - -#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) - if (cmd_interval > itvl_usec) { - itvl_usec = cmd_interval; - } -#endif - - itvl_ticks = os_cputime_usecs_to_ticks(itvl_usec); - ctx->itvl_rem_usec = (itvl_usec - os_cputime_ticks_to_usecs(itvl_ticks)); - if (ctx->itvl_rem_usec == 31) { - ctx->itvl_rem_usec = 0; - ++itvl_ticks; - } - ctx->itvl_ticks = itvl_ticks; -} - -static int -ble_ll_dtm_tx_create_ctx(uint8_t packet_payload, uint8_t len, - uint8_t rf_channel, uint8_t phy_mode, - uint16_t cmd_interval, uint16_t cmd_pkt_count) -{ - int rc = 0; - uint8_t byte_pattern; - struct ble_mbuf_hdr *ble_hdr; - struct os_mbuf *m; - struct dtm_ctx *ctx = &g_ble_ll_dtm_ctx; - struct ble_ll_sched_item *sch = &ctx->sch; - - /* MSYS is big enough to get continues memory */ - m = os_msys_get_pkthdr(len, sizeof(struct ble_mbuf_hdr)); - ctx->om = m; - BLE_LL_ASSERT(g_ble_ll_dtm_ctx.om); - - ctx->phy_mode = phy_mode; - ctx->rf_channel = rf_channel; - ctx->num_of_packets = 0; -#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) - ctx->num_of_packets_max = cmd_pkt_count; -#endif - - /* Set BLE transmit header */ - ble_hdr = BLE_MBUF_HDR_PTR(m); - ble_hdr->txinfo.flags = 0; - ble_hdr->txinfo.offset = 0; - ble_hdr->txinfo.pyld_len = len; - ble_hdr->txinfo.hdr_byte = packet_payload; - - switch(packet_payload) { - case 0x00: - if (os_mbuf_copyinto(m, 0, &g_ble_ll_dtm_prbs9_data, len)) { - return 1; - } - goto schedule; - case 0x01: - byte_pattern = 0x0F; - break; - case 0x02: - byte_pattern = 0x55; - break; - case 0x03: - if (os_mbuf_copyinto(m, 0, &g_ble_ll_dtm_prbs15_data, len)) { - return 1; - } - goto schedule; - case 0x04: - byte_pattern = 0xFF; - break; - case 0x05: - byte_pattern = 0x00; - break; - case 0x06: - byte_pattern = 0xF0; - break; - case 0x07: - byte_pattern = 0xAA; - break; - default: - return 1; - } - - for (rc = 0; rc < len; rc++) { - if (os_mbuf_copyinto(m, rc, &byte_pattern, 1)) { - return 1; - } - } - -schedule: - ble_phy_enable_dtm(); - - sch->sched_cb = ble_ll_dtm_tx_sched_cb; - sch->cb_arg = ctx; - sch->sched_type = BLE_LL_SCHED_TYPE_DTM; - - /* Prepare os_event */ - ble_npl_event_init(&ctx->evt, ble_ll_dtm_ev_tx_resched_cb, ctx); - - ble_ll_dtm_calculate_itvl(ctx, len, cmd_interval, phy_mode); - - ctx->pdu_start_ticks = ble_ll_rfmgmt_enable_now(); - ctx->pdu_start_usecs = 0; - ble_ll_dtm_set_next(ctx); - - /* Set some start point for TX packets */ - rc = ble_ll_sched_dtm(sch); - BLE_LL_ASSERT(rc == 0); - - g_ble_ll_dtm_ctx.active = 1; - return 0; -} - -static int -ble_ll_dtm_rx_start(void) -{ - os_sr_t sr; - int rc; - - rc = ble_phy_setchan(channel_rf_to_index[g_ble_ll_dtm_ctx.rf_channel], - BLE_DTM_SYNC_WORD, BLE_DTM_CRC); - if (rc) { - return rc; - } - -#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)) - ble_phy_mode_set(g_ble_ll_dtm_ctx.phy_mode, g_ble_ll_dtm_ctx.phy_mode); -#endif - - OS_ENTER_CRITICAL(sr); - rc = ble_phy_rx_set_start_time(os_cputime_get32(), 0); - OS_EXIT_CRITICAL(sr); - if (rc && rc != BLE_PHY_ERR_RX_LATE) { - return rc; - } - - ble_ll_state_set(BLE_LL_STATE_DTM); - - return 0; -} - -static int -ble_ll_dtm_rx_sched_cb(struct ble_ll_sched_item *sch) -{ - if (ble_ll_dtm_rx_start() != 0) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt); - STATS_INC(ble_ll_dtm_stats, rx_failed); - } - - return BLE_LL_SCHED_STATE_DONE; -} - -static int -ble_ll_dtm_rx_create_ctx(uint8_t rf_channel, uint8_t phy_mode) -{ - struct ble_ll_sched_item *sch = &g_ble_ll_dtm_ctx.sch; - int rc; - - g_ble_ll_dtm_ctx.phy_mode = phy_mode; - g_ble_ll_dtm_ctx.rf_channel = rf_channel; - - STATS_CLEAR(ble_ll_dtm_stats, rx_count); - - ble_npl_event_init(&g_ble_ll_dtm_ctx.evt, ble_ll_dtm_ev_rx_restart_cb, - NULL); - - sch->sched_cb = ble_ll_dtm_rx_sched_cb; - sch->cb_arg = &g_ble_ll_dtm_ctx; - sch->sched_type = BLE_LL_SCHED_TYPE_DTM; - sch->start_time = ble_ll_rfmgmt_enable_now(); - - rc = ble_ll_sched_dtm(sch); - BLE_LL_ASSERT(rc == 0); - - ble_phy_enable_dtm(); - - g_ble_ll_dtm_ctx.active = 1; - return 0; -} - -static void -ble_ll_dtm_ctx_free(struct dtm_ctx * ctx) -{ - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - if (!ctx->active) { - OS_EXIT_CRITICAL(sr); - return; - } - - ble_ll_sched_rmv_elem(&ctx->sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt); - - ble_phy_disable(); - ble_phy_disable_dtm(); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - ble_ll_rfmgmt_release(); - - os_mbuf_free_chain(ctx->om); - memset(ctx, 0, sizeof(*ctx)); - OS_EXIT_CRITICAL(sr); -} - -static int -ble_ll_dtm_tx_test(uint8_t tx_chan, uint8_t len, uint8_t packet_payload, - uint8_t hci_phy, uint16_t interval, uint16_t pkt_count) -{ - uint8_t phy_mode; - - if (g_ble_ll_dtm_ctx.active) { - return BLE_ERR_CTLR_BUSY; - } - - switch (hci_phy) { - case BLE_HCI_LE_PHY_1M: - phy_mode = BLE_PHY_MODE_1M; - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - case BLE_HCI_LE_PHY_2M: - phy_mode = BLE_PHY_MODE_2M; - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case BLE_HCI_LE_PHY_CODED_S8: - phy_mode = BLE_PHY_MODE_CODED_125KBPS; - break; - case BLE_HCI_LE_PHY_CODED_S2: - phy_mode = BLE_PHY_MODE_CODED_500KBPS; - break; -#endif - default: - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (tx_chan > 0x27 || packet_payload > 0x07) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (ble_ll_dtm_tx_create_ctx(packet_payload, len, tx_chan, phy_mode, - interval, pkt_count)) { - return BLE_ERR_UNSPECIFIED; - } - - return BLE_ERR_SUCCESS; -} - -#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) -static int -ble_ll_hci_dtm_tx_test_ext(const uint8_t *cmdbuf) -{ - const struct ble_hci_le_tx_test_ext_cp *cmd = (const void *) cmdbuf; - - return ble_ll_dtm_tx_test(cmd->tx_chan, cmd->test_data_len, cmd->payload, - BLE_HCI_LE_PHY_1M, le16toh(cmd->interval), - le16toh(cmd->pkt_count)); -} - -static int -ble_ll_hci_dtm_tx_test_v2_ext(const uint8_t *cmdbuf) -{ - const struct ble_hci_le_tx_test_v2_ext_cp *cmd = (const void *) cmdbuf; - - return ble_ll_dtm_tx_test(cmd->tx_chan, cmd->test_data_len, cmd->payload, - cmd->phy, le16toh(cmd->interval), - le16toh(cmd->pkt_count)); -} -#endif - -int -ble_ll_hci_dtm_tx_test(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_tx_test_cp *cmd = (const void *) cmdbuf; - -#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) - if (len == sizeof(struct ble_hci_le_tx_test_ext_cp)) { - return ble_ll_hci_dtm_tx_test_ext(cmdbuf); - } -#endif - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return ble_ll_dtm_tx_test(cmd->tx_chan, cmd->test_data_len, cmd->payload, - BLE_HCI_LE_PHY_1M, 0, 0); -} - -int -ble_ll_hci_dtm_tx_test_v2(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_tx_test_v2_cp *cmd = (const void *) cmdbuf; - -#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) - if (len == sizeof(struct ble_hci_le_tx_test_v2_ext_cp)) { - return ble_ll_hci_dtm_tx_test_v2_ext(cmdbuf); - } -#endif - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return ble_ll_dtm_tx_test(cmd->tx_chan, cmd->test_data_len, cmd->payload, - cmd->phy, 0, 0); -} - -static int -ble_ll_dtm_rx_test(uint8_t rx_chan, uint8_t hci_phy) -{ - uint8_t phy_mode; - - if (g_ble_ll_dtm_ctx.active) { - return BLE_ERR_CTLR_BUSY; - } - - switch (hci_phy) { - case BLE_HCI_LE_PHY_1M: - phy_mode = BLE_PHY_MODE_1M; - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - case BLE_HCI_LE_PHY_2M: - phy_mode = BLE_PHY_MODE_2M; - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case BLE_HCI_LE_PHY_CODED: - phy_mode = BLE_PHY_MODE_CODED_500KBPS; - break; -#endif - default: - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (rx_chan > 0x27) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (ble_ll_dtm_rx_create_ctx(rx_chan, phy_mode)) { - return BLE_ERR_UNSPECIFIED; - } - - return BLE_ERR_SUCCESS; -} - -int ble_ll_hci_dtm_rx_test(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_rx_test_cp *cmd = (const void *) cmdbuf; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return ble_ll_dtm_rx_test(cmd->rx_chan, BLE_HCI_LE_PHY_1M); -} - -int ble_ll_hci_dtm_rx_test_v2(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_rx_test_v2_cp *cmd = (const void *) cmdbuf; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* TODO ignoring modulation index */ - - return ble_ll_dtm_rx_test(cmd->rx_chan, cmd->phy); -} - -int ble_ll_dtm_end_test(uint8_t *rsp, uint8_t *rsplen) -{ - put_le16(rsp, g_ble_ll_dtm_ctx. num_of_packets); - *rsplen = 2; - - ble_ll_dtm_ctx_free(&g_ble_ll_dtm_ctx); - return BLE_ERR_SUCCESS; -} - -int ble_ll_dtm_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa) -{ - return 0; -} - -void -ble_ll_dtm_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) -{ - if (BLE_MBUF_HDR_CRC_OK(hdr)) { - /* XXX Compare data. */ - g_ble_ll_dtm_ctx.num_of_packets++; - STATS_INC(ble_ll_dtm_stats, rx_count); - } - - if (ble_ll_dtm_rx_start() != 0) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt); - STATS_INC(ble_ll_dtm_stats, rx_failed); - } -} - -int -ble_ll_dtm_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) -{ - struct os_mbuf *rxpdu; - - if (!g_ble_ll_dtm_ctx.active) { - return -1; - } - - rxpdu = ble_ll_rxpdu_alloc(rxbuf[1] + BLE_LL_PDU_HDR_LEN); - - /* Copy the received pdu and hand it up */ - if (rxpdu) { - ble_phy_rxpdu_copy(rxbuf, rxpdu); - ble_ll_rx_pdu_in(rxpdu); - } - - return 0; -} - -void -ble_ll_dtm_wfr_timer_exp(void) -{ - /* Should not be needed */ - BLE_LL_ASSERT(0); -} - - -void -ble_ll_dtm_reset(void) -{ - ble_ll_dtm_ctx_free(&g_ble_ll_dtm_ctx); -} - -void -ble_ll_dtm_init(void) -{ - int rc; - - rc = stats_init_and_reg(STATS_HDR(ble_ll_dtm_stats), - STATS_SIZE_INIT_PARMS(ble_ll_dtm_stats, STATS_SIZE_32), - STATS_NAME_INIT_PARMS(ble_ll_dtm_stats), - "ble_ll_dtm"); - SYSINIT_PANIC_ASSERT(rc == 0); -} -#endif -#endif \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_dtm_priv.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_dtm_priv.h deleted file mode 100644 index e04af07be..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_dtm_priv.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_TEST_PRIV_ -#define H_BLE_LL_TEST_PRIV_ - -#include -#include -#include "nimble/ble.h" - -int ble_ll_hci_dtm_tx_test(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_hci_dtm_tx_test_v2(const uint8_t *cmdbuf, uint8_t len); - -int ble_ll_hci_dtm_rx_test(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_hci_dtm_rx_test_v2(const uint8_t *cmdbuf, uint8_t len); - -int ble_ll_dtm_end_test(uint8_t *rsp, uint8_t *rsplen); - -int ble_ll_dtm_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa); -int ble_ll_dtm_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr); -void ble_ll_dtm_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr); -void ble_ll_dtm_wfr_timer_exp(void); -void ble_ll_dtm_reset(void); -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_hci.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_hci.c deleted file mode 100644 index f3faac637..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_hci.c +++ /dev/null @@ -1,1779 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "nimble/nimble/include/nimble/ble_hci_trans.h" -#include "../include/controller/ble_hw.h" -#include "../include/controller/ble_ll_adv.h" -#include "../include/controller/ble_ll_scan.h" -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_hci.h" -#include "../include/controller/ble_ll_whitelist.h" -#include "../include/controller/ble_ll_resolv.h" -#include "../include/controller/ble_ll_sync.h" -#include "../include/controller/ble_ll_iso.h" -#include "ble_ll_priv.h" -#include "ble_ll_conn_priv.h" - -#if MYNEWT_VAL(BLE_LL_DTM) -#include "ble_ll_dtm_priv.h" -#endif - -static void ble_ll_hci_cmd_proc(struct ble_npl_event *ev); - -/* OS event to enqueue command */ -static struct ble_npl_event g_ble_ll_hci_cmd_ev; - -/* LE event mask */ -static uint64_t g_ble_ll_hci_le_event_mask; -static uint64_t g_ble_ll_hci_event_mask; -static uint64_t g_ble_ll_hci_event_mask2; - -static int16_t rx_path_pwr_compensation; -static int16_t tx_path_pwr_compensation; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static enum { - ADV_MODE_ANY, - ADV_MODE_LEGACY, - ADV_MODE_EXT, -} hci_adv_mode; - -bool ble_ll_hci_adv_mode_ext(void) -{ - return hci_adv_mode == ADV_MODE_EXT; -} -#else -bool -ble_ll_hci_adv_mode_ext(void) -{ - return false; -} -#endif - -/** - * ll hci get num cmd pkts - * - * Returns the number of command packets that the host is allowed to send - * to the controller. - * - * @return uint8_t - */ -static uint8_t -ble_ll_hci_get_num_cmd_pkts(void) -{ - return BLE_LL_CFG_NUM_HCI_CMD_PKTS; -} - -/** - * Send an event to the host. - * - * @param evbuf Pointer to event buffer to send - * - * @return int 0: success; -1 otherwise. - */ -int -ble_ll_hci_event_send(struct ble_hci_ev *hci_ev) -{ - int rc; - - BLE_LL_DEBUG_GPIO(HCI_EV, 1); - - BLE_LL_ASSERT(sizeof(*hci_ev) + hci_ev->length <= BLE_LL_MAX_EVT_LEN); - - /* Count number of events sent */ - STATS_INC(ble_ll_stats, hci_events_sent); - - /* Send the event to the host */ - rc = ble_hci_trans_ll_evt_tx((uint8_t *)hci_ev); - - BLE_LL_DEBUG_GPIO(HCI_EV, 0); - - return rc; -} - -/** - * Created and sends a command complete event with the no-op opcode to the - * host. - */ -void -ble_ll_hci_send_noop(void) -{ - struct ble_hci_ev_command_complete_nop *ev; - struct ble_hci_ev *hci_ev; - - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - /* Create a command complete event with a NO-OP opcode */ - hci_ev->opcode = BLE_HCI_EVCODE_COMMAND_COMPLETE; - - hci_ev->length = sizeof(*ev); - ev = (void *)hci_ev->data; - - ev->num_packets = ble_ll_hci_get_num_cmd_pkts(); - ev->opcode = BLE_HCI_OPCODE_NOP; - - ble_ll_hci_event_send(hci_ev); - } -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/** - * LE encrypt command - * - * @param cmdbuf - * @param rspbuf - * @param rsplen - * - * @return int - */ -static int -ble_ll_hci_le_encrypt(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, - uint8_t *rsplen) -{ - const struct ble_hci_le_encrypt_cp *cmd = (const void *) cmdbuf; - struct ble_hci_le_encrypt_rp *rsp = (void *)rspbuf; - struct ble_encryption_block ecb; - int rc; - - /* Call the link layer to encrypt the data */ - swap_buf(ecb.key, cmd->key, BLE_ENC_BLOCK_SIZE); - swap_buf(ecb.plain_text, cmd->data, BLE_ENC_BLOCK_SIZE); - rc = ble_hw_encrypt_block(&ecb); - if (!rc) { - swap_buf(rsp->data, ecb.cipher_text, BLE_ENC_BLOCK_SIZE); - *rsplen = sizeof(*rsp); - rc = BLE_ERR_SUCCESS; - } else { - rc = BLE_ERR_CTLR_BUSY; - } - - return rc; -} -#endif - -/** - * LE rand command - * - * @param cmdbuf - * @param rspbuf - * @param rsplen - * - * @return int - */ -static int -ble_ll_hci_le_rand(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rand_rp *rsp = (void *) rspbuf; - - ble_ll_rand_data_get((uint8_t *)&rsp->random_number, - sizeof(rsp->random_number)); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -/** - * Read local version - * - * @param rspbuf - * @param rsplen - * - * @return int - */ -static int -ble_ll_hci_rd_local_version(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_ip_rd_local_ver_rp *rsp = (void *) rspbuf; - - rsp->hci_ver = BLE_HCI_VER_BCS; - rsp->hci_rev = 0; - rsp->lmp_ver = BLE_LMP_VER_BCS; - rsp->manufacturer = htole16(MYNEWT_VAL(BLE_LL_MFRG_ID)); - rsp->lmp_subver = 0; - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -/** - * Read local supported features - * - * @param rspbuf - * @param rsplen - * - * @return int - */ -static int -ble_ll_hci_rd_local_supp_feat(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_ip_rd_loc_supp_feat_rp *rsp = (void *) rspbuf; - - /* - * The only two bits we set here currently are (5th byte): - * BR/EDR not supported (bit 5) - * LE supported (controller) (bit 6) - */ - rsp->features = htole64(0x0000006000000000); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -/** - * Read local supported commands - * - * @param rspbuf - * @param rsplen - * - * @return int - */ -static int -ble_ll_hci_rd_local_supp_cmd(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_ip_rd_loc_supp_cmd_rp *rsp = (void *) rspbuf; - - memset(rsp->commands, 0, sizeof(rsp->commands)); - memcpy(rsp->commands, g_ble_ll_supp_cmds, sizeof(g_ble_ll_supp_cmds)); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -/** - * Called to read the public device address of the device - * - * - * @param rspbuf - * @param rsplen - * - * @return int - */ -static int -ble_ll_hci_rd_bd_addr(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_ip_rd_bd_addr_rp *rsp = (void *) rspbuf; - - memcpy(rsp->addr, g_dev_addr, BLE_DEV_ADDR_LEN); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -/** - * ll hci set le event mask - * - * Called when the LL controller receives a set LE event mask command. - * - * Context: Link Layer task (HCI command parser) - * - * @param cmdbuf Pointer to command buf. - * - * @return int BLE_ERR_SUCCESS. Does not return any errors. - */ -static int -ble_ll_hci_set_le_event_mask(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_event_mask_cp *cmd = (const void *) cmdbuf; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - g_ble_ll_hci_le_event_mask = le64toh(cmd->event_mask); - - return BLE_ERR_SUCCESS; -} - -/** - * HCI read buffer size command. Returns the ACL data packet length and - * num data packets. - * - * @param rspbuf Pointer to response buffer - * @param rsplen Length of response buffer - * - * @return int BLE error code - */ -static int -ble_ll_hci_le_read_bufsize(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_buf_size_rp *rp = (void *) rspbuf; - - rp->data_len = htole16(g_ble_ll_data.ll_acl_pkt_size); - rp->data_packets = g_ble_ll_data.ll_num_acl_pkts; - - *rsplen = sizeof(*rp); - return BLE_ERR_SUCCESS; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) -/** - * HCI read buffer size v2 command. Returns the ACL and ISO data packet length and - * num data packets. - * - * @param rspbuf Pointer to response buffer - * @param rsplen Length of response buffer - * - * @return int BLE error code - */ -static int -ble_ll_hci_le_read_bufsize_v2(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_buf_size_v2_rp *rp = (void *) rspbuf; - - rp->data_len = htole16(g_ble_ll_data.ll_acl_pkt_size); - rp->data_packets = g_ble_ll_data.ll_num_acl_pkts; - rp->iso_data_len = 0; - rp->iso_data_packets = 0; - - *rsplen = sizeof(*rp); - return BLE_ERR_SUCCESS; -} -#endif - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) -/** - * Checks the preferred phy masks for validity and places the preferred masks - * in the input phy masks - - * @return int BLE_ERR_SUCCESS or BLE_ERR_INV_HCI_CMD_PARMS or BLE_ERR_UNSUPPORTED - */ -int -ble_ll_hci_chk_phy_masks(uint8_t all_phys, uint8_t tx_phys, uint8_t rx_phys, - uint8_t *txphy, uint8_t *rxphy) -{ - /* Check for RFU */ - if ((tx_phys & ~BLE_HCI_LE_PHY_PREF_MASK_ALL) || - (rx_phys & ~BLE_HCI_LE_PHY_PREF_MASK_ALL)) { - return BLE_ERR_UNSUPPORTED; - } - - if ((!(all_phys & BLE_HCI_LE_PHY_NO_TX_PREF_MASK) && (tx_phys == 0)) || - (!(all_phys & BLE_HCI_LE_PHY_NO_RX_PREF_MASK) && (rx_phys == 0))) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* If phy not supported, return error */ -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - if((tx_phys & BLE_HCI_LE_PHY_2M_PREF_MASK) || - (rx_phys & BLE_HCI_LE_PHY_2M_PREF_MASK)) { - return BLE_ERR_UNSUPPORTED; - } -#endif -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - if ((tx_phys & BLE_HCI_LE_PHY_CODED_PREF_MASK) || - (rx_phys & BLE_HCI_LE_PHY_CODED_PREF_MASK)) { - return BLE_ERR_UNSUPPORTED; - } -#endif - /* Set the default PHY preferences */ - if (all_phys & BLE_HCI_LE_PHY_NO_TX_PREF_MASK) { - tx_phys = BLE_HCI_LE_PHY_PREF_MASK_ALL; - } - *txphy = tx_phys; - - if (all_phys & BLE_HCI_LE_PHY_NO_RX_PREF_MASK) { - rx_phys = BLE_HCI_LE_PHY_PREF_MASK_ALL; - } - *rxphy = rx_phys; - - return BLE_ERR_SUCCESS; -} - -/** - * Set PHY preferences for connection - * - * @param cmdbuf - * - * @return int - */ -static int -ble_ll_hci_le_set_def_phy(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_default_phy_cp *cmd = (const void *) cmdbuf; - int rc; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - rc = ble_ll_hci_chk_phy_masks(cmd->all_phys, cmd->tx_phys, cmd->rx_phys, - &g_ble_ll_data.ll_pref_tx_phys, - &g_ble_ll_data.ll_pref_rx_phys); - return rc; -} -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) -/** - * HCI write suggested default data length command. - * - * This command is used by the host to change the initial max tx octets/time - * for all connections. Note that if the controller does not support the - * requested times no error is returned; the controller simply ignores the - * request (but remembers what the host requested for the read suggested - * default data length command). The spec allows for the controller to - * disregard the host. - * - * @param rspbuf Pointer to response buffer - * @param rsplen Length of response buffer - * - * @return int BLE error code - */ -static int -ble_ll_hci_le_wr_sugg_data_len(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_wr_sugg_def_data_len_cp *cmd = (const void*) cmdbuf; - uint16_t tx_oct; - uint16_t tx_time; - int rc; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Get suggested octets and time */ - tx_oct = le16toh(cmd->max_tx_octets); - tx_time = le16toh(cmd->max_tx_time); - - /* If valid, write into suggested and change connection initial times */ - if (ble_ll_chk_txrx_octets(tx_oct) && ble_ll_chk_txrx_time(tx_time)) { - g_ble_ll_conn_params.sugg_tx_octets = (uint8_t)tx_oct; - g_ble_ll_conn_params.sugg_tx_time = tx_time; - - /* - * We can disregard host suggestion, but we are a nice controller so - * let's use host suggestion, unless they exceed max supported values - * in which case we just use our max. - */ - g_ble_ll_conn_params.conn_init_max_tx_octets = - min(tx_oct, g_ble_ll_conn_params.supp_max_tx_octets); - g_ble_ll_conn_params.conn_init_max_tx_time = - min(tx_time, g_ble_ll_conn_params.supp_max_tx_time); - - /* - * Use the same for coded and uncoded defaults. These are used when PHY - * parameters are initialized and we want to use values overridden by - * host. Make sure we do not exceed max supported time on uncoded. - */ - g_ble_ll_conn_params.conn_init_max_tx_time_uncoded = - min(BLE_LL_CONN_SUPP_TIME_MAX_UNCODED, - g_ble_ll_conn_params.conn_init_max_tx_time); - g_ble_ll_conn_params.conn_init_max_tx_time_coded = - g_ble_ll_conn_params.conn_init_max_tx_time; - - rc = BLE_ERR_SUCCESS; - } else { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - } - - return rc; -} - -/** - * HCI read suggested default data length command. Returns the controllers - * initial max tx octet/time. - * - * @param rspbuf Pointer to response buffer - * @param rsplen Length of response buffer - * - * @return int BLE error code - */ -static int -ble_ll_hci_le_rd_sugg_data_len(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_sugg_def_data_len_rp *rsp = (void *) rspbuf; - - /* Place the data packet length and number of packets in the buffer */ - rsp->max_tx_octets = htole16(g_ble_ll_conn_params.sugg_tx_octets); - rsp->max_tx_time = htole16(g_ble_ll_conn_params.sugg_tx_time); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -/** - * HCI read maximum data length command. Returns the controllers max supported - * rx/tx octets/times. - * - * @param rspbuf Pointer to response buffer - * @param rsplen Length of response buffer - * - * @return int BLE error code - */ -static int -ble_ll_hci_le_rd_max_data_len(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_max_data_len_rp *rsp = (void *)rspbuf; - - /* Place the data packet length and number of packets in the buffer */ - rsp->max_tx_octests = htole16(g_ble_ll_conn_params.supp_max_tx_octets); - rsp->max_tx_time = htole16(g_ble_ll_conn_params.supp_max_tx_time); - rsp->max_rx_octests = htole16(g_ble_ll_conn_params.supp_max_rx_octets); - rsp->max_rx_time = htole16(g_ble_ll_conn_params.supp_max_rx_time); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} -#endif - -/** - * HCI read local supported features command. Returns the features - * supported by the controller. - * - * @param rspbuf Pointer to response buffer - * @param rsplen Length of response buffer - * - * @return int BLE error code - */ -static int -ble_ll_hci_le_read_local_features(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_loc_supp_feat_rp *rsp = (void *) rspbuf; - - rsp->features = htole64(ble_ll_read_supp_features()); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -/** - * HCI read local supported states command. Returns the states - * supported by the controller. - * - * @param rspbuf Pointer to response buffer - * @param rsplen Length of response buffer - * - * @return int BLE error code - */ -static int -ble_ll_hci_le_read_supp_states(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_supp_states_rp *rsp = (void *) rspbuf; - - /* Add list of supported states. */ - rsp->states = htole64(ble_ll_read_supp_states()); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - - -/** - * Checks to see if a LE event has been disabled by the host. - * - * @param subev Sub-event code of the LE Meta event. Note that this can - * be a value from 1 to 64, inclusive. - * - * @return uint8_t 0: event is not enabled; otherwise event is enabled. - */ -bool -ble_ll_hci_is_le_event_enabled(unsigned int subev) -{ - /* The LE meta event must be enabled for any LE event to be enabled */ - if (g_ble_ll_hci_event_mask & (1ull << (BLE_HCI_EVCODE_LE_META - 1))) { - return g_ble_ll_hci_le_event_mask & (1ull << (subev - 1)); - } - - return false; -} - -/** - * Checks to see if an event has been disabled by the host. - * - * NOTE: there are two "pages" of event masks; the first page is for event - * codes between 0 and 63 and the second page is for event codes 64 and - * greater. - * - * @param evcode This is the event code for the event. - * - * @return uint8_t 0: event is not enabled; otherwise event is enabled. - */ -bool -ble_ll_hci_is_event_enabled(unsigned int evcode) -{ - if (evcode >= 64) { - return g_ble_ll_hci_event_mask2 & (1ull << (evcode - 64)); - } - - return g_ble_ll_hci_event_mask & (1ull << (evcode - 1)); -} - -/** - * Called to determine if the reply to the command should be a command complete - * event or a command status event. - * - * @param ocf - * - * @return int 0: return command complete; 1: return command status event - */ -static int -ble_ll_hci_le_cmd_send_cmd_status(uint16_t ocf) -{ - int rc; - - switch (ocf) { - case BLE_HCI_OCF_LE_RD_REM_FEAT: - case BLE_HCI_OCF_LE_CREATE_CONN: - case BLE_HCI_OCF_LE_EXT_CREATE_CONN: - case BLE_HCI_OCF_LE_CONN_UPDATE: - case BLE_HCI_OCF_LE_START_ENCRYPT: - case BLE_HCI_OCF_LE_RD_P256_PUBKEY: - case BLE_HCI_OCF_LE_GEN_DHKEY: - case BLE_HCI_OCF_LE_SET_PHY: - case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC: -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) - case BLE_HCI_OCF_LE_REQ_PEER_SCA: -#endif - rc = 1; - break; - default: - rc = 0; - break; - } - return rc; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -/** HCI LE read maximum advertising data length command. Returns the controllers -* max supported advertising data length; -* -* @param rspbuf Pointer to response buffer -* @param rsplen Length of response buffer -* -* @return int BLE error code -*/ -static int -ble_ll_adv_rd_max_adv_data_len(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_max_adv_data_len_rp *rsp = (void *) rspbuf; - - rsp->max_adv_data_len = htole16(BLE_ADV_DATA_MAX_LEN); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -/** - * HCI LE read number of supported advertising sets - * - * @param rspbuf Pointer to response buffer - * @param rsplen Length of response buffer - * - * @return int BLE error code - */ -static int -ble_ll_adv_rd_sup_adv_sets(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_num_of_adv_sets_rp *rsp = (void *)rspbuf; - - rsp->num_sets = BLE_ADV_INSTANCES; - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -static bool -ble_ll_is_valid_adv_mode(uint8_t ocf) -{ - /* - * If, since the last power-on or reset, the Host has ever issued a legacy - * advertising command and then issues an extended advertising command, or - * has ever issued an extended advertising command and then issues a legacy - * advertising command, the Controller shall return the error code Command - * Disallowed (0x0C). - */ - - switch(ocf) { - case BLE_HCI_OCF_LE_CREATE_CONN: - case BLE_HCI_OCF_LE_SET_ADV_PARAMS: - case BLE_HCI_OCF_LE_SET_ADV_ENABLE: - case BLE_HCI_OCF_LE_SET_ADV_DATA: - case BLE_HCI_OCF_LE_SET_SCAN_PARAMS: - case BLE_HCI_OCF_LE_SET_SCAN_ENABLE: - case BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA: - case BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR: - if (hci_adv_mode == ADV_MODE_EXT) { - return false; - } - - hci_adv_mode = ADV_MODE_LEGACY; - break; - case BLE_HCI_OCF_LE_EXT_CREATE_CONN: - case BLE_HCI_OCF_LE_SET_EXT_ADV_DATA: - case BLE_HCI_OCF_LE_SET_EXT_ADV_ENABLE: - case BLE_HCI_OCF_LE_SET_EXT_ADV_PARAM: - case BLE_HCI_OCF_LE_SET_EXT_SCAN_ENABLE: - case BLE_HCI_OCF_LE_SET_EXT_SCAN_PARAM: - case BLE_HCI_OCF_LE_SET_EXT_SCAN_RSP_DATA: - case BLE_HCI_OCF_LE_RD_MAX_ADV_DATA_LEN: - case BLE_HCI_OCF_LE_RD_NUM_OF_ADV_SETS: - case BLE_HCI_OCF_LE_REMOVE_ADV_SET: - case BLE_HCI_OCF_LE_CLEAR_ADV_SETS: - case BLE_HCI_OCF_LE_SET_PERIODIC_ADV_PARAMS: - case BLE_HCI_OCF_LE_SET_PERIODIC_ADV_DATA: - case BLE_HCI_OCF_LE_SET_PERIODIC_ADV_ENABLE: - case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC: - case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC_CANCEL: - case BLE_HCI_OCF_LE_PERIODIC_ADV_TERM_SYNC: - case BLE_HCI_OCF_LE_ADD_DEV_TO_PERIODIC_ADV_LIST: - case BLE_HCI_OCF_LE_REM_DEV_FROM_PERIODIC_ADV_LIST: - case BLE_HCI_OCF_LE_CLEAR_PERIODIC_ADV_LIST: - case BLE_HCI_OCF_LE_RD_PERIODIC_ADV_LIST_SIZE: -#if MYNEWT_VAL(BLE_VERSION) >= 51 - case BLE_HCI_OCF_LE_PERIODIC_ADV_RECEIVE_ENABLE: -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER: - case BLE_HCI_OCF_LE_PERIODIC_ADV_SET_INFO_TRANSFER: - case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER_PARAMS: - case BLE_HCI_OCF_LE_SET_DEFAULT_SYNC_TRANSFER_PARAMS: -#endif - if (hci_adv_mode == ADV_MODE_LEGACY) { - return false; - } - - hci_adv_mode = ADV_MODE_EXT; - break; - default: - break; - } - - return true; -} -#endif - -static int -ble_ll_read_tx_power(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_transmit_power_rp *rsp = (void *) rspbuf; - - rsp->min_tx_power = ble_phy_txpower_round(-127); - rsp->max_tx_power = ble_phy_txpower_round(126); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -static int -ble_ll_read_rf_path_compensation(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_rf_path_compensation_rp *rsp = (void *) rspbuf; - - rsp->rx_path_compensation = htole16(rx_path_pwr_compensation); - rsp->tx_path_compensation = htole16(tx_path_pwr_compensation); - - *rsplen = sizeof(*rsp);; - return BLE_ERR_SUCCESS; -} - -static int -ble_ll_write_rf_path_compensation(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_wr_rf_path_compensation_cp *cmd = (const void *)cmdbuf; - int16_t rx; - int16_t tx; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - tx = le16toh(cmd->tx_path_compensation); - rx = le16toh(cmd->rx_path_compensation); - - if ((tx < -1280) || (tx > 1280) || (rx < -1280) || (rx > 1280)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - tx_path_pwr_compensation = tx; - rx_path_pwr_compensation = rx; - - ble_phy_set_rx_pwr_compensation(rx_path_pwr_compensation / 10); - - return BLE_ERR_SUCCESS; -} - -int8_t -ble_ll_get_tx_pwr_compensation(void) -{ - return tx_path_pwr_compensation / 10; -} - -/** - * Process a LE command sent from the host to the controller. The HCI command - * has a 3 byte command header followed by data. The header is: - * -> opcode (2 bytes) - * -> Length of parameters (1 byte; does include command header bytes). - * - * @param cmdbuf Pointer to command buffer. Points to start of command header. - * @param ocf Opcode command field. - * @param *rsplen Pointer to length of response - * - * @return int This function returns a BLE error code. If a command status - * event should be returned as opposed to command complete, - * 256 gets added to the return value. - */ -static int -ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, - uint8_t *rspbuf, uint8_t *rsplen, - ble_ll_hci_post_cmd_complete_cb *cb) -{ - int rc; - - /* Assume error; if all pass rc gets set to 0 */ - rc = BLE_ERR_INV_HCI_CMD_PARMS; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (!ble_ll_is_valid_adv_mode(ocf)) { - rc = BLE_ERR_CMD_DISALLOWED; - - /* - * This code is here because we add 256 to the return code to denote - * that the reply to this command should be command status (as opposed to - * command complete). - * - * For unknown HCI command let us return always command status as per - * specification Bluetooth 5, Vol. 2, Chapter 4.4 - */ - if (ble_ll_hci_le_cmd_send_cmd_status(ocf)) { - rc += (BLE_ERR_MAX + 1); - } - - return rc; - } -#endif - - switch (ocf) { - case BLE_HCI_OCF_LE_SET_EVENT_MASK: - rc = ble_ll_hci_set_le_event_mask(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_RD_BUF_SIZE: - if (len == 0) { - rc = ble_ll_hci_le_read_bufsize(rspbuf, rsplen); - } - break; - case BLE_HCI_OCF_LE_RD_LOC_SUPP_FEAT: - if (len == 0) { - rc = ble_ll_hci_le_read_local_features(rspbuf, rsplen); - } - break; - case BLE_HCI_OCF_LE_SET_RAND_ADDR: -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - rc = ble_ll_set_random_addr(cmdbuf, len, hci_adv_mode == ADV_MODE_EXT); -#else - rc = ble_ll_set_random_addr(cmdbuf, len, false); -#endif - break; - case BLE_HCI_OCF_LE_SET_ADV_PARAMS: - rc = ble_ll_adv_set_adv_params(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR: - if (len == 0) { - rc = ble_ll_adv_read_txpwr(rspbuf, rsplen); - } - break; - case BLE_HCI_OCF_LE_SET_ADV_DATA: - rc = ble_ll_hci_set_adv_data(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA: - rc = ble_ll_hci_set_scan_rsp_data(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_ADV_ENABLE: - rc = ble_ll_hci_adv_set_enable(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_SCAN_PARAMS: - rc = ble_ll_scan_set_scan_params(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_SCAN_ENABLE: - rc = ble_ll_hci_scan_set_enable(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_CREATE_CONN: - rc = ble_ll_conn_create(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_CREATE_CONN_CANCEL: - if (len == 0) { - rc = ble_ll_conn_create_cancel(cb); - } - break; - case BLE_HCI_OCF_LE_RD_WHITE_LIST_SIZE: - if (len == 0) { - rc = ble_ll_whitelist_read_size(rspbuf, rsplen); - } - break; - case BLE_HCI_OCF_LE_CLEAR_WHITE_LIST: - if (len == 0) { - rc = ble_ll_whitelist_clear(); - } - break; - case BLE_HCI_OCF_LE_ADD_WHITE_LIST: - rc = ble_ll_whitelist_add(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_RMV_WHITE_LIST: - rc = ble_ll_whitelist_rmv(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_CONN_UPDATE: - rc = ble_ll_conn_hci_update(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_HOST_CHAN_CLASS: - rc = ble_ll_conn_hci_set_chan_class(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_RD_CHAN_MAP: - rc = ble_ll_conn_hci_rd_chan_map(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_RD_REM_FEAT: - rc = ble_ll_conn_hci_read_rem_features(cmdbuf, len); - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - case BLE_HCI_OCF_LE_ENCRYPT: - rc = ble_ll_hci_le_encrypt(cmdbuf, len, rspbuf, rsplen); - break; -#endif - case BLE_HCI_OCF_LE_RAND: - if (len == 0) { - rc = ble_ll_hci_le_rand(rspbuf, rsplen); - } - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - case BLE_HCI_OCF_LE_START_ENCRYPT: - rc = ble_ll_conn_hci_le_start_encrypt(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY: - rc = ble_ll_conn_hci_le_ltk_reply(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY: - rc = ble_ll_conn_hci_le_ltk_neg_reply(cmdbuf, len, rspbuf, rsplen); - break; -#endif - case BLE_HCI_OCF_LE_RD_SUPP_STATES : - if (len == 0) { - rc = ble_ll_hci_le_read_supp_states(rspbuf, rsplen); - } - break; -#if MYNEWT_VAL(BLE_LL_DTM) - case BLE_HCI_OCF_LE_TX_TEST: - rc = ble_ll_hci_dtm_tx_test(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_RX_TEST: - rc = ble_ll_hci_dtm_rx_test(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_TEST_END: - if (len == 0) { - rc = ble_ll_dtm_end_test(rspbuf, rsplen); - } - break; -#endif - case BLE_HCI_OCF_LE_REM_CONN_PARAM_RR: - rc = ble_ll_conn_hci_param_rr(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR: - rc = ble_ll_conn_hci_param_nrr(cmdbuf, len, rspbuf, rsplen); - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) - case BLE_HCI_OCF_LE_SET_DATA_LEN: - rc = ble_ll_conn_hci_set_data_len(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_RD_SUGG_DEF_DATA_LEN: - if (len == 0) { - rc = ble_ll_hci_le_rd_sugg_data_len(rspbuf, rsplen); - } - break; - case BLE_HCI_OCF_LE_WR_SUGG_DEF_DATA_LEN: - rc = ble_ll_hci_le_wr_sugg_data_len(cmdbuf, len); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - case BLE_HCI_OCF_LE_ADD_RESOLV_LIST: - rc = ble_ll_resolv_list_add(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_RMV_RESOLV_LIST: - rc = ble_ll_resolv_list_rmv(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_CLR_RESOLV_LIST: - if (len == 0) { - rc = ble_ll_resolv_list_clr(); - } - break; - case BLE_HCI_OCF_LE_RD_RESOLV_LIST_SIZE: - if (len == 0) { - rc = ble_ll_resolv_list_read_size(rspbuf, rsplen); - } - break; - case BLE_HCI_OCF_LE_RD_PEER_RESOLV_ADDR: - rc = ble_ll_resolv_peer_addr_rd(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_RD_LOCAL_RESOLV_ADDR: - rc = ble_ll_resolv_local_addr_rd(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_SET_ADDR_RES_EN: - rc = ble_ll_resolv_enable_cmd(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_RPA_TMO: - rc = ble_ll_resolv_set_rpa_tmo(cmdbuf, len); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) - case BLE_HCI_OCF_LE_RD_MAX_DATA_LEN: - if (len == 0) { - rc = ble_ll_hci_le_rd_max_data_len(rspbuf, rsplen); - } - break; -#endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - case BLE_HCI_OCF_LE_RD_PHY: - rc = ble_ll_conn_hci_le_rd_phy(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_SET_DEFAULT_PHY: - rc = ble_ll_hci_le_set_def_phy(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_PHY: - rc = ble_ll_conn_hci_le_set_phy(cmdbuf, len); - break; -#endif -#if MYNEWT_VAL(BLE_LL_DTM) - case BLE_HCI_OCF_LE_RX_TEST_V2: - rc = ble_ll_hci_dtm_rx_test_v2(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_TX_TEST_V2: - rc = ble_ll_hci_dtm_tx_test_v2(cmdbuf, len); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - case BLE_HCI_OCF_LE_SET_ADV_SET_RND_ADDR: - rc = ble_ll_adv_hci_set_random_addr(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_EXT_ADV_PARAM: - rc = ble_ll_adv_ext_set_param(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_SET_EXT_ADV_DATA: - rc = ble_ll_adv_ext_set_adv_data(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_EXT_SCAN_RSP_DATA: - rc = ble_ll_adv_ext_set_scan_rsp(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_EXT_ADV_ENABLE: - rc = ble_ll_adv_ext_set_enable(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_RD_MAX_ADV_DATA_LEN: - if (len == 0) { - rc = ble_ll_adv_rd_max_adv_data_len(rspbuf, rsplen); - } - break; - case BLE_HCI_OCF_LE_RD_NUM_OF_ADV_SETS: - if (len == 0) { - rc = ble_ll_adv_rd_sup_adv_sets(rspbuf, rsplen); - } - break; - case BLE_HCI_OCF_LE_REMOVE_ADV_SET: - rc = ble_ll_adv_remove(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_CLEAR_ADV_SETS: - if (len == 0) { - rc = ble_ll_adv_clear_all(); - } - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - case BLE_HCI_OCF_LE_SET_PERIODIC_ADV_PARAMS: - rc = ble_ll_adv_periodic_set_param(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_PERIODIC_ADV_DATA: - rc = ble_ll_adv_periodic_set_data(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_PERIODIC_ADV_ENABLE: - rc = ble_ll_adv_periodic_enable(cmdbuf, len); - break; -#endif -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - case BLE_HCI_OCF_LE_SET_EXT_SCAN_PARAM: - rc = ble_ll_set_ext_scan_params(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_EXT_SCAN_ENABLE: - rc = ble_ll_hci_ext_scan_set_enable(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_EXT_CREATE_CONN: - rc = ble_ll_ext_conn_create(cmdbuf, len); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC: - rc = ble_ll_sync_create(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC_CANCEL: - if (len == 0) { - rc = ble_ll_sync_cancel(cb); - } - break; - case BLE_HCI_OCF_LE_PERIODIC_ADV_TERM_SYNC: - rc = ble_ll_sync_terminate(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_ADD_DEV_TO_PERIODIC_ADV_LIST: - rc = ble_ll_sync_list_add(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_REM_DEV_FROM_PERIODIC_ADV_LIST: - rc = ble_ll_sync_list_remove(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_CLEAR_PERIODIC_ADV_LIST: - if (len == 0) { - rc = ble_ll_sync_list_clear(); - } - break; - case BLE_HCI_OCF_LE_RD_PERIODIC_ADV_LIST_SIZE: - if (len == 0) { - rc = ble_ll_sync_list_size(rspbuf, rsplen); - } - break; -#if MYNEWT_VAL(BLE_VERSION) >= 51 - case BLE_HCI_OCF_LE_PERIODIC_ADV_RECEIVE_ENABLE: - rc = ble_ll_sync_receive_enable(cmdbuf, len); - break; -#endif -#endif - case BLE_HCI_OCF_LE_RD_TRANSMIT_POWER: - rc = ble_ll_read_tx_power(rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_RD_RF_PATH_COMPENSATION: - rc = ble_ll_read_rf_path_compensation(rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_WR_RF_PATH_COMPENSATION: - rc = ble_ll_write_rf_path_compensation(cmdbuf, len); - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - case BLE_HCI_OCF_LE_SET_PRIVACY_MODE: - rc = ble_ll_resolve_set_priv_mode(cmdbuf, len); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER: - rc = ble_ll_sync_transfer(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_PERIODIC_ADV_SET_INFO_TRANSFER: - rc = ble_ll_adv_periodic_set_info_transfer(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER_PARAMS: - rc = ble_ll_set_sync_transfer_params(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_SET_DEFAULT_SYNC_TRANSFER_PARAMS: - rc = ble_ll_set_default_sync_transfer_params(cmdbuf, len); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) - case BLE_HCI_OCF_LE_READ_ISO_TX_SYNC: - rc = ble_ll_iso_read_tx_sync(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_SET_CIG_PARAM: - rc = ble_ll_iso_set_cig_param(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_CREATE_CIS: - rc = ble_ll_iso_create_cis(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_REMOVE_CIG: - rc = ble_ll_iso_remove_cig(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_ACCEPT_CIS_REQ: - rc = ble_ll_iso_accept_cis_req(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_REJECT_CIS_REQ: - rc = ble_ll_iso_reject_cis_req(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_CREATE_BIG: - rc = ble_ll_iso_create_big(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_TERMINATE_BIG: - rc = ble_ll_iso_terminate_big(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_BIG_CREATE_SYNC: - rc = ble_ll_iso_big_create_sync(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_BIG_TERMINATE_SYNC: - rc = ble_ll_iso_big_terminate_sync(cmdbuf,len); - break; - case BLE_HCI_OCF_LE_SETUP_ISO_DATA_PATH: - rc = ble_ll_iso_setup_iso_data_path(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_REMOVE_ISO_DATA_PATH: - rc = ble_ll_iso_remove_iso_data_path(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_RD_BUF_SIZE_V2: - rc = ble_ll_hci_le_read_bufsize_v2(rspbuf, rsplen); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO_TEST) - case BLE_HCI_OCF_LE_SET_CIG_PARAM_TEST: - rc = ble_ll_iso_set_cig_param_test(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_CREATE_BIG_TEST: - rc = ble_ll_iso_create_big_test(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_ISO_TRANSMIT_TEST: - rc = ble_ll_iso_transmit_test(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_ISO_RECEIVE_TEST: - rc = ble_ll_iso_receive_test(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_ISO_READ_TEST_COUNTERS: - rc = ble_ll_iso_read_counters_test(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_ISO_TEST_END: - rc = ble_ll_iso_end_test(cmdbuf, len); - break; -#endif -#if MYNEWT_VAL(BLE_VERSION) >= 52 - case BLE_HCI_OCF_LE_SET_HOST_FEAT: - rc = ble_ll_set_host_feat(cmdbuf, len); - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) - case BLE_HCI_OCF_LE_REQ_PEER_SCA: - rc = ble_ll_conn_req_peer_sca(cmdbuf, len, - rspbuf, rsplen); - break; -#endif - default: - rc = BLE_ERR_UNKNOWN_HCI_CMD; - break; - } - - /* - * This code is here because we add 256 to the return code to denote - * that the reply to this command should be command status (as opposed to - * command complete). - * - * For unknown HCI command let us return always command status as per - * specification Bluetooth 5, Vol. 2, Chapter 4.4 - */ - if (ble_ll_hci_le_cmd_send_cmd_status(ocf) || rc == BLE_ERR_UNKNOWN_HCI_CMD) { - rc += (BLE_ERR_MAX + 1); - } - - return rc; -} - -static int -ble_ll_hci_disconnect(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_lc_disconnect_cp *cmd; - - cmd = (const void *) cmdbuf; - - if (len != sizeof (*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) - if (le16toh(cmd->conn_handle) >= BLE_LL_CONN_HANDLE_ISO_OFFSET) { - return ble_ll_iso_disconnect_cmd(cmd); - } -#endif - - return ble_ll_conn_hci_disconnect_cmd(cmd); -} - -/** - * Process a link control command sent from the host to the controller. The HCI - * command has a 3 byte command header followed by data. The header is: - * -> opcode (2 bytes) - * -> Length of parameters (1 byte; does include command header bytes). - * - * @param cmdbuf Pointer to command buffer. Points to start of command header. - * @param ocf Opcode command field. - * - * @return int This function returns a BLE error code. If a command status - * event should be returned as opposed to command complete, - * 256 gets added to the return value. - */ -static int -ble_ll_hci_link_ctrl_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf) -{ - int rc; - - switch (ocf) { - case BLE_HCI_OCF_DISCONNECT_CMD: - rc = ble_ll_hci_disconnect(cmdbuf, len); - /* Send command status instead of command complete */ - rc += (BLE_ERR_MAX + 1); - break; - - case BLE_HCI_OCF_RD_REM_VER_INFO: - rc = ble_ll_conn_hci_rd_rem_ver_cmd(cmdbuf, len); - /* Send command status instead of command complete */ - rc += (BLE_ERR_MAX + 1); - break; - - default: - rc = BLE_ERR_UNKNOWN_HCI_CMD; - break; - } - - return rc; -} - -static int -ble_ll_hci_cb_set_event_mask(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_cb_set_event_mask_cp *cmd = (const void *) cmdbuf; - - if (len != sizeof (*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - g_ble_ll_hci_event_mask = le64toh(cmd->event_mask); - - return BLE_ERR_SUCCESS; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) -static int -ble_ll_hci_cb_set_ctrlr_to_host_fc(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_cb_ctlr_to_host_fc_cp *cmd = (const void *) cmdbuf; - - if (len != sizeof (*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* We only allow to either disable flow control or enable for ACL only */ - if (cmd->enable > 1) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (!ble_ll_conn_cth_flow_enable(cmd->enable)) { - return BLE_ERR_CMD_DISALLOWED; - } - - return BLE_ERR_SUCCESS; -} - -static int -ble_ll_hci_cb_host_buf_size(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_cb_host_buf_size_cp *cmd = (const void *) cmdbuf; - uint16_t acl_num; - uint16_t acl_data_len; - - if (len != sizeof (*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* We do not support SCO so those parameters should be set to 0 */ - if (cmd->sco_num || cmd->sco_data_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* - * Core 5.2 Vol 4 Part E section 7.3.39 states that "Both the Host and the - * Controller shall support command and event packets, where the data portion - * (excluding header) contained in the packets is 255 octets in size.". - * This means we can basically accept any allowed value since LL does not - * reassemble incoming data thus will not send more than 255 octets in single - * data packet. - */ - acl_num = le16toh(cmd->acl_num); - acl_data_len = le16toh(cmd->acl_data_len); - if (acl_data_len < 255) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - ble_ll_conn_cth_flow_set_buffers(acl_num); - - return BLE_ERR_SUCCESS; -} -#endif - -static int -ble_ll_hci_cb_set_event_mask2(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_cb_set_event_mask2_cp *cmd = (const void *) cmdbuf; - - if (len != sizeof (*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - g_ble_ll_hci_event_mask2 = le64toh(cmd->event_mask2); - - return BLE_ERR_SUCCESS; -} - -static int -ble_ll_hci_ctlr_bb_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, - uint8_t *rspbuf, uint8_t *rsplen) -{ - int rc; - - /* Assume error; if all pass rc gets set to 0 */ - rc = BLE_ERR_INV_HCI_CMD_PARMS; - - switch (ocf) { - case BLE_HCI_OCF_CB_SET_EVENT_MASK: - rc = ble_ll_hci_cb_set_event_mask(cmdbuf, len); - break; - case BLE_HCI_OCF_CB_RESET: - if (len == 0) { - rc = ble_ll_reset(); - } - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) - case BLE_HCI_OCF_CB_SET_CTLR_TO_HOST_FC: - rc = ble_ll_hci_cb_set_ctrlr_to_host_fc(cmdbuf, len); - break; - case BLE_HCI_OCF_CB_HOST_BUF_SIZE: - rc = ble_ll_hci_cb_host_buf_size(cmdbuf, len); - break; - case BLE_HCI_OCF_CB_HOST_NUM_COMP_PKTS: - /* - * HCI_Host_Number_Of_Completed_Packets is handled immediately when - * received from transport so we should never receive it here. - */ - BLE_LL_ASSERT(0); - rc = BLE_ERR_UNKNOWN_HCI_CMD; - break; -#endif - case BLE_HCI_OCF_CB_SET_EVENT_MASK2: - rc = ble_ll_hci_cb_set_event_mask2(cmdbuf, len); - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) - case BLE_HCI_OCF_CB_RD_AUTH_PYLD_TMO: - rc = ble_ll_conn_hci_rd_auth_pyld_tmo(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_CB_WR_AUTH_PYLD_TMO: - rc = ble_ll_conn_hci_wr_auth_pyld_tmo(cmdbuf, len, rspbuf, rsplen); - break; -#endif - default: - rc = BLE_ERR_UNKNOWN_HCI_CMD; - break; - } - - return rc; -} - -static int -ble_ll_hci_info_params_cmd_proc(const uint8_t *cmdbuf, uint8_t len, - uint16_t ocf, uint8_t *rspbuf, uint8_t *rsplen) -{ - int rc; - - /* Assume error; if all pass rc gets set to 0 */ - rc = BLE_ERR_INV_HCI_CMD_PARMS; - - switch (ocf) { - case BLE_HCI_OCF_IP_RD_LOCAL_VER: - if (len == 0) { - rc = ble_ll_hci_rd_local_version(rspbuf, rsplen); - } - break; - case BLE_HCI_OCF_IP_RD_LOC_SUPP_CMD: - if (len == 0) { - rc = ble_ll_hci_rd_local_supp_cmd(rspbuf, rsplen); - } - break; - case BLE_HCI_OCF_IP_RD_LOC_SUPP_FEAT: - if (len == 0) { - rc = ble_ll_hci_rd_local_supp_feat(rspbuf, rsplen); - } - break; - case BLE_HCI_OCF_IP_RD_BD_ADDR: - if (len == 0) { - rc = ble_ll_hci_rd_bd_addr(rspbuf, rsplen); - } - break; - default: - rc = BLE_ERR_UNKNOWN_HCI_CMD; - break; - } - - return rc; -} - -static int -ble_ll_hci_status_params_cmd_proc(const uint8_t *cmdbuf, uint8_t len, - uint16_t ocf, uint8_t *rspbuf, - uint8_t *rsplen) -{ - int rc; - - switch (ocf) { - case BLE_HCI_OCF_RD_RSSI: - rc = ble_ll_conn_hci_rd_rssi(cmdbuf, len, rspbuf, rsplen); - break; - default: - rc = BLE_ERR_UNKNOWN_HCI_CMD; - break; - } - - return rc; -} - -#if MYNEWT_VAL(BLE_HCI_VS) -static int -ble_ll_hci_vs_rd_static_addr(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_vs_rd_static_addr_rp *rsp = (void *) rspbuf; - ble_addr_t addr; - - if (ble_hw_get_static_addr(&addr) < 0) { - return BLE_ERR_UNSPECIFIED; - } - - memcpy(rsp->addr, addr.val, sizeof(rsp->addr)); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -static int -ble_ll_hci_vs_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, - uint8_t *rspbuf, uint8_t *rsplen) -{ - int rc; - - /* Assume error; if all pass rc gets set to 0 */ - rc = BLE_ERR_INV_HCI_CMD_PARMS; - - switch (ocf) { - case BLE_HCI_OCF_VS_RD_STATIC_ADDR: - if (len == 0) { - rc = ble_ll_hci_vs_rd_static_addr(rspbuf, rsplen); - } - break; - default: - rc = BLE_ERR_UNKNOWN_HCI_CMD; - break; - } - - return rc; -} -#endif - -/** - * Called to process an HCI command from the host. - * - * @param ev Pointer to os event containing a pointer to command buffer - */ -static void -ble_ll_hci_cmd_proc(struct ble_npl_event *ev) -{ - int rc; - uint8_t ogf; - uint8_t rsplen; - struct ble_hci_cmd *cmd; - uint16_t opcode; - uint16_t ocf; - ble_ll_hci_post_cmd_complete_cb post_cb = NULL; - struct ble_hci_ev *hci_ev; - struct ble_hci_ev_command_status *cmd_status; - struct ble_hci_ev_command_complete *cmd_complete; - uint8_t *rspbuf; - - BLE_LL_DEBUG_GPIO(HCI_CMD, 1); - - /* The command buffer is the event argument */ - cmd = ble_npl_event_get_arg(ev); - BLE_LL_ASSERT(cmd != NULL); - - /* Get the opcode from the command buffer */ - opcode = le16toh(cmd->opcode); - ocf = BLE_HCI_OCF(opcode); - ogf = BLE_HCI_OGF(opcode); - - /* - * The command response pointer points into the same buffer as the - * command data itself. That is fine, as each command reads all the data - * before crafting a response. - * Also reuse cmd buffer for complete event - */ - hci_ev = (struct ble_hci_ev *) cmd; - rspbuf = hci_ev->data + sizeof(*cmd_complete); - - /* Assume response length is zero */ - rsplen = 0; - - switch (ogf) { - case BLE_HCI_OGF_LINK_CTRL: - rc = ble_ll_hci_link_ctrl_cmd_proc(cmd->data, cmd->length, ocf); - break; - case BLE_HCI_OGF_CTLR_BASEBAND: - rc = ble_ll_hci_ctlr_bb_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen); - break; - case BLE_HCI_OGF_INFO_PARAMS: - rc = ble_ll_hci_info_params_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen); - break; - case BLE_HCI_OGF_STATUS_PARAMS: - rc = ble_ll_hci_status_params_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen); - break; - case BLE_HCI_OGF_LE: - rc = ble_ll_hci_le_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen, &post_cb); - break; -#if MYNEWT_VAL(BLE_HCI_VS) - case BLE_HCI_OGF_VENDOR: - rc = ble_ll_hci_vs_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen); - break; -#endif - default: - /* XXX: Need to support other OGF. For now, return unsupported */ - rc = BLE_ERR_UNKNOWN_HCI_CMD; - break; - } - - /* If no response is generated, we free the buffers */ - BLE_LL_ASSERT(rc >= 0); - if (rc <= BLE_ERR_MAX) { - /* Create a command complete event with status from command */ - hci_ev->opcode = BLE_HCI_EVCODE_COMMAND_COMPLETE; - hci_ev->length = sizeof(*cmd_complete) + rsplen; - - cmd_complete = (void *) hci_ev->data; - cmd_complete->num_packets = ble_ll_hci_get_num_cmd_pkts(); - cmd_complete->opcode = htole16(opcode); - cmd_complete->status = (uint8_t) rc; - } else { - /* Create a command status event */ - rc -= (BLE_ERR_MAX + 1); - - hci_ev->opcode = BLE_HCI_EVCODE_COMMAND_STATUS; - hci_ev->length = sizeof(*cmd_status); - - cmd_status = (void *) hci_ev->data; - cmd_status->status = (uint8_t)rc; - cmd_status->num_packets = ble_ll_hci_get_num_cmd_pkts(); - cmd_status->opcode = htole16(opcode); - } - - /* Count commands and those in error */ - if (rc) { - STATS_INC(ble_ll_stats, hci_cmd_errs); - } else { - STATS_INC(ble_ll_stats, hci_cmds); - } - - /* Send the event (events cannot be masked) */ - ble_ll_hci_event_send(hci_ev); - - /* Call post callback if set by command handler */ - if (post_cb) { - post_cb(); - } - - BLE_LL_DEBUG_GPIO(HCI_CMD, 0); -} - -/** - * Sends an HCI command to the controller. On success, the supplied buffer is - * relinquished to the controller task. On failure, the caller must free the - * buffer. - * - * @param cmd A flat buffer containing the HCI command to - * send. - * - * @return 0 on success; - * BLE_ERR_MEM_CAPACITY on HCI buffer exhaustion. - */ -int -ble_ll_hci_cmd_rx(uint8_t *cmdbuf, void *arg) -{ - struct ble_npl_event *ev; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) - const struct ble_hci_cmd *cmd; - uint16_t opcode; - uint16_t ocf; - uint16_t ogf; - - cmd = (const void *)cmdbuf; - opcode = le16toh(cmd->opcode); - ogf = BLE_HCI_OGF(opcode); - ocf = BLE_HCI_OCF(opcode); - - /* - * HCI_Host_Number_Of_Completed_Packets is processed outside standard flow - * thus it can be sent at any time, even if another command is already - * pending. This means we should better process it here and send an event to - * LL in case of error. - */ - if ((ogf == BLE_HCI_OGF_CTLR_BASEBAND) && - (ocf == BLE_HCI_OCF_CB_HOST_NUM_COMP_PKTS)) { - ble_ll_conn_cth_flow_process_cmd(cmdbuf); - ble_hci_trans_buf_free(cmdbuf); - return 0; - } -#endif - - /* Get an event structure off the queue */ - ev = &g_ble_ll_hci_cmd_ev; - if (ble_npl_event_is_queued(ev)) { - return BLE_ERR_MEM_CAPACITY; - } - - /* Fill out the event and post to Link Layer */ - ble_npl_event_set_arg(ev, cmdbuf); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, ev); - - return 0; -} - -/* Send ACL data from host to contoller */ -int -ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg) -{ - ble_ll_acl_data_in(om); - return 0; -} - -/** - * Initalize the LL HCI. - * - * NOTE: This function is called by the HCI RESET command so if any code - * is added here it must be OK to be executed when the reset command is used. - */ -void -ble_ll_hci_init(void) -{ - BLE_LL_DEBUG_GPIO_INIT(HCI_CMD); - BLE_LL_DEBUG_GPIO_INIT(HCI_EV); - - /* Set event callback for command processing */ - ble_npl_event_init(&g_ble_ll_hci_cmd_ev, ble_ll_hci_cmd_proc, NULL); - - /* Set defaults for LE events: Vol 2 Part E 7.8.1 */ - g_ble_ll_hci_le_event_mask = 0x1f; - - /* Set defaults for controller/baseband events: Vol 2 Part E 7.3.1 */ - g_ble_ll_hci_event_mask = 0x1fffffffffff; - - - /* Set page 2 to 0 */ - g_ble_ll_hci_event_mask2 = 0; - - /* reset RF path compensation values */ - rx_path_pwr_compensation = 0; - tx_path_pwr_compensation = 0; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* after reset both legacy and extended advertising commands are allowed */ - hci_adv_mode = ADV_MODE_ANY; -#endif -} - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_hci_ev.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_hci_ev.c deleted file mode 100644 index 1ba4e815c..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_hci_ev.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "nimble/nimble/include/nimble/ble_hci_trans.h" -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_hci.h" -#include "../include/controller/ble_ll_ctrl.h" -#include "ble_ll_conn_priv.h" - -#if (BLETEST_CONCURRENT_CONN_TEST == 1) -extern void bletest_ltk_req_reply(uint16_t handle); -#endif - -/** - * Send a data length change event for a connection to the host. - * - * @param connsm Pointer to connection state machine - */ -void -ble_ll_hci_ev_datalen_chg(struct ble_ll_conn_sm *connsm) -{ - struct ble_hci_ev_le_subev_data_len_chg *ev; - struct ble_hci_ev *hci_ev; - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_DATA_LEN_CHG)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_DATA_LEN_CHG; - ev->conn_handle = htole16(connsm->conn_handle); - - ev->max_tx_octets = htole16(connsm->eff_max_tx_octets); - ev->max_tx_time = htole16(connsm->eff_max_tx_time); - ev->max_rx_octets = htole16(connsm->eff_max_rx_octets); - ev->max_rx_time = htole16(connsm->eff_max_rx_time); - - ble_ll_hci_event_send(hci_ev); - } - } -} - -/** - * Send a connection parameter request event for a connection to the host. - * - * @param connsm Pointer to connection state machine - */ -void -ble_ll_hci_ev_rem_conn_parm_req(struct ble_ll_conn_sm *connsm, - struct ble_ll_conn_params *cp) -{ - struct ble_hci_ev_le_subev_rem_conn_param_req *ev; - struct ble_hci_ev *hci_ev; - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ; - ev->conn_handle = htole16(connsm->conn_handle); - ev->min_interval = htole16(cp->interval_min); - ev->max_interval = htole16(cp->interval_max); - ev->latency = htole16(cp->latency); - ev->timeout = htole16(cp->timeout); - - ble_ll_hci_event_send(hci_ev); - } - } -} - -/** - * Send a connection update event. - * - * @param connsm Pointer to connection state machine - * @param status The error code. - */ -void -ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status) -{ - struct ble_hci_ev_le_subev_conn_upd_complete *ev; - struct ble_hci_ev *hci_ev; - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE; - ev->status = status; - ev->conn_handle = htole16(connsm->conn_handle); - ev->conn_itvl = htole16(connsm->conn_itvl); - ev->conn_latency = htole16(connsm->slave_latency); - ev->supervision_timeout = htole16(connsm->supervision_tmo); - - ble_ll_hci_event_send(hci_ev); - } - } -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -void -ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status) -{ - struct ble_hci_ev_enc_key_refresh *ev_key_refresh; - struct ble_hci_ev_enrypt_chg *ev_enc_chf; - struct ble_hci_ev *hci_ev; - - if (CONN_F_ENC_CHANGE_SENT(connsm) == 0) { - if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_ENCRYPT_CHG)) { - hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_ENCRYPT_CHG; - hci_ev->length = sizeof(*ev_enc_chf); - ev_enc_chf = (void *) hci_ev->data; - - ev_enc_chf->status = status; - ev_enc_chf->connection_handle = htole16(connsm->conn_handle); - ev_enc_chf->enabled = (status == BLE_ERR_SUCCESS) ? 0x01 : 0x00; - - ble_ll_hci_event_send(hci_ev); - } - } - - CONN_F_ENC_CHANGE_SENT(connsm) = 1; - return; - } - - if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_ENC_KEY_REFRESH)) { - hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_ENC_KEY_REFRESH; - hci_ev->length = sizeof(*ev_key_refresh); - ev_key_refresh = (void *) hci_ev->data; - - ev_key_refresh->status = status; - ev_key_refresh->conn_handle = htole16(connsm->conn_handle); - - ble_ll_hci_event_send(hci_ev); - } - } -} - -/** - * Send a long term key request event for a connection to the host. - * - * @param connsm Pointer to connection state machine - */ -int -ble_ll_hci_ev_ltk_req(struct ble_ll_conn_sm *connsm) -{ - struct ble_hci_ev_le_subev_lt_key_req *ev; - struct ble_hci_ev *hci_ev; - int rc; - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_LT_KEY_REQ)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_LT_KEY_REQ; - ev->conn_handle = htole16(connsm->conn_handle); - ev->rand = htole64(connsm->enc_data.host_rand_num); - ev->div = htole16(connsm->enc_data.enc_div); - - ble_ll_hci_event_send(hci_ev); - } - rc = 0; - } else { - rc = -1; - } - -#if (BLETEST_CONCURRENT_CONN_TEST == 1) - if (rc == 0) { - bletest_ltk_req_reply(connsm->conn_handle); - } -#endif - return rc; -} -#endif - -void -ble_ll_hci_ev_rd_rem_used_feat(struct ble_ll_conn_sm *connsm, uint8_t status) -{ - struct ble_hci_ev_le_subev_rd_rem_used_feat *ev; - struct ble_hci_ev *hci_ev; - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT; - ev->status = status; - ev->conn_handle = htole16(connsm->conn_handle); - ev->features[0] = connsm->conn_features; - memcpy(ev->features + 1, connsm->remote_features, 7); - - ble_ll_hci_event_send(hci_ev); - } - } -} - -void -ble_ll_hci_ev_rd_rem_ver(struct ble_ll_conn_sm *connsm, uint8_t status) -{ - struct ble_hci_ev_rd_rem_ver_info_cmp *ev; - struct ble_hci_ev *hci_ev; - - if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->status = status; - ev->conn_handle = htole16(connsm->conn_handle); - ev->version = connsm->vers_nr; - ev->manufacturer = htole16(connsm->comp_id); - ev->subversion = htole16(connsm->sub_vers_nr); - - ble_ll_hci_event_send(hci_ev); - } - } -} - -/** - * Send a HW error to the host. - * - * @param hw_err - * - * @return int 0: event masked or event sent, -1 otherwise - */ -int -ble_ll_hci_ev_hw_err(uint8_t hw_err) -{ - struct ble_hci_ev_hw_error *ev; - struct ble_hci_ev *hci_ev; - int rc; - - rc = 0; - if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_HW_ERROR)) { - hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_HW_ERROR; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->hw_code = hw_err; - - ble_ll_hci_event_send(hci_ev); - } else { - rc = -1; - } - } - return rc; -} - -void -ble_ll_hci_ev_databuf_overflow(void) -{ - struct ble_hci_ev_data_buf_overflow *ev; - struct ble_hci_ev *hci_ev; - - if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_DATA_BUF_OVERFLOW)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_DATA_BUF_OVERFLOW; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->link_type = BLE_HCI_EVENT_ACL_BUF_OVERFLOW; - - ble_ll_hci_event_send(hci_ev); - } - } -} - -/** - * Send a LE Channel Selection Algorithm event. - * - * @param connsm Pointer to connection state machine - */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) -void -ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm) -{ - struct ble_hci_ev_le_subev_chan_sel_alg *ev; - struct ble_hci_ev *hci_ev; - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CHAN_SEL_ALG)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_CHAN_SEL_ALG; - ev->conn_handle = htole16(connsm->conn_handle); - ev->csa = connsm->csmflags.cfbit.csa2_supp ? 0x01 : 0x00; - - ble_ll_hci_event_send(hci_ev); - } - } -} -#endif - -/** - * Sends the LE Scan Request Received event - * - */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -void -ble_ll_hci_ev_send_scan_req_recv(uint8_t adv_handle, const uint8_t *peer, - uint8_t peer_addr_type) -{ - struct ble_hci_ev_le_subev_scan_req_rcvd *ev; - struct ble_hci_ev *hci_ev; - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD; - ev->adv_handle = adv_handle; - ev->peer_addr_type = peer_addr_type; - memcpy(ev->peer_addr, peer, BLE_DEV_ADDR_LEN); - - ble_ll_hci_event_send(hci_ev); - } - } -} -#endif - -/** - * Sends the LE Scan Timeout Event - * - */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -void -ble_ll_hci_ev_send_scan_timeout(void) -{ - struct ble_hci_ev_le_subev_scan_timeout *ev; - struct ble_hci_ev *hci_ev; - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_SCAN_TIMEOUT)) { - hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_SCAN_TIMEOUT; - - ble_ll_hci_event_send(hci_ev); - } - } -} -#endif - -/** - * Sends the LE Advertising Set Terminated event - * - */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -void -ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle, - uint16_t conn_handle, uint8_t events) -{ - struct ble_hci_ev_le_subev_adv_set_terminated *ev; - struct ble_hci_ev *hci_ev; - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED; - ev->status = status; - ev->adv_handle = adv_handle; - ev->conn_handle = htole16(conn_handle); - ev->num_events = events; - - ble_ll_hci_event_send(hci_ev); - } - } -} -#endif - -/** - * Send a PHY update complete event - * - * @param connsm Pointer to connection state machine - * @param status error status of event - */ -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) -int -ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status) -{ - struct ble_hci_ev_le_subev_phy_update_complete *ev; - struct ble_hci_ev *hci_ev; - int rc; - - rc = 0; - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PHY_UPDATE_COMPLETE)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_PHY_UPDATE_COMPLETE; - ev->status = status; - ev->conn_handle = htole16(connsm->conn_handle); - ev->tx_phy = connsm->phy_data.cur_tx_phy; - ev->rx_phy = connsm->phy_data.cur_rx_phy; - - ble_ll_hci_event_send(hci_ev); - } else { - rc = BLE_ERR_MEM_CAPACITY; - } - } - return rc; -} -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) -void -ble_ll_hci_ev_sca_update(struct ble_ll_conn_sm *connsm, uint8_t status, - uint8_t peer_sca) -{ - struct ble_hci_ev_le_subev_peer_sca_complete *ev; - struct ble_hci_ev *hci_ev; - - if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_REQ_PEER_SCA_COMP)) { - return; - } - - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (!hci_ev) { - return; - } - - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_REQ_PEER_SCA_COMP; - ev->status = status; - ev->conn_handle = htole16(connsm->conn_handle); - ev->sca = peer_sca; - - ble_ll_hci_event_send(hci_ev); -} - -#endif - -void -ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line) -{ - struct ble_hci_ev_vendor_debug *ev; - struct ble_hci_ev *hci_ev; - unsigned int str_len; - bool skip = true; - uint8_t digit; - int max_len; - int i; - - /* 6 is for line number ":00000" , we assume files have no more than 64k of - * lines - */ - max_len = BLE_HCI_MAX_DATA_LEN - sizeof(*ev) - 6; - - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_VENDOR_DEBUG; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - /* Debug id for future use */ - ev->id = 0x00; - - /* snprintf would be nicer but this is heavy on flash - * len = snprintf((char *) ev->data, max_len, "%s:%u", file, line); - * if (len < 0) { - * len = 0; - * } else if (len > max_len) { - * len = max_len; - * } - * - * hci_ev->length += len; - */ - str_len = strlen(file); - if (str_len > max_len) { - str_len = max_len; - } - - memcpy(ev->data, file, str_len); - ev->data[str_len++] = ':'; - - for (i = 100000; i >= 10; i /= 10) { - digit = (line % i) / (i/10); - - if (!digit && skip) { - continue; - } - - skip = false; - ev->data[str_len++] = '0' + digit; - } - - hci_ev->length += str_len; - - ble_ll_hci_event_send(hci_ev); - } -} - -#endif \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_iso.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_iso.c deleted file mode 100644 index ac8ca1e8a..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_iso.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "../include/controller/ble_ll_iso.h" - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) - -int -ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_set_cig_param(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_create_cis(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_remove_cig(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_accept_cis_req(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_reject_cis_req(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t len) -{ - /* Nothing to do here for now when HCI is supported */ - return 0; -} -int -ble_ll_iso_create_big(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_terminate_big(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_big_create_sync(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_big_terminate_sync(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO_TEST) -int -ble_ll_iso_set_cig_param_test(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_create_big_test(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_transmit_test(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_receive_test(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_read_counters_test(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} -#endif -#endif -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_priv.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_priv.h deleted file mode 100644 index 900950ef6..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_priv.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_LL_PRIV_ -#define H_BLE_LL_PRIV_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef MYNEWT - -#include "syscfg/syscfg.h" -#include "hal/hal_gpio.h" - -#define BLE_LL_DEBUG_GPIO_INIT(_name) \ - if (MYNEWT_VAL(BLE_LL_DEBUG_GPIO_ ## _name) >= 0) { \ - hal_gpio_init_out(MYNEWT_VAL(BLE_LL_DEBUG_GPIO_ ## _name), 0); \ - } - -#define BLE_LL_DEBUG_GPIO(_name, _val) \ - if (MYNEWT_VAL(BLE_LL_DEBUG_GPIO_ ## _name) >= 0) { \ - hal_gpio_write(MYNEWT_VAL(BLE_LL_DEBUG_GPIO_ ## _name), !!(_val)); \ - } - -#else -#define BLE_LL_DEBUG_GPIO_INIT(_name) (void)(0) -#define BLE_LL_DEBUG_GPIO(_name, _val) (void)(0) -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_LL_PRIV_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_rand.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_rand.c deleted file mode 100644 index d0b82ba5a..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_rand.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -/* for jrand48 */ -#define _XOPEN_SOURCE -#include -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "../include/controller/ble_hw.h" -#include "../include/controller/ble_ll.h" -#if MYNEWT_VAL(TRNG) -#include "trng/trng.h" -#endif - -#if MYNEWT_VAL(TRNG) -static struct trng_dev *g_trng; -#else -/* This is a simple circular buffer for holding N samples of random data */ -struct ble_ll_rnum_data -{ - uint8_t *rnd_in; - uint8_t *rnd_out; - volatile uint8_t rnd_size; -}; - -struct ble_ll_rnum_data g_ble_ll_rnum_data; -uint8_t g_ble_ll_rnum_buf[MYNEWT_VAL(BLE_LL_RNG_BUFSIZE)]; - -#define IS_RNUM_BUF_END(x) \ - (x == &g_ble_ll_rnum_buf[MYNEWT_VAL(BLE_LL_RNG_BUFSIZE) - 1]) - -void -ble_ll_rand_sample(uint8_t rnum) -{ - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - if (g_ble_ll_rnum_data.rnd_size < MYNEWT_VAL(BLE_LL_RNG_BUFSIZE)) { - ++g_ble_ll_rnum_data.rnd_size; - g_ble_ll_rnum_data.rnd_in[0] = rnum; - if (IS_RNUM_BUF_END(g_ble_ll_rnum_data.rnd_in)) { - g_ble_ll_rnum_data.rnd_in = g_ble_ll_rnum_buf; - } else { - ++g_ble_ll_rnum_data.rnd_in; - } - } else { - /* Stop generating random numbers as we are full */ - ble_hw_rng_stop(); - } - OS_EXIT_CRITICAL(sr); -} -#endif - -/* Get 'len' bytes of random data */ -int -ble_ll_rand_data_get(uint8_t *buf, uint8_t len) -{ -#if MYNEWT_VAL(TRNG) - size_t num; - - while (len) { - num = trng_read(g_trng, buf, len); - buf += num; - len -= num; - } -#else - uint8_t rnums; - os_sr_t sr; - - while (len != 0) { - OS_ENTER_CRITICAL(sr); - rnums = g_ble_ll_rnum_data.rnd_size; - if (rnums > len) { - rnums = len; - } - len -= rnums; - g_ble_ll_rnum_data.rnd_size -= rnums; - while (rnums) { - buf[0] = g_ble_ll_rnum_data.rnd_out[0]; - if (IS_RNUM_BUF_END(g_ble_ll_rnum_data.rnd_out)) { - g_ble_ll_rnum_data.rnd_out = g_ble_ll_rnum_buf; - } else { - ++g_ble_ll_rnum_data.rnd_out; - } - ++buf; - --rnums; - } - OS_EXIT_CRITICAL(sr); - - /* Make sure rng is started! */ - ble_hw_rng_start(); - - /* Wait till bytes are in buffer. */ - if (len) { - while ((g_ble_ll_rnum_data.rnd_size < len) && - (g_ble_ll_rnum_data.rnd_size < MYNEWT_VAL(BLE_LL_RNG_BUFSIZE))) { - /* Spin here */ - } - } - } -#endif - return BLE_ERR_SUCCESS; -} - -/* Simple wrapper to allow easy replacement of rand() */ -uint32_t -ble_ll_rand(void) -{ - static unsigned short xsubi[3]; - static bool init = true; - - if (init) { - init = false; - ble_ll_rand_data_get((uint8_t *)xsubi, sizeof(xsubi)); - } - - return (uint32_t) jrand48(xsubi); -} - -/** - * Called to obtain a "prand" as defined in core V4.2 Vol 6 Part B 1.3.2.2 - * - * @param prand - */ -void -ble_ll_rand_prand_get(uint8_t *prand) -{ - uint16_t sum; - - while (1) { - /* Get 24 bits of random data */ - ble_ll_rand_data_get(prand, 3); - - /* Prand cannot be all zeros or 1's. */ - sum = prand[0] + prand[1] + prand[2]; - if ((sum != 0) && (sum != (3 * 0xff))) { - break; - } - } - - /* Upper two bits must be 01 */ - prand[2] &= ~0xc0; - prand[2] |= 0x40; -} - -/** - * Start the generation of random numbers - * - * @return int - */ -int -ble_ll_rand_start(void) -{ -#if MYNEWT_VAL(TRNG) - /* Nothing to do - this is handled by driver */ -#else - /* Start the generation of numbers if we are not full */ - if (g_ble_ll_rnum_data.rnd_size < MYNEWT_VAL(BLE_LL_RNG_BUFSIZE)) { - ble_hw_rng_start(); - } -#endif - return 0; -} - -/** - * Initialize LL random number generation. Should be called only once on - * initialization. - * - * @return int - */ -int -ble_ll_rand_init(void) -{ -#if MYNEWT_VAL(TRNG) - g_trng = (struct trng_dev *) os_dev_open("trng", OS_TIMEOUT_NEVER, NULL); -#else - g_ble_ll_rnum_data.rnd_in = g_ble_ll_rnum_buf; - g_ble_ll_rnum_data.rnd_out = g_ble_ll_rnum_buf; - ble_hw_rng_init(ble_ll_rand_sample, 1); -#endif - return 0; -} - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_resolv.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_resolv.c deleted file mode 100644 index 231ecad23..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_resolv.c +++ /dev/null @@ -1,755 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_resolv.h" -#include "../include/controller/ble_ll_hci.h" -#include "../include/controller/ble_ll_scan.h" -#include "../include/controller/ble_ll_adv.h" -#include "../include/controller/ble_ll_sync.h" -#include "../include/controller/ble_hw.h" -#include "ble_ll_conn_priv.h" - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -struct ble_ll_resolv_data -{ - uint8_t addr_res_enabled; - uint8_t rl_size; - uint8_t rl_cnt_hw; - uint8_t rl_cnt; - ble_npl_time_t rpa_tmo; - struct ble_npl_callout rpa_timer; -}; -struct ble_ll_resolv_data g_ble_ll_resolv_data; - -__attribute__((aligned(4))) -struct ble_ll_resolv_entry g_ble_ll_resolv_list[MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE)]; - -static int -ble_ll_is_controller_busy(void) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - if (ble_ll_sync_enabled()) { - return 1; - } -#endif - - return ble_ll_adv_enabled() || ble_ll_scan_enabled() || - g_ble_ll_conn_create_sm; -} -/** - * Called to determine if a change is allowed to the resolving list at this - * time. We are not allowed to modify the resolving list if address translation - * is enabled and we are either scanning, advertising, or attempting to create - * a connection. - * - * @return int 0: not allowed. 1: allowed. - */ -static int -ble_ll_resolv_list_chg_allowed(void) -{ - int rc; - - if (g_ble_ll_resolv_data.addr_res_enabled && - ble_ll_is_controller_busy()) { - rc = 0; - } else { - rc = 1; - } - return rc; -} - - -/** - * Called to generate a resolvable private address in rl structure - * - * @param rl - * @param local - */ -static void -ble_ll_resolv_gen_priv_addr(struct ble_ll_resolv_entry *rl, int local) -{ - uint8_t *irk; - uint8_t *prand; - struct ble_encryption_block ecb; - uint8_t *addr; - - BLE_LL_ASSERT(rl != NULL); - - if (local) { - addr = rl->rl_local_rpa; - irk = rl->rl_local_irk; - } else { - addr = rl->rl_peer_rpa; - irk = rl->rl_peer_irk; - } - - /* Get prand */ - prand = addr + 3; - ble_ll_rand_prand_get(prand); - - /* Calculate hash, hash = ah(local IRK, prand) */ - memcpy(ecb.key, irk, 16); - memset(ecb.plain_text, 0, 13); - ecb.plain_text[13] = prand[2]; - ecb.plain_text[14] = prand[1]; - ecb.plain_text[15] = prand[0]; - - /* Calculate hash */ - ble_hw_encrypt_block(&ecb); - - addr[0] = ecb.cipher_text[15]; - addr[1] = ecb.cipher_text[14]; - addr[2] = ecb.cipher_text[13]; -} - -/** - * Called when the Resolvable private address timer expires. This timer - * is used to regenerate local and peers RPA's in the resolving list. - */ -static void -ble_ll_resolv_rpa_timer_cb(struct ble_npl_event *ev) -{ - int i; - os_sr_t sr; - struct ble_ll_resolv_entry *rl; - - rl = &g_ble_ll_resolv_list[0]; - for (i = 0; i < g_ble_ll_resolv_data.rl_cnt; ++i) { - if (rl->rl_has_local) { - OS_ENTER_CRITICAL(sr); - ble_ll_resolv_gen_priv_addr(rl, 1); - OS_EXIT_CRITICAL(sr); - } - - if (rl->rl_has_peer) { - OS_ENTER_CRITICAL(sr); - ble_ll_resolv_gen_priv_addr(rl, 0); - OS_EXIT_CRITICAL(sr); - } - ++rl; - } - - ble_npl_callout_reset(&g_ble_ll_resolv_data.rpa_timer, - g_ble_ll_resolv_data.rpa_tmo); - - ble_ll_adv_rpa_timeout(); -} - -/** - * Called to determine if the IRK is all zero. - * - * @param irk - * - * @return int 0: IRK is zero . 1: IRK has non-zero value. - */ -static int -ble_ll_resolv_irk_nonzero(const uint8_t *irk) -{ - int i; - int rc; - - rc = 0; - for (i = 0; i < 16; ++i) { - if (*irk != 0) { - rc = 1; - break; - } - ++irk; - } - - return rc; -} - -/** - * Clear the resolving list - * - * @return int 0: success, BLE error code otherwise - */ -int -ble_ll_resolv_list_clr(void) -{ - /* Check proper state */ - if (!ble_ll_resolv_list_chg_allowed()) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* Sets total on list to 0. Clears HW resolve list */ - g_ble_ll_resolv_data.rl_cnt_hw = 0; - g_ble_ll_resolv_data.rl_cnt = 0; - ble_hw_resolv_list_clear(); - - /* stop RPA timer when clearing RL */ - ble_npl_callout_stop(&g_ble_ll_resolv_data.rpa_timer); - - return BLE_ERR_SUCCESS; -} - -/** - * Read the size of the resolving list. This is the total number of resolving - * list entries allowed by the controller. - * - * @param rspbuf Pointer to response buffer - * - * @return int 0: success. - */ -int -ble_ll_resolv_list_read_size(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_resolv_list_size_rp *rsp = (void *) rspbuf; - - rsp->size = g_ble_ll_resolv_data.rl_size; - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -/** - * Used to determine if the device is on the resolving list. - * - * @param addr - * @param addr_type Public address (0) or random address (1) - * - * @return int 0: device is not on resolving list; otherwise the return value - * is the 'position' of the device in the resolving list (the index of the - * element plus 1). - */ -static int -ble_ll_is_on_resolv_list(const uint8_t *addr, uint8_t addr_type) -{ - int i; - struct ble_ll_resolv_entry *rl; - - rl = &g_ble_ll_resolv_list[0]; - for (i = 0; i < g_ble_ll_resolv_data.rl_cnt; ++i) { - if ((rl->rl_addr_type == addr_type) && - (!memcmp(&rl->rl_identity_addr[0], addr, BLE_DEV_ADDR_LEN))) { - return i + 1; - } - ++rl; - } - - return 0; -} - -/** - * Used to determine if the device is on the resolving list. - * - * @param addr - * @param addr_type Public address (0) or random address (1) - * - * @return Pointer to resolving list entry or NULL if no entry found. - */ -struct ble_ll_resolv_entry * -ble_ll_resolv_list_find(const uint8_t *addr, uint8_t addr_type) -{ - int i; - struct ble_ll_resolv_entry *rl; - - rl = &g_ble_ll_resolv_list[0]; - for (i = 0; i < g_ble_ll_resolv_data.rl_cnt; ++i) { - if ((rl->rl_addr_type == addr_type) && - (!memcmp(&rl->rl_identity_addr[0], addr, BLE_DEV_ADDR_LEN))) { - return rl; - } - ++rl; - } - - return NULL; -} - -/** - * Add a device to the resolving list - * - * @return int - */ -int -ble_ll_resolv_list_add(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_add_resolv_list_cp *cmd = (const void *) cmdbuf; - struct ble_ll_resolv_entry *rl; - int rc = BLE_ERR_SUCCESS; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Must be in proper state */ - if (!ble_ll_resolv_list_chg_allowed()) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* Check if we have any open entries */ - if (g_ble_ll_resolv_data.rl_cnt >= g_ble_ll_resolv_data.rl_size) { - return BLE_ERR_MEM_CAPACITY; - } - - /* spec is not clear on how to handle this but make sure host is aware - * that new keys are not used in that case - */ - if (ble_ll_is_on_resolv_list(cmd->peer_id_addr, cmd->peer_addr_type)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* we keep this sorted in a way that entries with peer_irk are first */ - if (ble_ll_resolv_irk_nonzero(cmd->peer_irk)) { - memmove(&g_ble_ll_resolv_list[g_ble_ll_resolv_data.rl_cnt_hw + 1], - &g_ble_ll_resolv_list[g_ble_ll_resolv_data.rl_cnt_hw], - (g_ble_ll_resolv_data.rl_cnt - g_ble_ll_resolv_data.rl_cnt_hw) * - sizeof(g_ble_ll_resolv_list[0])); - rl = &g_ble_ll_resolv_list[g_ble_ll_resolv_data.rl_cnt_hw]; - } else { - rl = &g_ble_ll_resolv_list[g_ble_ll_resolv_data.rl_cnt]; - } - - memset (rl, 0, sizeof(*rl)); - rl->rl_addr_type = cmd->peer_addr_type; - memcpy(rl->rl_identity_addr, cmd->peer_id_addr, BLE_DEV_ADDR_LEN); - - if (ble_ll_resolv_irk_nonzero(cmd->peer_irk)) { - swap_buf(rl->rl_peer_irk, cmd->peer_irk, 16); - rl->rl_has_peer = 1; - - /* generate peer RPA now, those will be updated by timer when - * resolution is enabled - */ - ble_ll_resolv_gen_priv_addr(rl, 0); - } - - if (ble_ll_resolv_irk_nonzero(cmd->local_irk)) { - swap_buf(rl->rl_local_irk, cmd->local_irk, 16); - rl->rl_has_local = 1; - - /* generate local RPA now, those will be updated by timer when - * resolution is enabled - */ - ble_ll_resolv_gen_priv_addr(rl, 1); - } - - /* By default use privacy network mode */ - rl->rl_priv_mode = BLE_HCI_PRIVACY_NETWORK; - - /* Add peers IRKs to HW resolving list. Should always succeed since we - * already checked if there is room for it. - */ - if (rl->rl_has_peer) { - rc = ble_hw_resolv_list_add(rl->rl_peer_irk); - BLE_LL_ASSERT(rc == BLE_ERR_SUCCESS); - g_ble_ll_resolv_data.rl_cnt_hw++; - } - - g_ble_ll_resolv_data.rl_cnt++; - - /* start RPA timer if this was first element added to RL */ - if (g_ble_ll_resolv_data.rl_cnt == 1) { - ble_npl_callout_reset(&g_ble_ll_resolv_data.rpa_timer, - g_ble_ll_resolv_data.rpa_tmo); - } - - return rc; -} - -/** - * Remove a device from the resolving list - * - * @param cmdbuf - * - * @return int 0: success, BLE error code otherwise - */ -int -ble_ll_resolv_list_rmv(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_rmv_resolve_list_cp *cmd = (const void *) cmdbuf; - int position; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Must be in proper state */ - if (!ble_ll_resolv_list_chg_allowed()) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* Remove from IRK records */ - position = ble_ll_is_on_resolv_list(cmd->peer_id_addr, cmd->peer_addr_type); - if (position) { - BLE_LL_ASSERT(position <= g_ble_ll_resolv_data.rl_cnt); - - memmove(&g_ble_ll_resolv_list[position - 1], - &g_ble_ll_resolv_list[position], - (g_ble_ll_resolv_data.rl_cnt - position) * - sizeof(g_ble_ll_resolv_list[0])); - g_ble_ll_resolv_data.rl_cnt--; - - /* Remove from HW list */ - if (position <= g_ble_ll_resolv_data.rl_cnt_hw) { - ble_hw_resolv_list_rmv(position - 1); - g_ble_ll_resolv_data.rl_cnt_hw--; - } - - /* stop RPA timer if list is empty */ - if (g_ble_ll_resolv_data.rl_cnt == 0) { - ble_npl_callout_stop(&g_ble_ll_resolv_data.rpa_timer); - } - - return BLE_ERR_SUCCESS; - } - - return BLE_ERR_UNK_CONN_ID; -} - -/** - * Called to enable or disable address resolution in the controller - * - * @param cmdbuf - * - * @return int - */ -int -ble_ll_resolv_enable_cmd(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_addr_res_en_cp *cmd = (const void *) cmdbuf; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (ble_ll_is_controller_busy()) { - return BLE_ERR_CMD_DISALLOWED; - - } - - if (cmd->enable > 1) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - g_ble_ll_resolv_data.addr_res_enabled = cmd->enable; - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_resolv_peer_addr_rd(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_rd_peer_recolv_addr_cp *cmd = (const void *) cmdbuf; - struct ble_hci_le_rd_peer_recolv_addr_rp *rsp = (void *) rspbuf; - struct ble_ll_resolv_entry *rl; - int rc; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - rl = ble_ll_resolv_list_find(cmd->peer_id_addr, cmd->peer_addr_type); - if (rl) { - memcpy(rsp->rpa, rl->rl_peer_rpa, BLE_DEV_ADDR_LEN); - rc = BLE_ERR_SUCCESS; - } else { - memset(rsp->rpa, 0, BLE_DEV_ADDR_LEN); - rc = BLE_ERR_UNK_CONN_ID; - } - - *rsplen = sizeof(*rsp); - return rc; -} - -int -ble_ll_resolv_local_addr_rd(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_rd_local_recolv_addr_cp *cmd = (const void *) cmdbuf; - struct ble_hci_le_rd_local_recolv_addr_rp *rsp = (void *) rspbuf; - struct ble_ll_resolv_entry *rl; - int rc; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - rl = ble_ll_resolv_list_find(cmd->peer_id_addr, cmd->peer_addr_type); - if (rl) { - memcpy(rsp->rpa, rl->rl_local_rpa, BLE_DEV_ADDR_LEN); - rc = BLE_ERR_SUCCESS; - } else { - memset(rsp->rpa, 0, BLE_DEV_ADDR_LEN); - rc = BLE_ERR_UNK_CONN_ID; - } - - *rsplen = sizeof(*rsp); - return rc; -} - -/** - * Set the resolvable private address timeout. - * - * @param cmdbuf - * - * @return int - */ -int -ble_ll_resolv_set_rpa_tmo(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_rpa_tmo_cp *cmd = (const void *)cmdbuf; - uint16_t tmo_secs; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - tmo_secs = le16toh(cmd->rpa_timeout); - if (!((tmo_secs > 0) && (tmo_secs <= 0xA1B8))) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - g_ble_ll_resolv_data.rpa_tmo = ble_npl_time_ms_to_ticks32(tmo_secs * 1000); - - /* restart timer if there is something on RL */ - if (g_ble_ll_resolv_data.rl_cnt) { - ble_npl_callout_reset(&g_ble_ll_resolv_data.rpa_timer, - g_ble_ll_resolv_data.rpa_tmo); - } - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_resolve_set_priv_mode(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_privacy_mode_cp *cmd = (const void *) cmdbuf; - struct ble_ll_resolv_entry *rl; - - if (ble_ll_is_controller_busy()) { - return BLE_ERR_CMD_DISALLOWED; - } - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - rl = ble_ll_resolv_list_find(cmd->peer_id_addr, cmd->peer_id_addr_type); - if (!rl) { - return BLE_ERR_UNK_CONN_ID; - } - - if (cmd->mode > BLE_HCI_PRIVACY_DEVICE) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - rl->rl_priv_mode = cmd->mode; - - return BLE_ERR_SUCCESS; -} - -/** - * Returns the Resolvable Private address timeout, in os ticks - * - * - * @return uint32_t - */ -uint32_t -ble_ll_resolv_get_rpa_tmo(void) -{ - return g_ble_ll_resolv_data.rpa_tmo; -} - -void -ble_ll_resolv_get_priv_addr(struct ble_ll_resolv_entry *rl, int local, - uint8_t *addr) -{ - os_sr_t sr; - - BLE_LL_ASSERT(rl != NULL); - BLE_LL_ASSERT(addr != NULL); - - OS_ENTER_CRITICAL(sr); - if (local) { - BLE_LL_ASSERT(rl->rl_has_local); - memcpy(addr, rl->rl_local_rpa, BLE_DEV_ADDR_LEN); - } else { - BLE_LL_ASSERT(rl->rl_has_peer); - memcpy(addr, rl->rl_peer_rpa, BLE_DEV_ADDR_LEN); - } - - OS_EXIT_CRITICAL(sr); -} - -void -ble_ll_resolv_set_peer_rpa(int index, uint8_t *rpa) -{ - os_sr_t sr; - struct ble_ll_resolv_entry *rl; - - OS_ENTER_CRITICAL(sr); - rl = &g_ble_ll_resolv_list[index]; - memcpy(rl->rl_peer_rpa, rpa, BLE_DEV_ADDR_LEN); - OS_EXIT_CRITICAL(sr); -} - -void -ble_ll_resolv_set_local_rpa(int index, uint8_t *rpa) -{ - os_sr_t sr; - struct ble_ll_resolv_entry *rl; - - OS_ENTER_CRITICAL(sr); - rl = &g_ble_ll_resolv_list[index]; - memcpy(rl->rl_local_rpa, rpa, BLE_DEV_ADDR_LEN); - OS_EXIT_CRITICAL(sr); -} - -/** - * Generate a resolvable private address. - * - * @param addr - * @param addr_type - * @param rpa - * - * @return int - */ -int -ble_ll_resolv_gen_rpa(uint8_t *addr, uint8_t addr_type, uint8_t *rpa, int local) -{ - struct ble_ll_resolv_entry *rl; - - rl = ble_ll_resolv_list_find(addr, addr_type); - if (rl) { - if ((local && rl->rl_has_local) || (!local && rl->rl_has_peer)) { - ble_ll_resolv_get_priv_addr(rl, local, rpa); - return 1; - } - } - - return 0; -} - -/** - * Resolve a Resolvable Private Address - * - * @param rpa - * @param index - * - * @return int - */ -int -ble_ll_resolv_rpa(const uint8_t *rpa, const uint8_t *irk) -{ - int rc; - const uint32_t *irk32; - uint32_t *key32; - uint32_t *pt32; - struct ble_encryption_block ecb; - - irk32 = (const uint32_t *)irk; - key32 = (uint32_t *)&ecb.key[0]; - - key32[0] = irk32[0]; - key32[1] = irk32[1]; - key32[2] = irk32[2]; - key32[3] = irk32[3]; - - pt32 = (uint32_t *)&ecb.plain_text[0]; - pt32[0] = 0; - pt32[1] = 0; - pt32[2] = 0; - pt32[3] = 0; - - ecb.plain_text[15] = rpa[3]; - ecb.plain_text[14] = rpa[4]; - ecb.plain_text[13] = rpa[5]; - - ble_hw_encrypt_block(&ecb); - if ((ecb.cipher_text[15] == rpa[0]) && (ecb.cipher_text[14] == rpa[1]) && - (ecb.cipher_text[13] == rpa[2])) { - rc = 1; - } else { - rc = 0; - } - - return rc; -} - -int -ble_ll_resolv_peer_rpa_any(const uint8_t *rpa) -{ - int i; - - for (i = 0; i < g_ble_ll_resolv_data.rl_cnt_hw; i++) { - if (ble_ll_resolv_rpa(rpa, g_ble_ll_resolv_list[i].rl_peer_irk)) { - return i; - } - } - - return -1; -} - -/** - * Returns whether or not address resolution is enabled. - * - * @return uint8_t - */ -uint8_t -ble_ll_resolv_enabled(void) -{ - return g_ble_ll_resolv_data.addr_res_enabled; -} - -/** - * Called to reset private address resolution module. - */ -void -ble_ll_resolv_list_reset(void) -{ - g_ble_ll_resolv_data.addr_res_enabled = 0; - ble_npl_callout_stop(&g_ble_ll_resolv_data.rpa_timer); - ble_ll_resolv_list_clr(); - ble_ll_resolv_init(); -} - -void -ble_ll_resolv_init(void) -{ - uint8_t hw_size; - - /* Default is 15 minutes */ - g_ble_ll_resolv_data.rpa_tmo = ble_npl_time_ms_to_ticks32(15 * 60 * 1000); - - hw_size = ble_hw_resolv_list_size(); - if (hw_size > MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE)) { - hw_size = MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE); - } - g_ble_ll_resolv_data.rl_size = hw_size; - - ble_npl_callout_init(&g_ble_ll_resolv_data.rpa_timer, - &g_ble_ll_data.ll_evq, - ble_ll_resolv_rpa_timer_cb, - NULL); -} - -#endif /* if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) */ -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_rfmgmt.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_rfmgmt.c deleted file mode 100644 index 40d79be01..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_rfmgmt.c +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os_cputime.h" -#include "../include/controller/ble_phy.h" -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_sched.h" -#include "../include/controller/ble_ll_rfmgmt.h" - -#if MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME) > 0 - -enum ble_ll_rfmgmt_state { - RFMGMT_STATE_OFF = 0, - RFMGMT_STATE_ENABLING = 1, - RFMGMT_STATE_ENABLED = 2, -}; - -struct ble_ll_rfmgmt_data { - enum ble_ll_rfmgmt_state state; - uint16_t ticks_to_enabled; - - struct hal_timer timer; - bool timer_scheduled; - uint32_t timer_scheduled_at; - - bool enable_scan; - bool enable_sched; - uint32_t enable_scan_at; - uint32_t enable_sched_at; - - uint32_t enabled_at; - - struct ble_npl_event release_ev; -}; - -static struct ble_ll_rfmgmt_data g_ble_ll_rfmgmt_data; - -static void -ble_ll_rfmgmt_enable(void) -{ - OS_ASSERT_CRITICAL(); - - if (g_ble_ll_rfmgmt_data.state == RFMGMT_STATE_OFF) { - g_ble_ll_rfmgmt_data.state = RFMGMT_STATE_ENABLING; - g_ble_ll_rfmgmt_data.enabled_at = os_cputime_get32(); - ble_phy_rfclk_enable(); - } -} - -static void -ble_ll_rfmgmt_disable(void) -{ - OS_ASSERT_CRITICAL(); - - if (g_ble_ll_rfmgmt_data.state != RFMGMT_STATE_OFF) { - ble_phy_rfclk_disable(); - g_ble_ll_rfmgmt_data.state = RFMGMT_STATE_OFF; - } -} - -static void -ble_ll_rfmgmt_timer_reschedule(void) -{ - struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data; - uint32_t enable_at; - - /* Figure out when we need to enable RF */ - if (rfmgmt->enable_scan && rfmgmt->enable_sched) { - if (CPUTIME_LT(rfmgmt->enable_scan_at, rfmgmt->enable_sched_at)) { - enable_at = rfmgmt->enable_scan_at; - } else { - enable_at = rfmgmt->enable_sched_at; - } - } else if (rfmgmt->enable_scan) { - enable_at = rfmgmt->enable_scan_at; - } else if (rfmgmt->enable_sched) { - enable_at = rfmgmt->enable_sched_at; - } else { - rfmgmt->timer_scheduled = false; - os_cputime_timer_stop(&rfmgmt->timer); - return; - } - - if (rfmgmt->timer_scheduled) { - /* - * If there is timer already scheduled at the same time we do not need - * to do anything. Otherwise we need to stop timer and schedule it again - * regardless if it's earlier or later to make sure it fires at the time - * something expects it. - */ - - if (rfmgmt->timer_scheduled_at == enable_at) { - return; - } - - rfmgmt->timer_scheduled = false; - os_cputime_timer_stop(&rfmgmt->timer); - } - - /* - * In case timer was requested to be enabled before current time, just make - * sure it's enabled and assume caller can deal with this. This will happen - * if something is scheduled "now" since "enable_at" is in the past, but in - * such case it's absolutely harmless since we already have clock enabled - * and this will do nothing. - */ - if (CPUTIME_LEQ(enable_at, os_cputime_get32())) { - ble_ll_rfmgmt_enable(); - return; - } - - rfmgmt->timer_scheduled = true; - rfmgmt->timer_scheduled_at = enable_at; - os_cputime_timer_start(&rfmgmt->timer, enable_at); -} - -static void -ble_ll_rfmgmt_timer_exp(void *arg) -{ - g_ble_ll_rfmgmt_data.timer_scheduled = false; - ble_ll_rfmgmt_enable(); -} - -static void -ble_ll_rfmgmt_release_ev(struct ble_npl_event *ev) -{ - struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data; - uint32_t now; - bool can_disable; - uint8_t lls; - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - - now = os_cputime_get32(); - - can_disable = true; - lls = ble_ll_state_get(); - - if (rfmgmt->enable_scan && CPUTIME_GEQ(now, rfmgmt->enable_scan_at)) { - /* Blocked by scan */ - can_disable = false; - } else if (rfmgmt->enable_sched && CPUTIME_GEQ(now, rfmgmt->enable_sched_at)) { - /* Blocked by scheduler item */ - can_disable = false; - } else if (lls != BLE_LL_STATE_STANDBY) { - /* Blocked by LL state */ - can_disable = false; - } - - if (can_disable) { - ble_ll_rfmgmt_disable(); - } - - OS_EXIT_CRITICAL(sr); -} - -static uint32_t -ble_ll_rfmgmt_ticks_to_enabled(void) -{ - struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data; - uint32_t rem_ticks; - uint32_t now; - - switch (rfmgmt->state) { - case RFMGMT_STATE_OFF: - rem_ticks = rfmgmt->ticks_to_enabled; - break; - case RFMGMT_STATE_ENABLING: - now = os_cputime_get32(); - if (CPUTIME_LT(now, rfmgmt->enabled_at + rfmgmt->ticks_to_enabled)) { - rem_ticks = rfmgmt->enabled_at + rfmgmt->ticks_to_enabled - now; - break; - } - rfmgmt->state = RFMGMT_STATE_ENABLED; - /* Else falls through. */ - /* no break */ - case RFMGMT_STATE_ENABLED: - rem_ticks = 0; - break; - default: - BLE_LL_ASSERT(0); - rem_ticks = 0; - break; - } - - return rem_ticks; -} - -void -ble_ll_rfmgmt_init(void) -{ - struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data; - - rfmgmt->state = RFMGMT_STATE_OFF; - - rfmgmt->ticks_to_enabled = - ble_ll_usecs_to_ticks_round_up(MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME)); - - rfmgmt->timer_scheduled = false; - os_cputime_timer_init(&rfmgmt->timer, ble_ll_rfmgmt_timer_exp, NULL); - - ble_npl_event_init(&rfmgmt->release_ev, ble_ll_rfmgmt_release_ev, NULL); -} - -void -ble_ll_rfmgmt_reset(void) -{ - struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data; - - rfmgmt->timer_scheduled = false; - rfmgmt->timer_scheduled_at = 0; - os_cputime_timer_stop(&rfmgmt->timer); - - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev); - - ble_ll_rfmgmt_disable(); - - rfmgmt->enable_scan = false; - rfmgmt->enable_scan_at = 0; - rfmgmt->enable_sched = false; - rfmgmt->enable_sched_at = 0; - - rfmgmt->enabled_at = 0; -} - -void -ble_ll_rfmgmt_scan_changed(bool enabled, uint32_t next_window) -{ - struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data; - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - - rfmgmt->enable_scan = enabled; - rfmgmt->enable_scan_at = next_window - rfmgmt->ticks_to_enabled; - - ble_ll_rfmgmt_timer_reschedule(); - - OS_EXIT_CRITICAL(sr); -} - -void -ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *first) -{ - struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data; - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - - rfmgmt->enable_sched = (first != NULL); - if (first) { - rfmgmt->enable_sched_at = first->start_time - rfmgmt->ticks_to_enabled; - } - - ble_ll_rfmgmt_timer_reschedule(); - - OS_EXIT_CRITICAL(sr); -} - -void -ble_ll_rfmgmt_release(void) -{ - struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data; - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev); - - if (g_ble_ll_rfmgmt_data.state != RFMGMT_STATE_OFF) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev); - } - - OS_EXIT_CRITICAL(sr); -} - -uint32_t -ble_ll_rfmgmt_enable_now(void) -{ - struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data; - uint32_t enabled_at; - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - - ble_ll_rfmgmt_enable(); - - if (rfmgmt->state == RFMGMT_STATE_ENABLED) { - enabled_at = os_cputime_get32(); - } else { - enabled_at = rfmgmt->enabled_at + rfmgmt->ticks_to_enabled + 1; - } - - OS_EXIT_CRITICAL(sr); - - return enabled_at; -} - -bool -ble_ll_rfmgmt_is_enabled(void) -{ - bool ret; - - OS_ASSERT_CRITICAL(); - - ret = ble_ll_rfmgmt_ticks_to_enabled() == 0; - - return ret; -} - -#else - -void -ble_ll_rfmgmt_init(void) -{ - static bool enabled = false; - - if (!enabled) { - ble_phy_rfclk_enable(); - } - - enabled = true; -} - -#endif -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_scan.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_scan.c deleted file mode 100644 index feeb9360b..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_scan.c +++ /dev/null @@ -1,3987 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef ESP_PLATFORM - -#include -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os.h" -#include "nimble/porting/nimble/include/os/os_cputime.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "nimble/nimble/include/nimble/ble_hci_trans.h" -#include "../include/controller/ble_phy.h" -#include "../include/controller/ble_hw.h" -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_sched.h" -#include "../include/controller/ble_ll_adv.h" -#include "../include/controller/ble_ll_scan.h" -#include "../include/controller/ble_ll_hci.h" -#include "../include/controller/ble_ll_whitelist.h" -#include "../include/controller/ble_ll_resolv.h" -#include "../include/controller/ble_ll_rfmgmt.h" -#include "../include/controller/ble_ll_trace.h" -#include "../include/controller/ble_ll_sync.h" -#include "ble_ll_conn_priv.h" - -/* - * XXX: - * 1) I think I can guarantee that we dont process things out of order if - * I send an event when a scan request is sent. The scan_rsp_pending flag - * code might be made simpler. - * - * 2) Interleave sending scan requests to different advertisers? I guess I need - * a list of advertisers to which I sent a scan request and have yet to - * receive a scan response from? Implement this. - */ - -/* Dont allow more than 255 of these entries */ -#if MYNEWT_VAL(BLE_LL_NUM_SCAN_RSP_ADVS) > 255 - #error "Cannot have more than 255 scan response entries!" -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) -#define SCAN_VALID_PHY_MASK (BLE_HCI_LE_PHY_1M_PREF_MASK | BLE_HCI_LE_PHY_CODED_PREF_MASK) -#else -#define SCAN_VALID_PHY_MASK (BLE_HCI_LE_PHY_1M_PREF_MASK) -#endif - -/* The scanning parameters set by host */ -static struct ble_ll_scan_params g_ble_ll_scan_params[BLE_LL_SCAN_PHY_NUMBER]; - -/* The scanning state machine global object */ -static struct ble_ll_scan_sm g_ble_ll_scan_sm; - -struct ble_ll_ext_adv_hdr -{ - uint8_t mode; - uint8_t hdr_len; - uint8_t hdr[0]; -}; - -struct ble_ll_scan_addr_data { - bool adva_present; - uint8_t adva_type; - uint8_t *adva; - uint8_t targeta_type; - uint8_t *targeta; - uint8_t adv_addr_type; - uint8_t *adv_addr; - struct ble_ll_resolv_entry *rl; -}; - -/* - * Structure used to store advertisers. This is used to limit sending scan - * requests to the same advertiser and also to filter duplicate events sent - * to the host. - */ -struct ble_ll_scan_advertisers -{ - uint16_t sc_adv_flags; - uint16_t adi; - struct ble_dev_addr adv_addr; -}; - -#define BLE_LL_SC_ADV_F_RANDOM_ADDR (0x01) -#define BLE_LL_SC_ADV_F_SCAN_RSP_RXD (0x02) -#define BLE_LL_SC_ADV_F_DIRECT_RPT_SENT (0x04) -#define BLE_LL_SC_ADV_F_ADV_RPT_SENT (0x08) -#define BLE_LL_SC_ADV_F_SCAN_RSP_SENT (0x10) - -/* Contains list of advertisers that we have heard scan responses from */ -static uint8_t g_ble_ll_scan_num_rsp_advs; -struct ble_ll_scan_advertisers -g_ble_ll_scan_rsp_advs[MYNEWT_VAL(BLE_LL_NUM_SCAN_RSP_ADVS)]; - -/* Duplicates filtering data */ -#define BLE_LL_SCAN_ENTRY_TYPE_LEGACY(addr_type) \ - ((addr_type) & 1) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#define BLE_LL_SCAN_ENTRY_TYPE_EXT(addr_type, has_aux, is_anon, adi) \ - (((adi >> 8) & 0xF0) | (1 << 3) | (is_anon << 2) | (has_aux << 1) | ((addr_type) & 1)) -#endif - -#define BLE_LL_SCAN_DUP_F_ADV_REPORT_SENT (0x01) -#define BLE_LL_SCAN_DUP_F_DIR_ADV_REPORT_SENT (0x02) -#define BLE_LL_SCAN_DUP_F_SCAN_RSP_SENT (0x04) - -struct ble_ll_scan_dup_entry { - uint8_t type; /* entry type, see BLE_LL_SCAN_ENTRY_TYPE_* */ - uint8_t addr[6]; - uint8_t flags; /* use BLE_LL_SCAN_DUP_F_xxx */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - uint16_t adi; -#endif - TAILQ_ENTRY(ble_ll_scan_dup_entry) link; -}; - -static os_membuf_t g_scan_dup_mem[ OS_MEMPOOL_SIZE( - MYNEWT_VAL(BLE_LL_NUM_SCAN_DUP_ADVS), - sizeof(struct ble_ll_scan_dup_entry)) ]; -static struct os_mempool g_scan_dup_pool; -static TAILQ_HEAD(ble_ll_scan_dup_list, ble_ll_scan_dup_entry) g_scan_dup_list; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#if MYNEWT_VAL(BLE_LL_EXT_ADV_AUX_PTR_CNT) != 0 -static os_membuf_t ext_scan_aux_mem[ OS_MEMPOOL_SIZE( - MYNEWT_VAL(BLE_LL_EXT_ADV_AUX_PTR_CNT), - sizeof (struct ble_ll_aux_data)) -]; -#else -#define ext_scan_aux_mem NULL -#endif - -static struct os_mempool ext_scan_aux_pool; - -static int ble_ll_scan_start(struct ble_ll_scan_sm *scansm, - struct ble_ll_sched_item *sch); - -static void -ble_ll_aux_scan_drop_event_cb(struct ble_npl_event *ev) -{ - struct ble_ll_aux_data *aux_data = ble_npl_event_get_arg(ev); - - ble_ll_scan_end_adv_evt(aux_data); - ble_ll_scan_aux_data_unref(aux_data); -} - -static void -ble_ll_aux_scan_drop(struct ble_ll_aux_data *aux_data) -{ - BLE_LL_ASSERT(aux_data); - - STATS_INC(ble_ll_stats, aux_scan_drop); - - ble_npl_event_init(&aux_data->ev, ble_ll_aux_scan_drop_event_cb, aux_data); - ble_ll_event_send(&aux_data->ev); -} - -static int -ble_ll_aux_scan_cb(struct ble_ll_sched_item *sch) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - uint8_t lls = ble_ll_state_get(); - uint32_t wfr_usec; - - STATS_INC(ble_ll_stats, aux_sched_cb); - - /* Drop the scheduled item if scan was disable or there is aux or scan - * response pending - */ - if (!scansm->scan_enabled || scansm->cur_aux_data || - scansm->scan_rsp_pending) { - ble_ll_aux_scan_drop(sch->cb_arg); - sch->cb_arg = NULL; - goto done; - } - - /* Check if there is no aux connect sent. If so drop the sched item */ - if (lls == BLE_LL_STATE_INITIATING && ble_ll_conn_init_pending_aux_conn_rsp()) { - ble_ll_aux_scan_drop(sch->cb_arg); - sch->cb_arg = NULL; - goto done; - } - - /* This function is called only when scanner is running. This can happen - * in 3 states: - * BLE_LL_STATE_SCANNING - * BLE_LL_STATE_INITIATING - * BLE_LL_STATE_STANDBY - */ - if (lls != BLE_LL_STATE_STANDBY) { - ble_phy_disable(); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - } - - /* When doing RX for AUX pkt, cur_aux_data keeps valid aux data */ - scansm->cur_aux_data = sch->cb_arg; - sch->cb_arg = NULL; - BLE_LL_ASSERT(scansm->cur_aux_data != NULL); - scansm->cur_aux_data->scanning = 1; - - if (ble_ll_scan_start(scansm, sch)) { - ble_ll_scan_interrupted(scansm); - goto done; - } - - STATS_INC(ble_ll_stats, aux_fired_for_read); - - wfr_usec = scansm->cur_aux_data->offset_units ? 300 : 30; - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_usec); - -done: - - return BLE_LL_SCHED_STATE_DONE; -} - -static int -ble_ll_scan_ext_adv_init(struct ble_ll_aux_data **aux_data) -{ - struct ble_ll_aux_data *e; - - e = os_memblock_get(&ext_scan_aux_pool); - if (!e) { - return -1; - } - - memset(e, 0, sizeof(*e)); - e->sch.sched_cb = ble_ll_aux_scan_cb; - e->sch.sched_type = BLE_LL_SCHED_TYPE_AUX_SCAN; - e->ref_cnt = 1; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - e->rpa_index = -1; -#endif - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_REF, (uint32_t)e, e->ref_cnt); - - *aux_data = e; - STATS_INC(ble_ll_stats, aux_allocated); - - return 0; -} -#endif - -static inline uint32_t -ble_ll_scan_time_hci_to_ticks(uint16_t value) -{ - return os_cputime_usecs_to_ticks(value * BLE_HCI_SCAN_ITVL); -} - -/* See Vol 6 Part B Section 4.4.3.2. Active scanning backoff */ -static void -ble_ll_scan_req_backoff(struct ble_ll_scan_sm *scansm, int success) -{ - BLE_LL_ASSERT(scansm->backoff_count == 0); - BLE_LL_ASSERT(scansm->scan_rsp_pending == 0); - - if (success) { - scansm->scan_rsp_cons_fails = 0; - ++scansm->scan_rsp_cons_ok; - if (scansm->scan_rsp_cons_ok == 2) { - scansm->scan_rsp_cons_ok = 0; - if (scansm->upper_limit > 1) { - scansm->upper_limit >>= 1; - } - } - STATS_INC(ble_ll_stats, scan_req_txg); - } else { - scansm->scan_rsp_cons_ok = 0; - ++scansm->scan_rsp_cons_fails; - if (scansm->scan_rsp_cons_fails == 2) { - scansm->scan_rsp_cons_fails = 0; - if (scansm->upper_limit < 256) { - scansm->upper_limit <<= 1; - } - } - STATS_INC(ble_ll_stats, scan_req_txf); - } - - scansm->backoff_count = ble_ll_rand() & (scansm->upper_limit - 1); - ++scansm->backoff_count; - BLE_LL_ASSERT(scansm->backoff_count <= 256); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -static void -ble_ll_scan_refresh_nrpa(struct ble_ll_scan_sm *scansm) -{ - ble_npl_time_t now; - - now = ble_npl_time_get(); - if (CPUTIME_GEQ(now, scansm->scan_nrpa_timer)) { - /* Generate new NRPA */ - ble_ll_rand_data_get(scansm->scan_nrpa, BLE_DEV_ADDR_LEN); - scansm->scan_nrpa[5] &= ~0xc0; - - /* We'll use the same timeout as for RPA rotation */ - scansm->scan_nrpa_timer = now + ble_ll_resolv_get_rpa_tmo(); - } -} -#endif - -static void -ble_ll_scan_req_pdu_prepare(struct ble_ll_scan_sm *scansm, - const uint8_t *adv_addr, uint8_t adv_addr_type, - struct ble_ll_resolv_entry *rl) -{ - uint8_t hdr_byte; - struct ble_ll_scan_pdu_data *pdu_data; - uint8_t *scana; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - uint8_t rpa[BLE_DEV_ADDR_LEN]; -#endif - - pdu_data = &scansm->pdu_data; - - /* Construct first PDU header byte */ - hdr_byte = BLE_ADV_PDU_TYPE_SCAN_REQ; - if (adv_addr_type) { - hdr_byte |= BLE_ADV_PDU_HDR_RXADD_RAND; - } - - /* Determine ScanA */ - if (scansm->own_addr_type & 0x01) { - hdr_byte |= BLE_ADV_PDU_HDR_TXADD_RAND; - scana = g_random_addr; - } else { - scana = g_dev_addr; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (scansm->own_addr_type & 0x02) { - /* - * If device is on RL and we have local IRK, we use RPA generated using - * that IRK as ScanA. Otherwise we use NRPA as ScanA to prevent our - * device from being tracked when doing an active scan (Core 5.1, Vol 6, - * Part B, section 6.3) - */ - if (rl && rl->rl_has_local) { - ble_ll_resolv_get_priv_addr(rl, 1, rpa); - scana = rpa; - } else { - ble_ll_scan_refresh_nrpa(scansm); - scana = scansm->scan_nrpa; - } - - hdr_byte |= BLE_ADV_PDU_HDR_TXADD_RAND; - } -#endif - - /* Save scan request data */ - pdu_data->hdr_byte = hdr_byte; - memcpy(pdu_data->scana, scana, BLE_DEV_ADDR_LEN); - memcpy(pdu_data->adva, adv_addr, BLE_DEV_ADDR_LEN); -} - -static uint8_t -ble_ll_scan_req_tx_pdu_cb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) -{ - struct ble_ll_scan_sm *scansm = pducb_arg; - struct ble_ll_scan_pdu_data *pdu_data = &scansm->pdu_data; - - memcpy(dptr, pdu_data->scana, BLE_DEV_ADDR_LEN); - memcpy(dptr + BLE_DEV_ADDR_LEN, pdu_data->adva, BLE_DEV_ADDR_LEN); - - *hdr_byte = pdu_data->hdr_byte; - - return BLE_DEV_ADDR_LEN * 2; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -/* if copy_from is provided new report is initialized with that instead of - * defaults - */ -static struct ble_hci_ev * -ble_ll_scan_get_ext_adv_report(struct ext_adv_report *copy_from) -{ - struct ble_hci_ev_le_subev_ext_adv_rpt *ev; - struct ext_adv_report *report; - struct ble_hci_ev *hci_ev; - - hci_ev = ( void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - if (!hci_ev) { - return NULL; - } - - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev) + sizeof(*report); - ev = (void *) hci_ev->data; - - memset(ev, 0, sizeof(*ev)); - ev->subev_code = BLE_HCI_LE_SUBEV_EXT_ADV_RPT; - /* We support only one report per event now */ - ev->num_reports = 1; - - report = ev->reports; - - if (copy_from) { - memcpy(report, copy_from, sizeof(*report)); - report->data_len = 0; - } else { - memset(report, 0, sizeof(*report)); - - report->pri_phy = BLE_PHY_1M; - /* Init SID with "Not available" which is 0xFF */ - report->sid = 0xFF; - /* Init TX Power with "Not available" which is 127 */ - report->tx_power = 127; - /* Init RSSI with "Not available" which is 127 */ - report->rssi = 127; - /* Init address type with "anonymous" which is 0xFF */ - report->addr_type = 0xFF; - } - - return hci_ev; -} - -static void -ble_ll_scan_send_truncated(struct ble_ll_aux_data *aux_data) -{ - struct ble_hci_ev_le_subev_ext_adv_rpt *ev; - struct ext_adv_report *report; - struct ble_hci_ev *hci_ev; - - if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { - return; - } - - BLE_LL_ASSERT(aux_data); - - /* No need to send if we did not send any report or sent truncated already */ - if (!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY) || - (aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)) { - return; - } - - BLE_LL_ASSERT(aux_data->evt); - hci_ev = aux_data->evt; - aux_data->evt = NULL; - - hci_ev->length = sizeof(*ev) + sizeof(*report); - - ev = (void *) hci_ev->data; - report = ev->reports; - - report->data_len = 0; - - report->evt_type = aux_data->evt_type; - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; - - if (aux_data->flags & BLE_LL_AUX_HAS_ADVA) { - memcpy(report->addr, aux_data->adva, 6); - report->addr_type = aux_data->adva_type; - } - - if (aux_data->flags & BLE_LL_AUX_HAS_TARGETA) { - memcpy(report->dir_addr, aux_data->targeta, 6); - report->dir_addr_type = aux_data->targeta_type; - } - - report->sid = aux_data->adi >> 12; - ble_ll_hci_event_send(hci_ev); - - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_ANY; - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED; -} - -static int -ble_ll_scan_get_adi(struct ble_ll_aux_data *aux_data, uint16_t *adi) -{ - if (!aux_data || !(aux_data->flags & BLE_LL_AUX_HAS_ADI)) { - return -1; - } - - *adi = aux_data->adi; - - return 0; -} - -void -ble_ll_scan_end_adv_evt(struct ble_ll_aux_data *aux_data) -{ - /* Make sure we send report with 'truncated' data state if needed */ - ble_ll_scan_send_truncated(aux_data); -} -#endif - -static void -ble_ll_scan_clean_cur_aux_data(void) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - - /* If scanner was reading aux ptr, we need to clean it up */ - if (scansm->cur_aux_data) { - ble_ll_scan_end_adv_evt(scansm->cur_aux_data); - ble_ll_scan_aux_data_unref(scansm->cur_aux_data); - scansm->cur_aux_data = NULL; - } -#endif -} - -void -ble_ll_scan_halt(void) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - - ble_ll_scan_clean_cur_aux_data(); - - /* Update backoff if we failed to receive scan response */ - if (scansm->scan_rsp_pending) { - scansm->scan_rsp_pending = 0; - ble_ll_scan_req_backoff(scansm, 0); - } -} - -/** - * Checks to see if we have received a scan response from this advertiser. - * - * @param adv_addr Address of advertiser - * @param txadd TxAdd bit (0: public; random otherwise) - * - * @return int 0: have not received a scan response; 1 otherwise. - */ -static int -ble_ll_scan_have_rxd_scan_rsp(uint8_t *addr, uint8_t txadd, - uint8_t ext_adv, uint16_t adi) -{ - uint8_t num_advs; - struct ble_ll_scan_advertisers *adv; - - /* Do we have an address match? Must match address type */ - adv = &g_ble_ll_scan_rsp_advs[0]; - num_advs = g_ble_ll_scan_num_rsp_advs; - while (num_advs) { - if (!memcmp(&adv->adv_addr, addr, BLE_DEV_ADDR_LEN)) { - /* Address type must match */ - if (txadd) { - if (adv->sc_adv_flags & BLE_LL_SC_ADV_F_RANDOM_ADDR) { - if (ext_adv) { - if (adi == adv->adi) { - return 1; - } - goto next; - } - return 1; - } - } else { - if ((adv->sc_adv_flags & BLE_LL_SC_ADV_F_RANDOM_ADDR) == 0) { - if (ext_adv) { - if (adi == adv->adi) { - return 1; - } - goto next; - } - return 1; - } - } - } -next: - ++adv; - --num_advs; - } - - return 0; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_scan_add_scan_rsp_adv(uint8_t *addr, uint8_t txadd, - uint8_t ext_adv, uint16_t adi) -{ - uint8_t num_advs; - struct ble_ll_scan_advertisers *adv; - - /* XXX: for now, if we dont have room, just leave */ - num_advs = g_ble_ll_scan_num_rsp_advs; - if (num_advs == MYNEWT_VAL(BLE_LL_NUM_SCAN_RSP_ADVS)) { - return; - } - - /* Check if address is already on the list */ - if (ble_ll_scan_have_rxd_scan_rsp(addr, txadd, ext_adv, adi)) { - return; - } - - /* Add the advertiser to the array */ - adv = &g_ble_ll_scan_rsp_advs[num_advs]; - memcpy(&adv->adv_addr, addr, BLE_DEV_ADDR_LEN); - adv->sc_adv_flags = BLE_LL_SC_ADV_F_SCAN_RSP_RXD; - if (txadd) { - adv->sc_adv_flags |= BLE_LL_SC_ADV_F_RANDOM_ADDR; - } - adv->adi = adi; - ++g_ble_ll_scan_num_rsp_advs; - - return; -} - -static int -ble_ll_hci_send_legacy_ext_adv_report(uint8_t evtype, - const uint8_t *addr, uint8_t addr_type, - int8_t rssi, - uint8_t adv_data_len, - struct os_mbuf *adv_data, - const uint8_t *inita, uint8_t inita_type) -{ - struct ble_hci_ev_le_subev_ext_adv_rpt *ev; - struct ext_adv_report *report; - struct ble_hci_ev *hci_ev; - - if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { - return -1; - } - - /* Drop packet if adv data doesn't fit */ - if ((sizeof(*ev) + sizeof(ev->reports[0]) + adv_data_len) > BLE_HCI_MAX_DATA_LEN) { - STATS_INC(ble_ll_stats, adv_evt_dropped); - return -1; - } - - hci_ev = ble_ll_scan_get_ext_adv_report(NULL); - if (!hci_ev) { - return -1; - } - - ev = (void *) hci_ev->data; - report = ev->reports; - - switch (evtype) { - case BLE_HCI_ADV_RPT_EVTYPE_ADV_IND: - report->evt_type = BLE_HCI_LEGACY_ADV_EVTYPE_ADV_IND; - break; - case BLE_HCI_ADV_RPT_EVTYPE_DIR_IND: - report->evt_type = BLE_HCI_LEGACY_ADV_EVTYPE_ADV_DIRECT_IND; - break; - case BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND: - report->evt_type = BLE_HCI_LEGACY_ADV_EVTYPE_ADV_NONCON_IND; - break; - case BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP: - report->evt_type = BLE_HCI_LEGACY_ADV_EVTYPE_SCAN_RSP_ADV_IND; - break; - case BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND: - report->evt_type = BLE_HCI_LEGACY_ADV_EVTYPE_ADV_SCAN_IND; - break; - default: - BLE_LL_ASSERT(0); - ble_hci_trans_buf_free((uint8_t *) hci_ev); - return -1; - } - - report->addr_type = addr_type; - memcpy(report->addr, addr, BLE_DEV_ADDR_LEN); - report->pri_phy = BLE_PHY_1M; - report->sid = 0xFF; - report->tx_power = 127; - report->rssi = rssi; - - if (inita) { - report->dir_addr_type = inita_type; - memcpy(report->dir_addr, inita, BLE_DEV_ADDR_LEN); - } - - if (adv_data_len) { - hci_ev->length += adv_data_len; - report->data_len = adv_data_len; - os_mbuf_copydata(adv_data, 0, adv_data_len, report->data); - } - - return ble_ll_hci_event_send(hci_ev); -} -#endif - -static int -ble_ll_hci_send_adv_report(uint8_t evtype, - const uint8_t *addr, uint8_t addr_type, int8_t rssi, - uint8_t adv_data_len, struct os_mbuf *adv_data) -{ - struct ble_hci_ev_le_subev_adv_rpt *ev; - struct ble_hci_ev *hci_ev; - int8_t *ev_rssi; - - if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_ADV_RPT)) { - return -1; - } - - /* Drop packet if adv data doesn't fit, note extra 1 is for RSSI */ - if ((sizeof(*ev) + sizeof(ev->reports[0]) + adv_data_len + 1) > BLE_HCI_MAX_DATA_LEN) { - STATS_INC(ble_ll_stats, adv_evt_dropped); - return -1; - } - - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - if (!hci_ev) { - return -1; - } - - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev) + sizeof(ev->reports[0]) + adv_data_len + 1; - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_ADV_RPT; - ev->num_reports = 1; - - ev->reports[0].type = evtype; - ev->reports[0].addr_type = addr_type; - memcpy(ev->reports[0].addr, addr, BLE_DEV_ADDR_LEN); - ev->reports[0].data_len = adv_data_len; - os_mbuf_copydata(adv_data, 0, adv_data_len, ev->reports[0].data); - - /* RSSI is after adv data... */ - ev_rssi = (int8_t *) (hci_ev->data + sizeof(*ev) + sizeof(ev->reports[0]) + adv_data_len); - *ev_rssi = rssi; - - return ble_ll_hci_event_send(hci_ev); -} - -static int -ble_ll_hci_send_dir_adv_report(const uint8_t *addr, uint8_t addr_type, - const uint8_t *inita, uint8_t inita_type, - int8_t rssi) -{ - struct ble_hci_ev_le_subev_direct_adv_rpt *ev; - struct ble_hci_ev *hci_ev; - - if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT)) { - return -1; - } - - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - if (!hci_ev) { - return -1; - } - - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev) + sizeof(*(ev->reports)); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT; - ev->num_reports = 1; - - ev->reports[0].type = BLE_HCI_ADV_RPT_EVTYPE_DIR_IND; - ev->reports[0].addr_type = addr_type; - memcpy(ev->reports[0].addr, addr, BLE_DEV_ADDR_LEN); - ev->reports[0].dir_addr_type = inita_type; - memcpy(ev->reports[0].dir_addr, inita, BLE_DEV_ADDR_LEN); - ev->reports[0].rssi = rssi; - - return ble_ll_hci_event_send(hci_ev); -} - -static int -ble_ll_scan_dup_update_legacy(uint8_t addr_type, const uint8_t *addr, - uint8_t subev, uint8_t evtype) -{ - struct ble_ll_scan_dup_entry *e; - uint8_t type; - - type = BLE_LL_SCAN_ENTRY_TYPE_LEGACY(addr_type); - - /* - * We assume ble_ll_scan_dup_check() was called before which either matched - * some entry or allocated new one and placed in on the top of queue. - */ - - e = TAILQ_FIRST(&g_scan_dup_list); - BLE_LL_ASSERT(e && e->type == type && !memcmp(e->addr, addr, 6)); - - if (subev == BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT) { - e->flags |= BLE_LL_SCAN_DUP_F_DIR_ADV_REPORT_SENT; - } else { - if (evtype == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) { - e->flags |= BLE_LL_SCAN_DUP_F_SCAN_RSP_SENT; - } else { - e->flags |= BLE_LL_SCAN_DUP_F_ADV_REPORT_SENT; - } - } - - return 0; -} - -/** - * Send an advertising report to the host. - * - * NOTE: while we are allowed to send multiple devices in one report, we - * will just send for one for now. - * - * @param pdu_type - * @param txadd - * @param rxbuf - * @param hdr - * @param scansm - */ -static void -ble_ll_scan_send_adv_report(uint8_t pdu_type, - const uint8_t *adva, uint8_t adva_type, - const uint8_t *inita, uint8_t inita_type, - struct os_mbuf *om, - struct ble_mbuf_hdr *hdr, - struct ble_ll_scan_sm *scansm) -{ - uint8_t subev = BLE_HCI_LE_SUBEV_ADV_RPT; - uint8_t adv_data_len; - uint8_t evtype; - int rc; - - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_DIRECT_IND) { - if (ble_ll_is_rpa(inita, inita_type)) { - /* For resolvable we send separate subevent */ - subev = BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT; - } - - evtype = BLE_HCI_ADV_RPT_EVTYPE_DIR_IND; - adv_data_len = 0; - } else { - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) { - evtype = BLE_HCI_ADV_RPT_EVTYPE_ADV_IND; - } else if (pdu_type == BLE_ADV_PDU_TYPE_ADV_SCAN_IND) { - evtype = BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND; - } else if (pdu_type == BLE_ADV_PDU_TYPE_ADV_NONCONN_IND) { - evtype = BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND; - } else { - evtype = BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP; - } - adv_data_len = om->om_data[1] - BLE_DEV_ADDR_LEN; - os_mbuf_adj(om, BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN); - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* If RPA has been used, make sure we use correct address types - * in the advertising report. - */ - if (BLE_MBUF_HDR_RESOLVED(hdr)) { - adva_type += 2; - } - if (BLE_MBUF_HDR_TARGETA_RESOLVED(hdr)) { - inita_type += 2; - } -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (scansm->ext_scanning) { - rc = ble_ll_hci_send_legacy_ext_adv_report(evtype, - adva, adva_type, - hdr->rxinfo.rssi, - adv_data_len, om, - inita, inita_type); - goto done; - } -#endif - - if (subev == BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT) { - rc = ble_ll_hci_send_dir_adv_report(adva, adva_type, inita, inita_type, - hdr->rxinfo.rssi); - goto done; - } - - rc = ble_ll_hci_send_adv_report(evtype, adva, adva_type, hdr->rxinfo.rssi, - adv_data_len, om); -done: - if (!rc && scansm->scan_filt_dups) { - ble_ll_scan_dup_update_legacy(adva_type, adva, subev, evtype); - } -} - -static void -ble_ll_get_chan_to_scan(struct ble_ll_scan_sm *scansm, uint8_t *chan, - int *phy) -{ - struct ble_ll_scan_params *scanp = scansm->scanp; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data = scansm->cur_aux_data; - - if (!scansm->ext_scanning || !aux_data || !aux_data->scanning) { - *chan = scanp->scan_chan; - *phy = scanp->phy; - return; - } - - *chan = aux_data->chan; - *phy = aux_data->aux_phy; -#else - *chan = scanp->scan_chan; - *phy = scanp->phy; -#endif -} -/** - * Called to enable the receiver for scanning. - * - * Context: Link Layer task - * - * @param sch - * - * @return int - */ -static int -ble_ll_scan_start(struct ble_ll_scan_sm *scansm, struct ble_ll_sched_item *sch) -{ - int rc; - struct ble_ll_scan_params *scanp = scansm->scanp; - uint8_t scan_chan; -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - uint8_t phy_mode; -#endif - int phy; - - BLE_LL_ASSERT(scansm->scan_rsp_pending == 0); - - ble_ll_get_chan_to_scan(scansm, &scan_chan, &phy); - - /* XXX: right now scheduled item is only present if we schedule for aux - * scan just make sanity check that we have proper combination of - * sch and resulting scan_chan - */ - BLE_LL_ASSERT(!sch || scan_chan < BLE_PHY_ADV_CHAN_START); - BLE_LL_ASSERT(sch || scan_chan >= BLE_PHY_ADV_CHAN_START); - - /* Set channel */ - rc = ble_phy_setchan(scan_chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); - BLE_LL_ASSERT(rc == 0); - - /* - * Set transmit end callback to NULL in case we transmit a scan request. - * There is a callback for the connect request. - */ - ble_phy_set_txend_cb(NULL, NULL); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - ble_phy_encrypt_disable(); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (ble_ll_resolv_enabled()) { - ble_phy_resolv_list_enable(); - } else { - ble_phy_resolv_list_disable(); - } -#endif - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - phy_mode = ble_ll_phy_to_phy_mode(phy, BLE_HCI_LE_PHY_CODED_ANY); - ble_phy_mode_set(phy_mode, phy_mode); -#endif - - /* XXX: probably need to make sure hfxo is running too */ - /* XXX: can make this better; want to just start asap. */ - if (sch) { - rc = ble_phy_rx_set_start_time(sch->start_time + - g_ble_ll_sched_offset_ticks, - sch->remainder); - } else { - rc = ble_phy_rx_set_start_time(os_cputime_get32() + - g_ble_ll_sched_offset_ticks, 0); - } - if (!rc || rc == BLE_PHY_ERR_RX_LATE) { - /* If we are late here, it is still OK because we keep scanning. - * Clear error - */ - rc = 0; - - /* Enable/disable whitelisting */ - if (scanp->scan_filt_policy & 1) { - ble_ll_whitelist_enable(); - } else { - ble_ll_whitelist_disable(); - } - - /* Set link layer state to scanning */ - if (scanp->scan_type == BLE_SCAN_TYPE_INITIATE) { - ble_ll_state_set(BLE_LL_STATE_INITIATING); - } else { - ble_ll_state_set(BLE_LL_STATE_SCANNING); - } - } - - return rc; -} - -static uint8_t -ble_ll_scan_get_next_adv_prim_chan(uint8_t chan) -{ - ++chan; - if (chan == BLE_PHY_NUM_CHANS) { - chan = BLE_PHY_ADV_CHAN_START; - } - - return chan; -} - -static uint32_t -ble_ll_scan_move_window_to(struct ble_ll_scan_params *scanp, uint32_t time) -{ - uint32_t end_time; - - /* - * Move window until given tick is before or inside window and move to next - * channel for each skipped interval. - */ - - end_time = scanp->timing.start_time + scanp->timing.window; - while (CPUTIME_GEQ(time, end_time)) { - scanp->timing.start_time += scanp->timing.interval; - scanp->scan_chan = ble_ll_scan_get_next_adv_prim_chan(scanp->scan_chan); - end_time = scanp->timing.start_time + scanp->timing.window; - } - - return scanp->timing.start_time; -} - -static bool -ble_ll_scan_is_inside_window(struct ble_ll_scan_params *scanp, uint32_t time) -{ - uint32_t start_time; - - /* Make sure we are checking against closest window */ - start_time = ble_ll_scan_move_window_to(scanp, time); - - if (scanp->timing.window == scanp->timing.interval) { - /* always inside window in continuous scan */ - return true; - } - - return CPUTIME_GEQ(time, start_time) && - CPUTIME_LT(time, start_time + scanp->timing.window); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_scan_aux_data_free(struct ble_ll_aux_data *aux_data) -{ - if (aux_data) { - if (aux_data->evt) { - ble_hci_trans_buf_free((uint8_t *)aux_data->evt); - aux_data->evt = NULL; - } - os_memblock_put(&ext_scan_aux_pool, aux_data); - STATS_INC(ble_ll_stats, aux_freed); - } -} - -struct ble_ll_aux_data * -ble_ll_scan_aux_data_ref(struct ble_ll_aux_data *aux_data) -{ - os_sr_t sr; - - BLE_LL_ASSERT(aux_data); - - OS_ENTER_CRITICAL(sr); - aux_data->ref_cnt++; - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_REF, (uint32_t) aux_data, aux_data->ref_cnt); - - OS_EXIT_CRITICAL(sr); - - return aux_data; -} - -void -ble_ll_scan_aux_data_unref(struct ble_ll_aux_data *aux_data) -{ - os_sr_t sr; - - BLE_LL_ASSERT(aux_data); - - OS_ENTER_CRITICAL(sr); - aux_data->ref_cnt--; - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_UNREF, (uint32_t) aux_data, aux_data->ref_cnt); - - if (aux_data->ref_cnt == 0) { - /* - * Some validation to make sure that we completed scan properly: - * - we either did not send any report or sent completed/truncated - * - we only sent one of completed/truncated - * - in case of error, we wither did not send anything or sent truncated - */ - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY) || - ((aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY) && - (aux_data->flags_ll & (BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED | BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)))); - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED) || !(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)); - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR) || - !(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY) || - (aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)); - - ble_ll_scan_aux_data_free(aux_data); - } - - OS_EXIT_CRITICAL(sr); -} - -static void -ble_ll_scan_sched_remove(struct ble_ll_sched_item *sch) -{ - ble_ll_scan_end_adv_evt(sch->cb_arg); - ble_ll_scan_aux_data_unref(sch->cb_arg); - sch->cb_arg = NULL; -} -#endif -/** - * Stop the scanning state machine - */ -void -ble_ll_scan_sm_stop(int chk_disable) -{ - os_sr_t sr; - uint8_t lls; - struct ble_ll_scan_sm *scansm; - - /* Stop the scanning timer */ - scansm = &g_ble_ll_scan_sm; - os_cputime_timer_stop(&scansm->scan_timer); - - /* Only set state if we are currently in a scan window */ - if (chk_disable) { - OS_ENTER_CRITICAL(sr); - lls = ble_ll_state_get(); - - if ((lls == BLE_LL_STATE_SCANNING) || - (lls == BLE_LL_STATE_INITIATING && chk_disable == 1)) { - /* Disable phy */ - ble_phy_disable(); - - /* Set LL state to standby */ - ble_ll_state_set(BLE_LL_STATE_STANDBY); - } - OS_EXIT_CRITICAL(sr); - } - - OS_ENTER_CRITICAL(sr); - - /* Disable scanning state machine */ - scansm->scan_enabled = 0; - scansm->restart_timer_needed = 0; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (scansm->ext_scanning) { - ble_ll_scan_clean_cur_aux_data(); - ble_ll_sched_rmv_elem_type(BLE_LL_SCHED_TYPE_AUX_SCAN, ble_ll_scan_sched_remove); - scansm->ext_scanning = 0; - } -#endif - - /* Update backoff if we failed to receive scan response */ - if (scansm->scan_rsp_pending) { - scansm->scan_rsp_pending = 0; - ble_ll_scan_req_backoff(scansm, 0); - } - OS_EXIT_CRITICAL(sr); - - /* Count # of times stopped */ - STATS_INC(ble_ll_stats, scan_stops); - - /* No need for RF anymore */ - OS_ENTER_CRITICAL(sr); - ble_ll_rfmgmt_scan_changed(false, 0); - ble_ll_rfmgmt_release(); - OS_EXIT_CRITICAL(sr); -} - -static int -ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm) -{ - struct ble_ll_scan_params *scanp; - struct ble_ll_scan_params *scanp_next; - - if (!ble_ll_is_valid_own_addr_type(scansm->own_addr_type, g_random_addr)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - BLE_LL_ASSERT(scansm->scanp); - scanp = scansm->scanp; - scanp_next = scansm->scanp_next; - - /* Count # of times started */ - STATS_INC(ble_ll_stats, scan_starts); - - /* Set flag telling us that scanning is enabled */ - scansm->scan_enabled = 1; - - /* Set first advertising channel */ - scanp->scan_chan = BLE_PHY_ADV_CHAN_START; - if (scanp_next) { - scanp_next->scan_chan = BLE_PHY_ADV_CHAN_START; - } - - /* Reset scan request backoff parameters to default */ - scansm->upper_limit = 1; - scansm->backoff_count = 1; - scansm->scan_rsp_pending = 0; - - /* Forget filtered advertisers from previous scan. */ - g_ble_ll_scan_num_rsp_advs = 0; - - os_mempool_clear(&g_scan_dup_pool); - TAILQ_INIT(&g_scan_dup_list); - - /* - * First scan window can start when RF is enabled. Add 1 tick since we are - * most likely not aligned with ticks so RF may be effectively enabled 1 - * tick later. - */ - scanp->timing.start_time = ble_ll_rfmgmt_enable_now(); - ble_ll_rfmgmt_scan_changed(true, scanp->timing.start_time); - - if (scanp_next) { - /* Schedule start time right after first phy */ - scanp_next->timing.start_time = scanp->timing.start_time + - scanp->timing.window; - } - - /* Start scan at 1st window */ - os_cputime_timer_start(&scansm->scan_timer, scanp->timing.start_time); - - return BLE_ERR_SUCCESS; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_aux_scan_rsp_failed(struct ble_ll_scan_sm *scansm) -{ - if (!scansm->cur_aux_data) { - return; - } - - STATS_INC(ble_ll_stats, aux_scan_rsp_err); - ble_ll_scan_interrupted(scansm); -} -#endif - -static void -ble_ll_scan_interrupted_event_cb(struct ble_npl_event *ev) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data; -#endif - - if (!scansm->scan_enabled) { - return; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - aux_data = ble_npl_event_get_arg(ev); - - if (aux_data) { - if (scansm->scan_rsp_pending) { - STATS_INC(ble_ll_stats, aux_scan_rsp_err); - } - ble_ll_scan_end_adv_evt(aux_data); - ble_ll_scan_aux_data_unref(aux_data); - ble_npl_event_set_arg(ev, NULL); - STATS_INC(ble_ll_stats, aux_missed_adv); - } -#endif - - /* - * If we timed out waiting for a response, the scan response pending - * flag should be set. Deal with scan backoff. Put device back into rx. - */ - - if (scansm->scan_rsp_pending) { - scansm->scan_rsp_pending = 0; - ble_ll_scan_req_backoff(scansm, 0); - } - - ble_ll_scan_chk_resume(); -} - -/** - * Called to process the scanning OS event which was posted to the LL task - * - * Context: Link Layer task. - * - * @param arg - */ -static void -ble_ll_scan_event_proc(struct ble_npl_event *ev) -{ - struct ble_ll_scan_sm *scansm; - os_sr_t sr; - bool start_scan; - bool inside_window; - struct ble_ll_scan_params *scanp; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - bool inside_window_next; - struct ble_ll_scan_params *scanp_next; -#endif - uint32_t next_proc_time; - uint32_t now; - /* - * Get the scanning state machine. If not enabled (this is possible), just - * leave and do nothing (just make sure timer is stopped). - */ - scansm = (struct ble_ll_scan_sm *)ble_npl_event_get_arg(ev); - scanp = scansm->scanp; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - scanp_next = scansm->scanp_next; -#endif - - OS_ENTER_CRITICAL(sr); - if (!scansm->scan_enabled) { - os_cputime_timer_stop(&scansm->scan_timer); - ble_ll_rfmgmt_scan_changed(false, 0); - ble_ll_rfmgmt_release(); - OS_EXIT_CRITICAL(sr); - return; - } - - if (scansm->cur_aux_data || scansm->scan_rsp_pending) { - /* Aux scan in progress. Wait */ - STATS_INC(ble_ll_stats, scan_timer_stopped); - scansm->restart_timer_needed = 1; - OS_EXIT_CRITICAL(sr); - return; - } - - now = os_cputime_get32(); - - inside_window = ble_ll_scan_is_inside_window(scanp, now); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* Update also next PHY if configured */ - if (scanp_next) { - inside_window_next = ble_ll_scan_is_inside_window(scanp_next, now); - - /* - * Switch PHY if current PHY is outside window and next PHY is either - * inside window or has next window earlier than current PHY. - */ - if (!inside_window && - ((inside_window_next || CPUTIME_LEQ(scanp_next->timing.start_time, - scanp->timing.start_time)))) { - scansm->scanp = scanp_next; - scansm->scanp_next = scanp; - scanp = scansm->scanp; - scanp_next = scansm->scanp_next; - inside_window = inside_window_next; - } - } -#endif - - /* - * At this point scanp and scanp_next point to current or closest scan - * window on both PHYs (scanp is the closer one). Make sure RF is enabled - * on time. - */ - ble_ll_rfmgmt_scan_changed(true, scanp->timing.start_time); - - /* - * If we are inside window, next scan proc should happen at the end of - * current window to either disable scan or switch to next PHY. - * If we are outside window, next scan proc should happen at the time of - * closest scan window. - */ - if (inside_window) { - next_proc_time = scanp->timing.start_time + scanp->timing.window; - } else { - next_proc_time = scanp->timing.start_time; - } - - /* - * If we are not in the standby state it means that the scheduled - * scanning event was overlapped in the schedule. In this case all we do - * is post the scan schedule end event. - */ - start_scan = inside_window; - switch (ble_ll_state_get()) { - case BLE_LL_STATE_ADV: - case BLE_LL_STATE_CONNECTION: - case BLE_LL_STATE_SYNC: - start_scan = false; - break; - case BLE_LL_STATE_INITIATING: - /* Must disable PHY since we will move to a new channel */ - ble_phy_disable(); - if (!inside_window) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - } - /* PHY is disabled - make sure we do not wait for AUX_CONNECT_RSP */ - ble_ll_conn_reset_pending_aux_conn_rsp(); - break; - case BLE_LL_STATE_SCANNING: - /* Must disable PHY since we will move to a new channel */ - ble_phy_disable(); - if (!inside_window) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - } - break; - case BLE_LL_STATE_STANDBY: - break; - default: - BLE_LL_ASSERT(0); - break; - } - - if (start_scan) { - ble_ll_scan_start(scansm, NULL); - } else { - ble_ll_rfmgmt_release(); - } - - OS_EXIT_CRITICAL(sr); - os_cputime_timer_start(&scansm->scan_timer, next_proc_time); -} - -/** - * ble ll scan rx pdu start - * - * Called when a PDU reception has started and the Link Layer is in the - * scanning state. - * - * Context: Interrupt - * - * @param pdu_type - * @param rxflags - * - * @return int - * 0: we will not attempt to reply to this frame - * 1: we may send a response to this frame. - */ -int -ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint16_t *rxflags) -{ - int rc; - struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; - - rc = 0; - scansm = &g_ble_ll_scan_sm; - scanp = scansm->scanp; - - switch (scanp->scan_type) { - case BLE_SCAN_TYPE_ACTIVE: - /* If adv ind or scan ind, we may send scan request */ - if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) || - (pdu_type == BLE_ADV_PDU_TYPE_ADV_SCAN_IND)) { - rc = 1; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND && scansm->ext_scanning)) { - *rxflags |= BLE_MBUF_HDR_F_EXT_ADV; - rc = 1; - } -#endif - - if (scansm->cur_aux_data && !scansm->scan_rsp_pending ) { - STATS_INC(ble_ll_stats, aux_received); - } - - /* - * If this is the first PDU after we sent the scan response (as - * denoted by the scan rsp pending flag), we set a bit in the ble - * header so the link layer can check to see if the scan request - * was successful. We do it this way to let the Link Layer do the - * work for successful scan requests. If failed, we do the work here. - */ - if (scansm->scan_rsp_pending) { - scansm->scan_rsp_pending = 0; - - if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_RSP) { - *rxflags |= BLE_MBUF_HDR_F_SCAN_RSP_RXD; - } else if (pdu_type == BLE_ADV_PDU_TYPE_AUX_SCAN_RSP) { - *rxflags |= BLE_MBUF_HDR_F_SCAN_RSP_RXD; - } else { - ble_ll_scan_req_backoff(scansm, 0); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_ll_aux_scan_rsp_failed(scansm); -#endif - } - } - break; - case BLE_SCAN_TYPE_PASSIVE: -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND && scansm->ext_scanning)) { - *rxflags |= BLE_MBUF_HDR_F_EXT_ADV; - } - break; -#endif - default: - break; - } - - return rc; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static uint8_t -ble_ll_ext_adv_phy_mode_to_local_phy(uint8_t adv_phy_mode) -{ - switch (adv_phy_mode) { - case 0x00: - return BLE_PHY_1M; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - case 0x01: - return BLE_PHY_2M; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case 0x02: - return BLE_PHY_CODED; -#endif - } - - return 0; -} - -static int -ble_ll_ext_scan_parse_aux_ptr(struct ble_ll_aux_data *aux_data, uint8_t *buf) -{ - uint32_t aux_ptr_field = get_le32(buf) & 0x00FFFFFF; - - aux_data->chan = (aux_ptr_field) & 0x3F; - if (aux_data->chan >= BLE_PHY_NUM_DATA_CHANS) { - return -1; - } - - /* TODO use CA aux_ptr_field >> 6 */ - - aux_data->offset = 30 * ((aux_ptr_field >> 8) & 0x1FFF); - - if ((aux_ptr_field >> 7) & 0x01) { - aux_data->offset *= 10; - aux_data->offset_units = 1; - } - - if (aux_data->offset < BLE_LL_MAFS) { - return -1; - } - - aux_data->aux_phy = - ble_ll_ext_adv_phy_mode_to_local_phy((aux_ptr_field >> 21) & 0x07); - if (aux_data->aux_phy == 0) { - return -1; - } - - return 0; -} - -static void -ble_ll_ext_scan_parse_adv_info(struct ext_adv_report *report, const uint8_t *buf) -{ - uint16_t adv_info = get_le16(buf); - - /* TODO Use DID */ - - report->sid = (adv_info >> 12); -} - -/** - * ble_ll_scan_update_aux_data - * - * Update aux_data stored in ble_hdr.rxinfo.user_data. If no aux_data is present - * (i.e. processing ADV_EXT_IND) this will try to allocate new aux_data. - * - * Context: Interrupt - * - * @param ble_hdr - * @param rxbuf - * - * @return int - * 1: do not scan for next AUX (no AuxPtr or malformed data) - * 0: scan for next AUX (valid AuxPtr found) - * -1: error - */ -int -ble_ll_scan_update_aux_data(struct ble_mbuf_hdr *ble_hdr, uint8_t *rxbuf, - bool *adva_present) -{ - uint8_t pdu_hdr; - uint8_t pdu_len; - uint8_t adv_mode; - uint8_t eh_len; - uint8_t eh_flags; - uint8_t *eh; - struct ble_ll_aux_data *aux_data; - bool is_aux; - - aux_data = ble_hdr->rxinfo.user_data; - /* aux_data is initially not set only for ADV_EXT_IND */ - is_aux = aux_data; - - pdu_hdr = rxbuf[0]; - pdu_len = rxbuf[1]; - - /* PDU without at least Extended Header Length is invalid */ - if (pdu_len == 0) { - return -1; - } - - adv_mode = rxbuf[2] >> 6; - eh_len = rxbuf[2] & 0x3f; - eh_flags = rxbuf[3]; - eh = &rxbuf[4]; - - /* - * PDU without Extended Header is valid in case of last AUX_CHAIN_IND in - * chain so aux_data has to be set and advertising mode has to be 00b, - * otherwise it's an invalid PDU. - */ - if (eh_len == 0) { - if (!aux_data || adv_mode) { - return -1; - } - aux_data->flags_isr |= BLE_LL_AUX_FLAG_SCAN_COMPLETE; - return 1; - } - - /* - * If aux_data is not set, this is ADV_EXT_IND which starts new extended - * advertising event. - */ - if (!aux_data) { - if (ble_ll_scan_ext_adv_init(&aux_data)) { - return -1; - } - - aux_data->aux_primary_phy = ble_hdr->rxinfo.phy; - } else { - if (aux_data->flags_isr & BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED) { - aux_data->flags_isr |= BLE_LL_AUX_FLAG_AUX_CHAIN_RECEIVED; - } else { - aux_data->flags_isr |= BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED; - } - } - - /* Now parse extended header... */ - - if (eh_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - aux_data->flags |= BLE_LL_AUX_HAS_ADVA; - memcpy(aux_data->adva, eh, 6); - aux_data->adva_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_TXADD_MASK); - eh += BLE_LL_EXT_ADV_ADVA_SIZE; - - if (adva_present) { - *adva_present = true; - } - } else if (adva_present) { - *adva_present = false; - } - - if (eh_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - aux_data->flags |= BLE_LL_AUX_HAS_TARGETA; - memcpy(aux_data->targeta, eh, 6); - aux_data->targeta_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_MASK); - eh += BLE_LL_EXT_ADV_TARGETA_SIZE; - } - - - if (eh_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { - eh += 1; - } - - if (eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { - aux_data->flags |= BLE_LL_AUX_HAS_ADI; - if (is_aux) { - if (get_le16(eh) != aux_data->adi) { - aux_data->flags_isr |= BLE_LL_AUX_FLAG_SCAN_ERROR; - STATS_INC(ble_ll_stats, aux_chain_err); - } - } else { - aux_data->adi = get_le16(eh); - } - eh += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - } - - if (eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { - if (ble_ll_ext_scan_parse_aux_ptr(aux_data, eh)) { - aux_data->flags_isr |= BLE_LL_AUX_FLAG_SCAN_ERROR; - } - } else if (!(adv_mode & BLE_LL_EXT_ADV_MODE_SCAN)) { - /* No AuxPtr for scannable PDU is ignored since we can still scan it */ - aux_data->flags_isr |= BLE_LL_AUX_FLAG_SCAN_COMPLETE; - } - - ble_hdr->rxinfo.user_data = aux_data; - - /* Do not scan for next AUX if either no AuxPtr or malformed data found */ - return !(eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) || - (aux_data->flags_isr & BLE_LL_AUX_FLAG_SCAN_ERROR); -} - -/** - * Called when a receive ADV_EXT PDU has ended. - * - * Context: Interrupt - * - * @return int - * < 0 Error - * >= 0: Success (number of bytes left in PDU) - * - */ -static int -ble_ll_scan_parse_ext_hdr(struct os_mbuf *om, - const uint8_t *adva, uint8_t adva_type, - const uint8_t *inita, uint8_t inita_type, - struct ble_mbuf_hdr *ble_hdr, - struct ext_adv_report *report) -{ - uint8_t pdu_len; - uint8_t ext_hdr_len; - uint8_t ext_hdr_flags; - uint8_t *ext_hdr; - uint8_t *rxbuf = om->om_data; - int i = 1; - struct ble_ll_scan_sm *scansm; - struct ble_ll_aux_data *aux_data = ble_hdr->rxinfo.user_data; - - BLE_LL_ASSERT(report); - - scansm = &g_ble_ll_scan_sm; - - if (!scansm->ext_scanning) { - /* Ignore ext adv if host does not want it*/ - return -1; - } - - pdu_len = rxbuf[1]; - if (pdu_len == 0) { - return -1; - } - - report->evt_type = rxbuf[2] >> 6; - if ( report->evt_type > BLE_LL_EXT_ADV_MODE_SCAN) { - return -1; - } - - if (BLE_MBUF_HDR_SCAN_RSP_RXD(ble_hdr)) { - report->evt_type |= BLE_HCI_ADV_SCAN_RSP_MASK; - } - - ext_hdr_len = rxbuf[2] & 0x3F; - os_mbuf_adj(om, 3); - - ext_hdr_flags = rxbuf[3]; - ext_hdr = &rxbuf[4]; - - if (ext_hdr_len) { - i = 0; - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - i += BLE_LL_EXT_ADV_ADVA_SIZE; - } - - if (adva) { - memcpy(report->addr, adva, 6); - report->addr_type = adva_type; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - i += BLE_LL_EXT_ADV_TARGETA_SIZE; - } - - if (inita) { - memcpy(report->dir_addr, inita, 6); - report->dir_addr_type = inita_type; - report->evt_type |= BLE_HCI_ADV_DIRECT_MASK; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { - /* Just skip it for now*/ - i += 1; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { - ble_ll_ext_scan_parse_adv_info(report, (ext_hdr + i)); - i += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - } else if (report->evt_type & BLE_HCI_ADV_SCAN_RSP_MASK) { - report->sid = (aux_data->adi >> 12); - } - - /* In this point of time we don't want to care about aux ptr */ - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { - i += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { - report->periodic_itvl = get_le16(ext_hdr + i + 2); - i += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { - report->tx_power = *(ext_hdr + i); - i += BLE_LL_EXT_ADV_TX_POWER_SIZE; - } - - /* TODO Handle ACAD if needed */ - } - - /* In the event we need information on primary and secondary PHY used during - * advertising. - */ - if (!aux_data) { - report->pri_phy = ble_hdr->rxinfo.phy; - goto done; - } - - report->sec_phy = aux_data->aux_phy; - report->pri_phy = aux_data->aux_primary_phy; - - if (ext_hdr_len) { - /* Adjust mbuf to contain advertising data only */ - os_mbuf_adj(om, ext_hdr_len); - } - - /* Let us first keep update event type in aux data. - * Note that in aux chain and aux scan response packets - * we do miss original event type, which we need for advertising report. - */ - aux_data->evt_type |= report->evt_type; - report->evt_type = aux_data->evt_type; - -done: - return pdu_len - ext_hdr_len - 1; -} - -static int -ble_ll_scan_get_addr_from_ext_adv(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr, - uint8_t **addr, uint8_t *addr_type, - uint8_t **inita, uint8_t *inita_type, - int *ext_mode) -{ - uint8_t pdu_len; - uint8_t ext_hdr_len; - uint8_t ext_hdr_flags; - uint8_t *ext_hdr; - bool has_adva = false; - bool has_inita = false; - int i; - struct ble_ll_aux_data *aux_data = ble_hdr->rxinfo.user_data; - - *addr = NULL; - *inita = NULL; - - pdu_len = rxbuf[1]; - if (pdu_len == 0) { - return -1; - } - - *ext_mode = rxbuf[2] >> 6; - if (*ext_mode > BLE_LL_EXT_ADV_MODE_SCAN) { - return -1; - } - - ext_hdr_len = rxbuf[2] & 0x3F; - if (ext_hdr_len == 0) { - goto done; - } - - ext_hdr_flags = rxbuf[3]; - ext_hdr = &rxbuf[4]; - - i = 0; - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - if (ext_hdr_len < BLE_LL_EXT_ADV_ADVA_SIZE) { - return -1; - } - - *addr = ext_hdr + i; - *addr_type = - ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK); - i += BLE_LL_EXT_ADV_ADVA_SIZE; - - has_adva = true; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - *inita = ext_hdr + i; - *inita_type = - ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK); - i += BLE_LL_EXT_ADV_TARGETA_SIZE; - - has_inita = true; - } - -done: - /* Check if we had address already. If yes, replace it with new one */ - - if (aux_data) { - /* If address has been provided, we do have it already in aux_data.*/ - if (aux_data->flags & BLE_LL_AUX_HAS_ADVA) { - if (!has_adva) { - *addr = aux_data->adva; - *addr_type = aux_data->adva_type; - } else { - memcpy(aux_data->adva, *addr, 6); - aux_data->adva_type = *addr_type; - } - } - - if (aux_data->flags & BLE_LL_AUX_HAS_TARGETA) { - if (!has_inita) { - *inita = aux_data->targeta; - *inita_type = aux_data->targeta_type; - } else { - memcpy(aux_data->targeta, *inita, 6); - aux_data->targeta_type = *inita_type; - } - } - } - - return 0; -} -#endif - -int -ble_ll_scan_adv_decode_addr(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *ble_hdr, - uint8_t **addr, uint8_t *addr_type, - uint8_t **inita, uint8_t *inita_type, - int *ext_mode) -{ - /* - * XXX this should be only used for legacy advertising, but need to refactor - * code in ble_ll_init first so it does not call this for ext - */ - - if (pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND && - pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) { - /* Legacy advertising */ - *addr_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK); - *addr = rxbuf + BLE_LL_PDU_HDR_LEN; - - if (pdu_type != BLE_ADV_PDU_TYPE_ADV_DIRECT_IND) { - *inita = NULL; - *inita_type = 0; - return 0; - } - - *inita = rxbuf + BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN; - *inita_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK); - - return 0; - } - - /* Extended advertising */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - return ble_ll_scan_get_addr_from_ext_adv(rxbuf, ble_hdr, addr, addr_type, - inita, inita_type, ext_mode); -#else - return -1; -#endif - - return 0; -} - -static void -ble_ll_scan_get_addr_data_from_legacy(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_ll_scan_addr_data *addrd) -{ - BLE_LL_ASSERT(pdu_type < BLE_ADV_PDU_TYPE_ADV_EXT_IND); - - addrd->adva_present = true; - - addrd->adva = rxbuf + BLE_LL_PDU_HDR_LEN; - addrd->adva_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK); - - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_DIRECT_IND) { - addrd->targeta = rxbuf + BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN; - addrd->targeta_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK); - } else { - addrd->targeta = NULL; - addrd->targeta_type = 0; - } -} - -/* - * Matches incoming PDU using scan filter policy and whitelist, if applicable. - * This will also resolve addresses and update flags/fields in header and - * addr_data as needed. - * - * @return 0 = no match - * 1 = match - * 2 = match, but do not scan - */ -static int -ble_ll_scan_rx_filter(struct ble_mbuf_hdr *hdr, struct ble_ll_scan_addr_data *addrd) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - struct ble_ll_scan_params *scanp = scansm->scanp; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data = hdr->rxinfo.user_data; -#endif - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - struct ble_ll_resolv_entry *rl = NULL; -#endif - bool scan_req_allowed = true; - int resolved = 0; - - /* Use AdvA as initial advertiser address, we may try to resolve it later */ - addrd->adv_addr = addrd->adva; - addrd->adv_addr_type = addrd->adva_type; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* By default, assume AdvA is not resolved */ - rxinfo->rpa_index = -1; - - switch (ble_ll_addr_subtype(addrd->adva, addrd->adva_type)) { - case BLE_LL_ADDR_SUBTYPE_RPA: - /* - * Only resolve if packet actually contained AdvA. - * In extended advertising PDUs we may use RL index from a PDU that - * already had AdvA (e.g. ADV_EXT_IND in case of AUX_ADV_IND without - * AdvA). In legacy advertising PDUs we always need to resolve AdvA. - */ - if (addrd->adva_present) { - rxinfo->rpa_index = ble_hw_resolv_list_match(); - } else { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - BLE_LL_ASSERT(aux_data); - rxinfo->rpa_index = aux_data->rpa_index; -#else - BLE_LL_ASSERT(false); - rxinfo->rpa_index = -1; -#endif - } - - if (rxinfo->rpa_index < 0) { - break; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (aux_data) { - aux_data->rpa_index = rxinfo->rpa_index; - } -#endif - - /* Use resolved identity address as advertiser address */ - rl = &g_ble_ll_resolv_list[rxinfo->rpa_index]; - addrd->adv_addr = rl->rl_identity_addr; - addrd->adv_addr_type = rl->rl_addr_type; - addrd->rl = rl; - - rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; - resolved = 1; - break; - case BLE_LL_ADDR_SUBTYPE_IDENTITY: - /* - * If AdvA is an identity address, we need to check if that device was - * added to RL in order to use proper privacy mode. - */ - rl = ble_ll_resolv_list_find(addrd->adva, addrd->adva_type); - if (!rl) { - break; - } - - addrd->rl = rl; - - /* Ignore device if using network privacy mode and it has IRK */ - if ((rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && rl->rl_has_peer) { - return 0; - } - break; - default: - /* NRPA goes through filtering policy directly */ - break; - } - - if (addrd->targeta) { - switch (ble_ll_addr_subtype(addrd->targeta, addrd->targeta_type)) { - case BLE_LL_ADDR_SUBTYPE_RPA: - /* Check if TargetA can be resolved using the same RL entry as AdvA */ - if (rl && ble_ll_resolv_rpa(addrd->targeta, rl->rl_local_irk)) { - rxinfo->flags |= BLE_MBUF_HDR_F_TARGETA_RESOLVED; - break; - } - - /* Check if scan filter policy allows unresolved RPAs to be processed */ - if (!(scanp->scan_filt_policy & 0x02)) { - return 0; - } - - /* - * We will notify host as requited by scan policy, but make sure we - * do not send scan request since we do not know if this is directed - * to us. - */ - scan_req_allowed = false; - break; - case BLE_LL_ADDR_SUBTYPE_IDENTITY: - /* We shall ignore identity in TargetA if we are using RPA */ - if ((scanp->own_addr_type & 0x02) && rl && rl->rl_has_local) { - return 0; - } - /* Ignore if not directed to us */ - if (!ble_ll_is_our_devaddr(addrd->targeta, addrd->targeta_type)) { - return 0; - } - break; - default: - /* NRPA goes through filtering policy directly */ - break; - } - } -#else - /* Ignore if not directed to us */ - if (addrd->targeta && - !ble_ll_is_our_devaddr(addrd->targeta, addrd->targeta_type)) { - return 0; - } -#endif - - /* Check on WL if required by scan filter policy */ - if (scanp->scan_filt_policy & 0x01) { - if (!ble_ll_whitelist_match(addrd->adv_addr, addrd->adv_addr_type, resolved)) { - return 0; - } - } - - return scan_req_allowed ? 1 : 2; -} - -static int -ble_ll_scan_rx_isr_on_legacy(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *hdr, - struct ble_ll_scan_addr_data *addrd) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - struct ble_ll_scan_params *scanp = scansm->scanp; - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - uint8_t sreq_adva_type; - uint8_t *sreq_adva; - int rc; - - ble_ll_scan_get_addr_data_from_legacy(pdu_type, rxbuf, addrd); - - if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_RSP) { - if (!BLE_MBUF_HDR_SCAN_RSP_RXD(hdr)) { - /* - * We were not expecting scan response so just ignore and do not - * update backoff. - */ - return -1; - } - - sreq_adva_type = !!(scansm->pdu_data.hdr_byte & BLE_ADV_PDU_HDR_RXADD_MASK); - sreq_adva = scansm->pdu_data.adva; - - /* - * Ignore scan response if AdvA does not match AdvA in request and also - * update backoff as if there was no scan response. - */ - if ((addrd->adva_type != sreq_adva_type) || - memcmp(addrd->adva, sreq_adva, BLE_DEV_ADDR_LEN)) { - ble_ll_scan_req_backoff(scansm, 0); - return -1; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* - * We are not pushing this one through filters so need to update - * rpa_index here as otherwise pkt_in won't be able to determine - * advertiser address properly. - */ - rxinfo->rpa_index = ble_hw_resolv_list_match(); - if (rxinfo->rpa_index >= 0) { - rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; - } -#endif - - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; - - return 0; - } - - rc = ble_ll_scan_rx_filter(hdr, addrd); - if (!rc) { - return 0; - } - - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; - - if (rc == 2) { - /* Scan request forbidden by filter policy */ - return 0; - } - - return (scanp->scan_type == BLE_SCAN_TYPE_ACTIVE) && - ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) || - (pdu_type == BLE_ADV_PDU_TYPE_ADV_SCAN_IND)); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static int -ble_ll_scan_rx_isr_on_aux(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *hdr, - struct ble_ll_scan_addr_data *addrd) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - struct ble_ll_scan_params *scanp = scansm->scanp; - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - struct ble_ll_aux_data *aux_data; - int rc; - - if (!scansm->ext_scanning) { - return -1; - } - - rc = ble_ll_scan_update_aux_data(hdr, rxbuf, &addrd->adva_present); - if (rc < 0) { - rxinfo->flags |= BLE_MBUF_HDR_F_AUX_INVALID; - return -1; - } else if (rc == 0) { - rxinfo->flags |= BLE_MBUF_HDR_F_AUX_PTR_WAIT; - } - - /* Now we can update aux_data from header since it may have just been created */ - aux_data = rxinfo->user_data; - - /* - * Restore proper header flags if filtering was already done successfully on - * some previous PDU in an event. - */ - if (aux_data->flags & BLE_LL_AUX_IS_MATCHED) { - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - rxinfo->rpa_index = aux_data->rpa_index; - if (rxinfo->rpa_index >= 0) { - rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; - } - if (aux_data->flags & BLE_LL_AUX_IS_TARGETA_RESOLVED) { - rxinfo->flags |= BLE_MBUF_HDR_F_TARGETA_RESOLVED; - } -#endif - goto done; - } - - if (aux_data->flags & BLE_LL_AUX_HAS_ADVA) { - addrd->adva = aux_data->adva; - addrd->adva_type = aux_data->adva_type; - } else { - /* Accept this PDU and wait for AdvA in aux */ - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; - return 0; - } - if (aux_data->flags & BLE_LL_AUX_HAS_TARGETA) { - addrd->targeta = aux_data->targeta; - addrd->targeta_type = aux_data->targeta_type; - } else { - addrd->targeta = NULL; - } - - rc = ble_ll_scan_rx_filter(hdr, addrd); - if (!rc) { - return 0; - } - - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; - - /* - * Once we matched device, there's no need to go through filtering on every - * other PDU in an event so just store info required to restore state for - * subsequent PDUs in aux_data. - */ - aux_data->flags |= BLE_LL_AUX_IS_MATCHED; - if (rxinfo->flags & BLE_MBUF_HDR_F_TARGETA_RESOLVED) { - aux_data->flags |= BLE_LL_AUX_IS_TARGETA_RESOLVED; - /* AdvA state is already stored in rpa_index */ - } - - if (rc == 2) { - /* Scan request forbidden by filter policy */ - return 0; - } - -done: - return (scanp->scan_type == BLE_SCAN_TYPE_ACTIVE) && - ((rxbuf[2] >> 6) == BLE_LL_EXT_ADV_MODE_SCAN); -} -#endif - -static bool -ble_ll_scan_send_scan_req(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *hdr, - struct ble_ll_scan_addr_data *addrd) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data = rxinfo->user_data; - uint8_t phy_mode; -#endif - bool is_ext_adv = false; - uint16_t adi = 0; - int rc; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) { - if (ble_ll_scan_get_adi(aux_data, &adi) < 0) { - return false; - } - is_ext_adv = true; - } -#endif - - /* Check if we already scanned this device successfully */ - if (ble_ll_scan_have_rxd_scan_rsp(addrd->adv_addr, addrd->adv_addr_type, - is_ext_adv, adi)) { - return false; - } - - /* Better not be a scan response pending */ - BLE_LL_ASSERT(scansm->scan_rsp_pending == 0); - - /* We want to send a request. See if backoff allows us */ - if (scansm->backoff_count > 0) { - if (--scansm->backoff_count != 0) { - return false; - } - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - phy_mode = ble_ll_phy_to_phy_mode(rxinfo->phy, BLE_HCI_LE_PHY_CODED_ANY); - if (ble_ll_sched_scan_req_over_aux_ptr(rxinfo->channel, phy_mode)) { - return false; - } -#endif - - /* Use original AdvA in scan request (Core 5.1, Vol 6, Part B, section 6.3) */ - ble_ll_scan_req_pdu_prepare(scansm, addrd->adva, addrd->adva_type, addrd->rl); - - rc = ble_phy_tx(ble_ll_scan_req_tx_pdu_cb, scansm, BLE_PHY_TRANSITION_TX_RX); - if (rc) { - return false; - } - - scansm->scan_rsp_pending = 1; - rxinfo->flags |= BLE_MBUF_HDR_F_SCAN_REQ_TXD; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (rxinfo->channel < BLE_PHY_NUM_DATA_CHANS) { - /* Keep aux_data for expected scan response */ - scansm->cur_aux_data = ble_ll_scan_aux_data_ref(aux_data); - STATS_INC(ble_ll_stats, aux_scan_req_tx); - } -#endif - - return true; -} - -/** - * Called when a receive PDU has ended. - * - * Context: Interrupt - * - * @param rxpdu - * - * @return int - * < 0: Disable the phy after reception. - * == 0: Success. Do not disable the PHY. - * > 0: Do not disable PHY as that has already been done. - */ -int -ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - struct ble_mbuf_hdr *hdr = BLE_MBUF_HDR_PTR(rxpdu); - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - uint8_t *rxbuf; - uint8_t pdu_type; - struct ble_ll_scan_addr_data addrd; - int rc; - - /* - * If buffer for incoming PDU was not allocated we need to force scan to be - * restarted since LL will not be notified. Keep PHY enabled. - */ - if (rxpdu == NULL) { - ble_ll_scan_interrupted(scansm); - return 0; - } - - rxbuf = rxpdu->om_data; - pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* - * In case aux was expected, copy aux_data for LL to use. Make sure this was - * indeed an aux as otherwise there's no need to process it and just pass to - * LL immediately. - */ - if (scansm->cur_aux_data) { - rxinfo->user_data = scansm->cur_aux_data; - scansm->cur_aux_data = NULL; - if (pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - return -1; - } - } -#endif - - if (!crcok) { - goto scan_rx_isr_ignore; - } - - /* - * Addresses will be always set in handlers, no need to initialize them. We - * only need to initialize rl which may not be always set, depending on how - * filtering goes. - */ - addrd.rl = NULL; - - switch (pdu_type) { - case BLE_ADV_PDU_TYPE_ADV_IND: - case BLE_ADV_PDU_TYPE_ADV_DIRECT_IND: - case BLE_ADV_PDU_TYPE_ADV_NONCONN_IND: - case BLE_ADV_PDU_TYPE_SCAN_RSP: - case BLE_ADV_PDU_TYPE_ADV_SCAN_IND: - rc = ble_ll_scan_rx_isr_on_legacy(pdu_type, rxbuf, hdr, &addrd); - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - case BLE_ADV_PDU_TYPE_ADV_EXT_IND: - rc = ble_ll_scan_rx_isr_on_aux(pdu_type, rxbuf, hdr, &addrd); - break; -#endif - default: - /* This is not something we would like to process here */ - rc = -1; - break; - } - - if (rc == -1) { - goto scan_rx_isr_ignore; - } else if (rc == 1) { - if (ble_ll_scan_send_scan_req(pdu_type, rxbuf, hdr, &addrd)) { - /* Keep PHY active and LL in scanning state */ - return 0; - } - } - - /* We are done with this PDU so go to standby and let LL resume if needed */ - ble_ll_state_set(BLE_LL_STATE_STANDBY); - return -1; - -scan_rx_isr_ignore: - rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; - ble_ll_state_set(BLE_LL_STATE_STANDBY); - return -1; -} - -/** - * Called to resume scanning. This is called after an advertising event or - * connection event has ended. It is also called if we receive a packet while - * in the initiating or scanning state. - * - * If periodic advertising is enabled this is also called on sync event end - * or sync packet received if chaining - * - * Context: Link Layer task - */ -void -ble_ll_scan_chk_resume(void) -{ - os_sr_t sr; - struct ble_ll_scan_sm *scansm; - uint32_t now; - - scansm = &g_ble_ll_scan_sm; - if (scansm->scan_enabled) { - OS_ENTER_CRITICAL(sr); - if (scansm->restart_timer_needed) { - scansm->restart_timer_needed = 0; - ble_ll_event_send(&scansm->scan_sched_ev); - STATS_INC(ble_ll_stats, scan_timer_restarted); - OS_EXIT_CRITICAL(sr); - return; - } - - now = os_cputime_get32(); - if (ble_ll_state_get() == BLE_LL_STATE_STANDBY && - ble_ll_scan_is_inside_window(scansm->scanp, now)) { - /* Turn on the receiver and set state */ - ble_ll_scan_start(scansm, NULL); - } - OS_EXIT_CRITICAL(sr); - } -} - -/** - * Scan timer callback; means that the scan window timeout has been reached - * and we should perform the appropriate actions. - * - * Context: Interrupt (cputimer) - * - * @param arg Pointer to scan state machine. - */ -void -ble_ll_scan_timer_cb(void *arg) -{ - struct ble_ll_scan_sm *scansm; - - scansm = (struct ble_ll_scan_sm *)arg; - ble_ll_event_send(&scansm->scan_sched_ev); -} - -void -ble_ll_scan_interrupted(struct ble_ll_scan_sm *scansm) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_npl_event_set_arg(&scansm->scan_interrupted_ev, scansm->cur_aux_data); - scansm->cur_aux_data = NULL; -#endif - - ble_ll_event_send(&scansm->scan_interrupted_ev); -} - -/** - * Called when the wait for response timer expires while in the scanning - * state. - * - * Context: Interrupt. - */ -void -ble_ll_scan_wfr_timer_exp(void) -{ - struct ble_ll_scan_sm *scansm; - uint8_t chan; - int phy; - int rc; -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - uint8_t phy_mode; -#endif - uint32_t now; - - scansm = &g_ble_ll_scan_sm; - - /* Update backoff if we failed to receive scan response */ - if (scansm->scan_rsp_pending) { - scansm->scan_rsp_pending = 0; - ble_ll_scan_req_backoff(scansm, 0); - } - - if (scansm->cur_aux_data) { - /* We actually care about interrupted scan only for EXT ADV because only - * then we might consider to send truncated event to the host. - */ - ble_ll_scan_interrupted(scansm); - - /* Need to disable phy since we are going to move to BLE_LL_STATE_STANDBY - * or we will need to change channel to primary one - */ - ble_phy_disable(); - - now = os_cputime_get32(); - if (!ble_ll_scan_is_inside_window(scansm->scanp, now)) { - /* Outside the window scan */ - ble_ll_state_set(BLE_LL_STATE_STANDBY); - return; - } - - ble_ll_get_chan_to_scan(scansm, &chan, &phy); -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - phy_mode = ble_ll_phy_to_phy_mode(phy, BLE_HCI_LE_PHY_CODED_ANY); - ble_phy_mode_set(phy_mode, phy_mode); -#endif - rc = ble_phy_setchan(chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); - BLE_LL_ASSERT(rc == 0); - } - - - ble_phy_restart_rx(); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -/* - * Send extended advertising report - * - * @return -1 on error (data truncated or other error) - * 0 on success (data status is "completed") - * 1 on success (data status is not "completed") - */ -static int -ble_ll_hci_send_ext_adv_report(uint8_t ptype, uint8_t *adva, uint8_t adva_type, - uint8_t *inita, uint8_t inita_type, - struct os_mbuf *om, - struct ble_mbuf_hdr *hdr) -{ - struct ble_ll_aux_data *aux_data = hdr->rxinfo.user_data; - struct ble_hci_ev_le_subev_ext_adv_rpt *ev; - struct ext_adv_report *report; - struct ble_hci_ev *hci_ev; - struct ble_hci_ev *hci_ev_next; - int offset; - int datalen; - int rc; - bool need_event; - bool is_scannable_aux; - uint8_t max_data_len; - - if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { - rc = -1; - goto done; - } - - /* - * We keep one allocated event in aux_data to be able to truncate chain - * properly in case of error. If there is no event in aux_data it means this - * is the first event for this chain. - */ - if (aux_data && aux_data->evt) { - hci_ev = aux_data->evt; - aux_data->evt = NULL; - - hci_ev->length = sizeof(*ev) + sizeof(*report); - } else { - hci_ev = ble_ll_scan_get_ext_adv_report(NULL); - if (!hci_ev) { - rc = -1; - goto done; - } - } - - ev = (void *) hci_ev->data; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* If RPA has been used, make sure we use correct address types - * in the advertising report. - */ - if (BLE_MBUF_HDR_RESOLVED(hdr)) { - adva_type += 2; - } - if (BLE_MBUF_HDR_TARGETA_RESOLVED(hdr)) { - inita_type += 2; - } -#endif - - datalen = ble_ll_scan_parse_ext_hdr(om, adva, adva_type, inita, inita_type, - hdr, ev->reports); - if (datalen < 0) { - rc = -1; - - /* Need to send truncated event if we already sent some reports */ - if (aux_data && (aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY)) { - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED)); - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)); - - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED; - - report = ev->reports; - report->data_len = 0; - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; - - ble_ll_hci_event_send(hci_ev); - goto done; - } - - ble_hci_trans_buf_free((uint8_t *)hci_ev); - goto done; - } - - is_scannable_aux = aux_data && - (aux_data->evt_type & BLE_HCI_ADV_SCAN_MASK) && - !(aux_data->evt_type & BLE_HCI_ADV_SCAN_RSP_MASK); - - max_data_len = BLE_LL_MAX_EVT_LEN - sizeof(*hci_ev) - sizeof(*ev) - sizeof(*report); - offset = 0; - - do { - hci_ev_next = NULL; - - ev = (void *) hci_ev->data; - report = ev->reports; - - report->data_len = min(max_data_len, datalen - offset); - - /* adjust event length */ - hci_ev->length += report->data_len; - report->rssi = hdr->rxinfo.rssi; - - os_mbuf_copydata(om, offset, report->data_len, report->data); - offset += report->data_len; - - /* - * We need another event if either there are still some data left to - * send in current PDU or scan is not completed. There are two exceptions - * though: - * - we sent all data from this PDU and there is scan error set already; - * it may be set before entering current function due to failed aux - * scan scheduling - * - this is a scannable event which is not a scan response - */ - need_event = ((offset < datalen) || (aux_data && !(aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_COMPLETE))) && - !((offset == datalen) && (aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR)) && - !is_scannable_aux; - - if (need_event) { - /* - * We will need another event so let's try to allocate one now. If - * we cannot do this, need to mark event as truncated. - */ - hci_ev_next = ble_ll_scan_get_ext_adv_report(report); - - if (hci_ev_next) { - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_INCOMPLETE; - rc = 1; - } else { - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; - rc = -1; - } - } else if (aux_data && (aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR)) { - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; - rc = -1; - } else { - rc = 0; - } - - if ((rc == -1) && aux_data) { - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - - if (!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY)) { - ble_hci_trans_buf_free((uint8_t *)hci_ev); - goto done; - } - - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED; - } else if (!is_scannable_aux) { - /* - * We do not set 'sent' flags for scannable AUX since we only care - * about scan response that will come next. - */ - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_ANY; - if (rc == 0) { - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED; - } - } - - ble_ll_hci_event_send(hci_ev); - - hci_ev = hci_ev_next; - } while ((offset < datalen) && hci_ev); - - BLE_LL_ASSERT(offset <= datalen); - - if (aux_data) { - /* Store any event left for later use */ - aux_data->evt = hci_ev; - } else { - /* If it is empty beacon, evt shall be NULL */ - BLE_LL_ASSERT(!hci_ev); - } - -done: - if (!aux_data) { - return rc; - } - - if (rc == 0) { - if (aux_data->evt_type & BLE_HCI_ADV_SCAN_RSP_MASK) { - /* Complete scan response can be added to duplicates list */ - ble_ll_scan_add_scan_rsp_adv(aux_data->adva, aux_data->adva_type, - 1, aux_data->adi); - } else if (is_scannable_aux) { - /* - * Scannable AUX is marked as incomplete because we do not want to - * add this to duplicates list now, this should happen only after - * we receive complete scan response. The drawback here is that we - * will keep receiving reports for scannable PDUs until complete - * scan response is received. - * - * XXX ^^ extend duplicates list to fix - */ - rc = 1; - } - } else if (rc < 0) { - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - } - - return rc; -} -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) -static void -ble_ll_scan_check_periodic_sync(const struct os_mbuf *om, struct ble_mbuf_hdr *rxhdr, - uint8_t *adva, uint8_t adva_type, int rpa_index) -{ - uint8_t pdu_len; - uint8_t ext_hdr_len; - uint8_t ext_hdr_flags; - uint8_t *ext_hdr; - uint8_t *rxbuf = om->om_data; - uint8_t sid; - int i; - - pdu_len = rxbuf[1]; - if (pdu_len == 0) { - return; - } - - ext_hdr_len = rxbuf[2] & 0x3F; - - if (ext_hdr_len) { - ext_hdr_flags = rxbuf[3]; - ext_hdr = &rxbuf[4]; - i = 0; - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - i += BLE_LL_EXT_ADV_ADVA_SIZE; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - i += BLE_LL_EXT_ADV_TARGETA_SIZE; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { - i += 1; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { - sid = (get_le16(ext_hdr + i) >> 12); - i += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - } else { - /* ADI is mandatory */ - return; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { - i += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { - ble_ll_sync_info_event(adva, adva_type, rpa_index, sid, rxhdr, - ext_hdr + i); - } - } -} -#endif - -static inline void -ble_ll_scan_dup_move_to_head(struct ble_ll_scan_dup_entry *e) -{ - if (e != TAILQ_FIRST(&g_scan_dup_list)) { - TAILQ_REMOVE(&g_scan_dup_list, e, link); - TAILQ_INSERT_HEAD(&g_scan_dup_list, e, link); - } -} - -static inline struct ble_ll_scan_dup_entry * -ble_ll_scan_dup_new(void) -{ - struct ble_ll_scan_dup_entry *e; - - e = os_memblock_get(&g_scan_dup_pool); - if (!e) { - e = TAILQ_LAST(&g_scan_dup_list, ble_ll_scan_dup_list); - TAILQ_REMOVE(&g_scan_dup_list, e, link); - } - - memset(e, 0, sizeof(*e)); - - return e; -} - -static int -ble_ll_scan_dup_check_legacy(uint8_t addr_type, uint8_t *addr, uint8_t pdu_type) -{ - struct ble_ll_scan_dup_entry *e; - uint8_t type; - int rc; - - type = BLE_LL_SCAN_ENTRY_TYPE_LEGACY(addr_type); - - TAILQ_FOREACH(e, &g_scan_dup_list, link) { - if ((e->type == type) && !memcmp(e->addr, addr, 6)) { - break; - } - } - - if (e) { - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_DIRECT_IND) { - rc = e->flags & BLE_LL_SCAN_DUP_F_DIR_ADV_REPORT_SENT; - } else if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_RSP) { - rc = e->flags & BLE_LL_SCAN_DUP_F_SCAN_RSP_SENT; - } else { - rc = e->flags & BLE_LL_SCAN_DUP_F_ADV_REPORT_SENT; - } - - ble_ll_scan_dup_move_to_head(e); - } else { - rc = 0; - - e = ble_ll_scan_dup_new(); - e->flags = 0; - e->type = type; - memcpy(e->addr, addr, 6); - - TAILQ_INSERT_HEAD(&g_scan_dup_list, e, link); - } - - return rc; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static int -ble_ll_scan_dup_check_ext(uint8_t addr_type, uint8_t *addr, - struct ble_ll_aux_data *aux_data) -{ - struct ble_ll_scan_dup_entry *e; - bool has_aux; - bool is_anon; - uint16_t adi; - uint8_t type; - int rc; - - has_aux = aux_data != NULL; - is_anon = addr == NULL; - adi = has_aux ? aux_data->adi : 0; - - type = BLE_LL_SCAN_ENTRY_TYPE_EXT(addr_type, has_aux, is_anon, adi); - - TAILQ_FOREACH(e, &g_scan_dup_list, link) { - if ((e->type == type) && - (is_anon || !memcmp(e->addr, addr, BLE_DEV_ADDR_LEN))) { - break; - } - } - - if (e) { - if (e->adi != adi) { - rc = 0; - - e->flags = 0; - e->adi = adi; - } else { - rc = e->flags & BLE_LL_SCAN_DUP_F_ADV_REPORT_SENT; - } - - ble_ll_scan_dup_move_to_head(e); - } else { - rc = 0; - - e = ble_ll_scan_dup_new(); - e->flags = 0; - e->type = type; - e->adi = adi; - if (!is_anon) { - memcpy(e->addr, addr, 6); - } - - TAILQ_INSERT_HEAD(&g_scan_dup_list, e, link); - } - - return rc; -} - -static int -ble_ll_scan_dup_update_ext(uint8_t addr_type, uint8_t *addr, - struct ble_ll_aux_data *aux_data) -{ - struct ble_ll_scan_dup_entry *e; - bool has_aux; - bool is_anon; - uint16_t adi; - uint8_t type; - - has_aux = aux_data != NULL; - is_anon = addr == NULL; - adi = has_aux ? aux_data->adi : 0; - - type = BLE_LL_SCAN_ENTRY_TYPE_EXT(addr_type, has_aux, is_anon, adi); - - /* - * We assume ble_ll_scan_dup_check() was called before which either matched - * some entry or allocated new one and placed in on the top of queue. - */ - - e = TAILQ_FIRST(&g_scan_dup_list); - BLE_LL_ASSERT(e && e->type == type && (is_anon || !memcmp(e->addr, addr, 6))); - - e->flags |= BLE_LL_SCAN_DUP_F_ADV_REPORT_SENT; - - return 0; -} -#endif - -static void -ble_ll_scan_rx_pkt_in_restore_addr_data(struct ble_mbuf_hdr *hdr, - struct ble_ll_scan_addr_data *addrd) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - struct ble_ll_resolv_entry *rl; -#endif - - addrd->adv_addr = addrd->adva; - addrd->adv_addr_type = addrd->adva_type; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (rxinfo->rpa_index >= 0) { - rl = &g_ble_ll_resolv_list[rxinfo->rpa_index]; - addrd->adv_addr = rl->rl_identity_addr; - addrd->adv_addr_type = rl->rl_addr_type; - addrd->rl = rl; - } - if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_TARGETA_RESOLVED) { - addrd->targeta = ble_ll_get_our_devaddr(scansm->own_addr_type & 1); - addrd->targeta_type = scansm->own_addr_type & 1; - } -#endif -} - -static void -ble_ll_scan_rx_pkt_in_on_legacy(uint8_t pdu_type, struct os_mbuf *om, - struct ble_mbuf_hdr *hdr, - struct ble_ll_scan_addr_data *addrd) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - uint8_t *rxbuf = om->om_data; - bool send_hci_report; - - - if (!BLE_MBUF_HDR_DEVMATCH(hdr) || - !BLE_MBUF_HDR_CRC_OK(hdr) || - BLE_MBUF_HDR_IGNORED(hdr) || - !scansm->scan_enabled) { - return; - } - - ble_ll_scan_get_addr_data_from_legacy(pdu_type, rxbuf, addrd); - ble_ll_scan_rx_pkt_in_restore_addr_data(hdr, addrd); - - send_hci_report = !scansm->scan_filt_dups || - !ble_ll_scan_dup_check_legacy(addrd->adv_addr_type, - addrd->adv_addr, - pdu_type); - if (send_hci_report) { - /* Sending advertising report will also update scan_dup list */ - ble_ll_scan_send_adv_report(pdu_type, - addrd->adv_addr, addrd->adv_addr_type, - addrd->targeta, addrd->targeta_type, - om, hdr, scansm); - } - - if (BLE_MBUF_HDR_SCAN_RSP_RXD(hdr)) { - ble_ll_scan_req_backoff(scansm, 1); - } -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_scan_rx_pkt_in_on_aux(uint8_t pdu_type, struct os_mbuf *om, - struct ble_mbuf_hdr *hdr, - struct ble_ll_scan_addr_data *addrd) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - uint8_t *rxbuf = om->om_data; -#endif - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - struct ble_ll_aux_data *aux_data = rxinfo->user_data; - bool send_hci_report; - int rc; - - if (aux_data) { - aux_data->flags_ll |= aux_data->flags_isr; - } - - /* - * For every new extended advertising event scanned, rx_isr_end will either - * allocate new aux_data or set 'invalid' flag. This means if no 'invalid' - * flag is set, aux_data is always valid. - */ - - /* Drop on scan error or if we received not what we expected to receive */ - if (!BLE_MBUF_HDR_CRC_OK(hdr) || - BLE_MBUF_HDR_IGNORED(hdr) || - BLE_MBUF_HDR_AUX_INVALID(hdr) || - (aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR) || - (pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND) || - !scansm->scan_enabled) { - if (aux_data) { - ble_ll_scan_end_adv_evt(aux_data); - ble_ll_scan_aux_data_unref(aux_data); - rxinfo->user_data = NULL; - } - return; - } - - BLE_LL_ASSERT(aux_data); - - if (aux_data->flags & BLE_LL_AUX_HAS_ADVA) { - addrd->adva = aux_data->adva; - addrd->adva_type = aux_data->adva_type; - } else { - addrd->adva = NULL; - addrd->adva_type = 0; - } - if (aux_data->flags & BLE_LL_AUX_HAS_TARGETA) { - addrd->targeta = aux_data->targeta; - addrd->targeta_type = aux_data->targeta_type; - } else { - addrd->targeta = NULL; - addrd->targeta_type = 0; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - /* - * Periodic scan uses own filter list so we need to let it do own filtering - * regardless of scanner filtering. Just make sure we already have AdvA. - */ - if (ble_ll_sync_enabled() && - ((rxbuf[2] >> 6) == BLE_LL_EXT_ADV_MODE_NON_CONN) && addrd->adva && - !(aux_data->flags_ll & BLE_LL_AUX_FLAG_AUX_CHAIN_RECEIVED)) { - ble_ll_scan_check_periodic_sync(om, hdr, addrd->adva, addrd->adva_type, - rxinfo->rpa_index); - } -#endif - - /* Ignore if device was not matched by either whitelist or scan policy */ - if (!BLE_MBUF_HDR_DEVMATCH(hdr)) { - goto scan_continue; - } - - ble_ll_scan_rx_pkt_in_restore_addr_data(hdr, addrd); - - /* - * If there is AuxPtr in this PDU, we should first try to schedule scan for - * subsequent aux. - */ - if (BLE_MBUF_HDR_WAIT_AUX(hdr)) { - if (ble_ll_sched_aux_scan(hdr, scansm, aux_data)) { - rxinfo->flags &= ~BLE_MBUF_HDR_F_AUX_PTR_WAIT; - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - - /* Silently ignore if no HCI event was sent to host */ - if (!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY)) { - goto scan_continue; - } - } - - /* Ignore if this was just ADV_EXT_IND with AuxPtr, will process aux */ - if (!(aux_data->flags_ll & BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED)) { - goto scan_continue; - } - - STATS_INC(ble_ll_stats, aux_chain_cnt); - } - - send_hci_report = !scansm->scan_filt_dups || - !ble_ll_scan_dup_check_ext(addrd->adv_addr_type, - addrd->adv_addr, aux_data); - if (send_hci_report) { - rc = ble_ll_hci_send_ext_adv_report(pdu_type, - addrd->adv_addr, addrd->adv_addr_type, - addrd->targeta, addrd->targeta_type, - om, hdr); - if ((rc < 0) && BLE_MBUF_HDR_WAIT_AUX(hdr)) { - /* Data were truncated so stop scanning for subsequent auxes */ - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - - if (ble_ll_sched_rmv_elem(&aux_data->sch) == 0) { - ble_ll_scan_aux_data_unref(aux_data->sch.cb_arg); - aux_data->sch.cb_arg = NULL; - } - } else if ((rc == 0) && scansm->scan_filt_dups) { - /* Complete data were send so we can update scan_dup list */ - ble_ll_scan_dup_update_ext(addrd->adv_addr_type, addrd->adv_addr, - aux_data); - } - } - - if (BLE_MBUF_HDR_SCAN_RSP_RXD(hdr)) { - /* - * For now assume success if we just received direct scan response, - * don't care about complete aux chain. - */ - ble_ll_scan_req_backoff(scansm, 1); - } - -scan_continue: - ble_ll_scan_aux_data_unref(rxinfo->user_data); - rxinfo->user_data = NULL; -} -#endif - -/** - * Process a received PDU while in the scanning state. - * - * Context: Link Layer task. - * - * @param pdu_type - * @param rxbuf - */ -void -ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hdr) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - struct ble_ll_aux_data *aux_data = rxinfo->user_data; -#endif - struct ble_ll_scan_addr_data addrd; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (aux_data || (ptype == BLE_ADV_PDU_TYPE_ADV_EXT_IND)) { - ble_ll_scan_rx_pkt_in_on_aux(ptype, om, hdr, &addrd); - ble_ll_scan_chk_resume(); - return; - } -#endif - - ble_ll_scan_rx_pkt_in_on_legacy(ptype, om, hdr, &addrd); - ble_ll_scan_chk_resume(); -} - -int -ble_ll_scan_set_scan_params(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_scan_params_cp *cmd = (const void *)cmdbuf; - uint16_t scan_itvl; - uint16_t scan_window; - struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* If already enabled, we return an error */ - scansm = &g_ble_ll_scan_sm; - if (scansm->scan_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* Get the scan interval and window */ - scan_itvl = le16toh(cmd->scan_itvl); - scan_window = le16toh(cmd->scan_window); - - /* Check scan type */ - if ((cmd->scan_type != BLE_HCI_SCAN_TYPE_PASSIVE) && - (cmd->scan_type != BLE_HCI_SCAN_TYPE_ACTIVE)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check interval and window */ - if ((scan_itvl < BLE_HCI_SCAN_ITVL_MIN) || - (scan_itvl > BLE_HCI_SCAN_ITVL_MAX) || - (scan_window < BLE_HCI_SCAN_WINDOW_MIN) || - (scan_window > BLE_HCI_SCAN_WINDOW_MAX) || - (scan_itvl < scan_window)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check own addr type */ - if (cmd->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check scanner filter policy */ - if (cmd->filter_policy > BLE_HCI_SCAN_FILT_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Store scan parameters */ - scanp = &g_ble_ll_scan_params[PHY_UNCODED]; - scanp->configured = 1; - scanp->scan_type = cmd->scan_type; - scanp->timing.interval = ble_ll_scan_time_hci_to_ticks(scan_itvl); - scanp->timing.window = ble_ll_scan_time_hci_to_ticks(scan_window); - scanp->scan_filt_policy = cmd->filter_policy; - scanp->own_addr_type = cmd->own_addr_type; - -#if (BLE_LL_SCAN_PHY_NUMBER == 2) - g_ble_ll_scan_params[PHY_CODED].configured = 0; -#endif - - return 0; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static int -ble_ll_check_scan_params(uint8_t type, uint16_t itvl, uint16_t window) -{ - /* Check scan type */ - if ((type != BLE_HCI_SCAN_TYPE_PASSIVE) && - (type != BLE_HCI_SCAN_TYPE_ACTIVE)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check interval and window */ - if ((itvl < BLE_HCI_SCAN_ITVL_MIN) || - (itvl > BLE_HCI_SCAN_ITVL_MAX) || - (window < BLE_HCI_SCAN_WINDOW_MIN) || - (window > BLE_HCI_SCAN_WINDOW_MAX) || - (itvl < window)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return 0; -} - -int -ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_ext_scan_params_cp *cmd = (const void *) cmdbuf; - const struct scan_params *params = cmd->scans; - - struct ble_ll_scan_params new_params[BLE_LL_SCAN_PHY_NUMBER] = { }; - struct ble_ll_scan_params *uncoded = &new_params[PHY_UNCODED]; - struct ble_ll_scan_params *coded = &new_params[PHY_CODED]; - uint16_t interval; - uint16_t window; - int rc; - - if (len <= sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - len -= sizeof(*cmd); - - /* If already enabled, we return an error */ - if (g_ble_ll_scan_sm.scan_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* Check own addr type */ - if (cmd->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - coded->own_addr_type = cmd->own_addr_type; - uncoded->own_addr_type = cmd->own_addr_type; - - /* Check scanner filter policy */ - if (cmd->filter_policy > BLE_HCI_SCAN_FILT_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - coded->scan_filt_policy = cmd->filter_policy; - uncoded->scan_filt_policy = cmd->filter_policy; - - /* Check if no reserved bits in PHYS are set and that at least one valid PHY - * is set. - */ - if (!(cmd->phys & SCAN_VALID_PHY_MASK) || - (cmd->phys & ~SCAN_VALID_PHY_MASK)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (cmd->phys & BLE_HCI_LE_PHY_1M_PREF_MASK) { - if (len < sizeof(*params)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - interval = le16toh(params->itvl); - window = le16toh(params->window); - - rc = ble_ll_check_scan_params(params->type, interval, window); - if (rc) { - return rc; - } - - uncoded->scan_type = params->type; - uncoded->timing.interval = ble_ll_scan_time_hci_to_ticks(interval); - uncoded->timing.window = ble_ll_scan_time_hci_to_ticks(window); - - /* That means user wants to use this PHY for scanning */ - uncoded->configured = 1; - params++; - len -= sizeof(*params); - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - if (cmd->phys & BLE_HCI_LE_PHY_CODED_PREF_MASK) { - if (len < sizeof(*params)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - interval = le16toh(params->itvl); - window = le16toh(params->window); - - rc = ble_ll_check_scan_params(params->type, interval, window); - if (rc) { - return rc; - } - - coded->scan_type = params->type; - coded->timing.interval = ble_ll_scan_time_hci_to_ticks(interval); - coded->timing.window = ble_ll_scan_time_hci_to_ticks(window); - - /* That means user wants to use this PHY for scanning */ - coded->configured = 1; - } -#endif - - /* if any of PHYs is configured for continuous scan we alter interval to - * fit other PHY - */ - if (coded->configured && uncoded->configured) { - if (coded->timing.interval == coded->timing.window) { - coded->timing.interval += uncoded->timing.window; - } - - if (uncoded->timing.interval == uncoded->timing.window) { - uncoded->timing.window += coded->timing.window; - } - } - - memcpy(g_ble_ll_scan_params, new_params, sizeof(new_params)); - - return 0; -} - -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_scan_duration_period_timers_restart(struct ble_ll_scan_sm *scansm) -{ - uint32_t now; - - now = os_cputime_get32(); - - os_cputime_timer_stop(&scansm->duration_timer); - os_cputime_timer_stop(&scansm->period_timer); - - if (scansm->duration_ticks) { - os_cputime_timer_start(&scansm->duration_timer, - now + scansm->duration_ticks); - - if (scansm->period_ticks) { - os_cputime_timer_start(&scansm->period_timer, - now + scansm->period_ticks); - } - } -} - -static void -ble_ll_scan_duration_timer_cb(void *arg) -{ - struct ble_ll_scan_sm *scansm; - - scansm = (struct ble_ll_scan_sm *)arg; - - ble_ll_scan_sm_stop(2); - - /* if period is set both timers get started from period cb */ - if (!scansm->period_ticks) { - ble_ll_hci_ev_send_scan_timeout(); - } -} - -static void -ble_ll_scan_period_timer_cb(void *arg) -{ - struct ble_ll_scan_sm *scansm = arg; - - ble_ll_scan_sm_start(scansm); - - /* always start timer regardless of ble_ll_scan_sm_start result - * if it failed will restart in next period - */ - ble_ll_scan_duration_period_timers_restart(scansm); -} -#endif - -/** - * ble ll scan set enable - * - * HCI scan set enable command processing function - * - * Context: Link Layer task (HCI Command parser). - * - * @return int BLE error code. - */ -static int -ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, - uint16_t dur, bool ext) -{ - int rc; - struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; - struct ble_ll_scan_params *scanp_phy; - int i; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - uint32_t period_ticks = 0; - uint32_t dur_ticks = 0; -#endif - - /* Check for valid parameters */ - if ((filter_dups > 1) || (enable > 1)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - scansm = &g_ble_ll_scan_sm; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* we can do that here since value will never change until reset */ - scansm->ext_scanning = ext; - - if (ext) { - /* Period parameter is ignored when the Duration parameter is zero */ - if (!dur) { - period = 0; - } - - /* period is in 1.28 sec units - * TODO support full range, would require os_cputime milliseconds API - */ - if (period > 3355) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - period_ticks = os_cputime_usecs_to_ticks(period * 1280000); - - /* duration is in 10ms units */ - dur_ticks = os_cputime_usecs_to_ticks(dur * 10000); - - if (dur_ticks && period_ticks && (dur_ticks >= period_ticks)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - } -#endif - - /* disable*/ - if (!enable) { - if (scansm->scan_enabled) { - ble_ll_scan_sm_stop(1); - } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - os_cputime_timer_stop(&scansm->duration_timer); - os_cputime_timer_stop(&scansm->period_timer); -#endif - - return BLE_ERR_SUCCESS; - } - - /* if already enable we just need to update parameters */ - if (scansm->scan_enabled) { - /* Controller does not allow initiating and scanning.*/ - for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) { - scanp_phy = &scansm->scanp_phys[i]; - if (scanp_phy->configured && - scanp_phy->scan_type == BLE_SCAN_TYPE_INITIATE) { - return BLE_ERR_CMD_DISALLOWED; - } - } - -#if MYNEWT_VAL(BLE_LL_NUM_SCAN_DUP_ADVS) - /* update filter policy */ - scansm->scan_filt_dups = filter_dups; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* restart timers according to new settings */ - scansm->duration_ticks = dur_ticks; - scansm->period_ticks = period_ticks; - ble_ll_scan_duration_period_timers_restart(scansm); -#endif - - return BLE_ERR_SUCCESS; - } - - /* we can store those upfront regardless of start scan result since scan is - * disabled now - */ - -#if MYNEWT_VAL(BLE_LL_NUM_SCAN_DUP_ADVS) - scansm->scan_filt_dups = filter_dups; -#endif - scansm->scanp = NULL; - scansm->scanp_next = NULL; - - for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) { - scanp_phy = &scansm->scanp_phys[i]; - scanp = &g_ble_ll_scan_params[i]; - - if (!scanp->configured) { - continue; - } - - scanp_phy->configured = scanp->configured; - scanp_phy->scan_type = scanp->scan_type; - scanp_phy->timing = scanp->timing; - scanp_phy->scan_filt_policy = scanp->scan_filt_policy; - scanp_phy->own_addr_type = scanp->own_addr_type; - - if (!scansm->scanp) { - scansm->scanp = scanp_phy; - /* Take own_addr_type from the first configured PHY. - * Note: All configured PHYs shall have the same own_addr_type - */ - scansm->own_addr_type = scanp_phy->own_addr_type; - } else { - scansm->scanp_next = scanp_phy; - } - } - - /* spec is not really clear if we should use defaults in this case - * or just disallow starting scan without explicit configuration - * For now be nice to host and just use values based on LE Set Scan - * Parameters defaults. - */ - if (!scansm->scanp) { - scansm->scanp = &scansm->scanp_phys[PHY_UNCODED]; - scansm->own_addr_type = BLE_ADDR_PUBLIC; - - scanp_phy = scansm->scanp; - scanp_phy->configured = 1; - scanp_phy->scan_type = BLE_SCAN_TYPE_PASSIVE; - scanp_phy->timing.interval = - ble_ll_scan_time_hci_to_ticks(BLE_HCI_SCAN_ITVL_DEF); - scanp_phy->timing.window = - ble_ll_scan_time_hci_to_ticks(BLE_HCI_SCAN_WINDOW_DEF); - scanp_phy->scan_filt_policy = BLE_HCI_SCAN_FILT_NO_WL; - scanp_phy->own_addr_type = BLE_ADDR_PUBLIC; - } - - rc = ble_ll_scan_sm_start(scansm); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (rc == BLE_ERR_SUCCESS) { - scansm->duration_ticks = dur_ticks; - scansm->period_ticks = period_ticks; - ble_ll_scan_duration_period_timers_restart(scansm); - } -#endif - - return rc; -} - -int ble_ll_hci_scan_set_enable(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_scan_enable_cp *cmd = (const void *) cmdbuf; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return ble_ll_scan_set_enable(cmd->enable, cmd->filter_duplicates, 0, 0, - false); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int ble_ll_hci_ext_scan_set_enable(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_ext_scan_enable_cp *cmd = (const void *) cmdbuf; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return ble_ll_scan_set_enable(cmd->enable, cmd->filter_dup, - le16toh(cmd->period), le16toh(cmd->duration), - true); -} -#endif - -/** - * Checks if controller can change the whitelist. If scanning is enabled and - * using the whitelist the controller is not allowed to change the whitelist. - * - * @return int 0: not allowed to change whitelist; 1: change allowed. - */ -int -ble_ll_scan_can_chg_whitelist(void) -{ - int rc; - struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; - - scansm = &g_ble_ll_scan_sm; - scanp = scansm->scanp; - if (scansm->scan_enabled && (scanp->scan_filt_policy & 1)) { - rc = 0; - } else { - rc = 1; - } - - return rc; -} - -int -ble_ll_scan_initiator_start(struct hci_create_conn *hcc, - struct ble_ll_scan_sm **sm) -{ - struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; - int rc; - - scansm = &g_ble_ll_scan_sm; - scansm->own_addr_type = hcc->own_addr_type; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - scansm->ext_scanning = 0; -#endif - scansm->scanp = &scansm->scanp_phys[PHY_UNCODED]; - scansm->scanp_next = NULL; - - scanp = scansm->scanp; - scanp->scan_filt_policy = hcc->filter_policy; - scanp->timing.interval = ble_ll_scan_time_hci_to_ticks(hcc->scan_itvl); - scanp->timing.window = ble_ll_scan_time_hci_to_ticks(hcc->scan_window); - scanp->scan_type = BLE_SCAN_TYPE_INITIATE; - - rc = ble_ll_scan_sm_start(scansm); - if (sm == NULL) { - return rc; - } - - if (rc == BLE_ERR_SUCCESS) { - *sm = scansm; - } else { - *sm = NULL; - } - - return rc; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int -ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn *hcc, - struct ble_ll_scan_sm **sm) -{ - struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp_uncoded; - struct ble_ll_scan_params *scanp_coded; - struct hci_ext_conn_params *params; - int rc; - - scansm = &g_ble_ll_scan_sm; - scansm->own_addr_type = hcc->own_addr_type; - scansm->scanp = NULL; - scansm->scanp_next = NULL; - scansm->ext_scanning = 1; - - if (hcc->init_phy_mask & BLE_PHY_MASK_1M) { - params = &hcc->params[0]; - scanp_uncoded = &scansm->scanp_phys[PHY_UNCODED]; - - scanp_uncoded->timing.interval = ble_ll_scan_time_hci_to_ticks(params->scan_itvl); - scanp_uncoded->timing.window = ble_ll_scan_time_hci_to_ticks(params->scan_window); - scanp_uncoded->scan_type = BLE_SCAN_TYPE_INITIATE; - scanp_uncoded->scan_filt_policy = hcc->filter_policy; - scansm->scanp = scanp_uncoded; - } - - if (hcc->init_phy_mask & BLE_PHY_MASK_CODED) { - params = &hcc->params[2]; - scanp_coded = &scansm->scanp_phys[PHY_CODED]; - - scanp_coded->timing.interval = ble_ll_scan_time_hci_to_ticks(params->scan_itvl); - scanp_coded->timing.window = ble_ll_scan_time_hci_to_ticks(params->scan_window); - scanp_coded->scan_type = BLE_SCAN_TYPE_INITIATE; - scanp_coded->scan_filt_policy = hcc->filter_policy; - if (scansm->scanp) { - scansm->scanp_next = scanp_coded; - } else { - scansm->scanp = scanp_coded; - } - } - - /* if any of PHYs is configured for continuous scan we alter interval to - * fit other PHY - */ - if (scansm->scanp && scansm->scanp_next && scanp_coded->configured && - scanp_uncoded->configured) { - if (scanp_coded->timing.interval == scanp_coded->timing.window) { - scanp_coded->timing.interval += scanp_uncoded->timing.window; - } - - if (scanp_uncoded->timing.interval == scanp_uncoded->timing.window) { - scanp_uncoded->timing.interval += scanp_coded->timing.window; - } - } - - rc = ble_ll_scan_sm_start(scansm); - if (sm == NULL) { - return rc; - } - - if (rc == BLE_ERR_SUCCESS) { - *sm = scansm; - } else { - *sm = NULL; - } - - return rc; -} -#endif - -/** - * Checks to see if the scanner is enabled. - * - * @return int 0: not enabled; enabled otherwise - */ -int -ble_ll_scan_enabled(void) -{ - return (int)g_ble_ll_scan_sm.scan_enabled; -} - -/** - * Returns the peer resolvable private address of last device connecting to us - * - * @return uint8_t* - */ -uint8_t * -ble_ll_scan_get_peer_rpa(void) -{ - struct ble_ll_scan_sm *scansm; - - /* XXX: should this go into IRK list or connection? */ - scansm = &g_ble_ll_scan_sm; - return scansm->scan_peer_rpa; -} - -/** - * Returns the local resolvable private address currently being using by - * the scanner/initiator - * - * @return uint8_t* - */ -uint8_t * -ble_ll_scan_get_local_rpa(void) -{ - return g_ble_ll_scan_sm.pdu_data.scana; -} - -/** - * Set the Resolvable Private Address in the scanning (or initiating) state - * machine. - * - * XXX: should this go into IRK list or connection? - * - * @param rpa - */ -void -ble_ll_scan_set_peer_rpa(uint8_t *rpa) -{ - struct ble_ll_scan_sm *scansm; - - scansm = &g_ble_ll_scan_sm; - memcpy(scansm->scan_peer_rpa, rpa, BLE_DEV_ADDR_LEN); -} - -struct ble_ll_scan_pdu_data * -ble_ll_scan_get_pdu_data(void) -{ - return &g_ble_ll_scan_sm.pdu_data; -} - -/* Returns true if whitelist is enabled for scanning */ -int -ble_ll_scan_whitelist_enabled(void) -{ - return g_ble_ll_scan_sm.scanp->scan_filt_policy & 1; -} - -static void -ble_ll_scan_common_init(void) -{ - struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; - int i; - - /* Clear state machine in case re-initialized */ - scansm = &g_ble_ll_scan_sm; - memset(scansm, 0, sizeof(struct ble_ll_scan_sm)); - - /* Clear scan parameters in case re-initialized */ - memset(g_ble_ll_scan_params, 0, sizeof(g_ble_ll_scan_params)); - - /* Initialize scanning window end event */ - ble_npl_event_init(&scansm->scan_sched_ev, ble_ll_scan_event_proc, scansm); - - for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) { - /* Set all non-zero default parameters */ - scanp = &g_ble_ll_scan_params[i]; - scanp->timing.interval = - ble_ll_scan_time_hci_to_ticks(BLE_HCI_SCAN_ITVL_DEF); - scanp->timing.window = - ble_ll_scan_time_hci_to_ticks(BLE_HCI_SCAN_WINDOW_DEF); - } - - scansm->scanp_phys[PHY_UNCODED].phy = BLE_PHY_1M; -#if (BLE_LL_SCAN_PHY_NUMBER == 2) - scansm->scanp_phys[PHY_CODED].phy = BLE_PHY_CODED; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* Make sure we'll generate new NRPA if necessary */ - scansm->scan_nrpa_timer = ble_npl_time_get(); -#endif - - /* Initialize scanning timer */ - os_cputime_timer_init(&scansm->scan_timer, ble_ll_scan_timer_cb, scansm); - - /* Initialize extended scan timers */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - os_cputime_timer_init(&scansm->duration_timer, - ble_ll_scan_duration_timer_cb, scansm); - os_cputime_timer_init(&scansm->period_timer, ble_ll_scan_period_timer_cb, - scansm); -#endif - - ble_npl_event_init(&scansm->scan_interrupted_ev, ble_ll_scan_interrupted_event_cb, NULL); -} - -/** - * Called when the controller receives the reset command. Resets the - * scanning state machine to its initial state. - * - * @return int - */ -void -ble_ll_scan_reset(void) -{ - struct ble_ll_scan_sm *scansm; - - scansm = &g_ble_ll_scan_sm; - - /* If enabled, stop it. */ - if (scansm->scan_enabled) { - ble_ll_scan_sm_stop(0); - } - - /* stop extended scan timers */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - os_cputime_timer_stop(&scansm->duration_timer); - os_cputime_timer_stop(&scansm->period_timer); -#endif - - /* Reset duplicate advertisers and those from which we rxd a response */ - g_ble_ll_scan_num_rsp_advs = 0; - memset(&g_ble_ll_scan_rsp_advs[0], 0, sizeof(g_ble_ll_scan_rsp_advs)); - - os_mempool_clear(&g_scan_dup_pool); - TAILQ_INIT(&g_scan_dup_list); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* clear memory pool for AUX scan results */ - os_mempool_clear(&ext_scan_aux_pool); -#endif - - /* Call the common init function again */ - ble_ll_scan_common_init(); -} - -/** - * ble ll scan init - * - * Initialize a scanner. Must be called before scanning can be started. - * Expected to be called with a un-initialized scanning state machine. - */ -void -ble_ll_scan_init(void) -{ - os_error_t err; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - err = os_mempool_init(&ext_scan_aux_pool, - MYNEWT_VAL(BLE_LL_EXT_ADV_AUX_PTR_CNT), - sizeof (struct ble_ll_aux_data), - ext_scan_aux_mem, - "ble_ll_aux_scan_pool"); - BLE_LL_ASSERT(err == 0); -#endif - - err = os_mempool_init(&g_scan_dup_pool, - MYNEWT_VAL(BLE_LL_NUM_SCAN_DUP_ADVS), - sizeof(struct ble_ll_scan_dup_entry), - g_scan_dup_mem, - "ble_ll_scan_dup_pool"); - BLE_LL_ASSERT(err == 0); - - TAILQ_INIT(&g_scan_dup_list); - - ble_ll_scan_common_init(); -} - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_sched.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_sched.c deleted file mode 100644 index dbe53e15c..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_sched.c +++ /dev/null @@ -1,1838 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include -#include -#include -#include "nimble/porting/nimble/include/os/os.h" -#include "nimble/porting/nimble/include/os/os_cputime.h" - -#if defined(ARDUINO_ARCH_NRF5) && defined(NRF51) -#include "nimble/nimble/drivers/nrf51/include/ble/xcvr.h" -#elif defined(ARDUINO_ARCH_NRF5) && defined(NRF52_SERIES) -#include "nimble/nimble/drivers/nrf52/include/ble/xcvr.h" -#endif - -#include "../include/controller/ble_phy.h" -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_sched.h" -#include "../include/controller/ble_ll_adv.h" -#include "../include/controller/ble_ll_scan.h" -#include "../include/controller/ble_ll_rfmgmt.h" -#include "../include/controller/ble_ll_trace.h" -#include "../include/controller/ble_ll_sync.h" -#include "ble_ll_priv.h" -#include "ble_ll_conn_priv.h" - -/* XXX: this is temporary. Not sure what I want to do here */ -struct hal_timer g_ble_ll_sched_timer; - -uint8_t g_ble_ll_sched_offset_ticks; - -#define BLE_LL_SCHED_ADV_WORST_CASE_USECS \ - (BLE_LL_SCHED_MAX_ADV_PDU_USECS + BLE_LL_IFS + BLE_LL_SCHED_ADV_MAX_USECS \ - + XCVR_TX_SCHED_DELAY_USECS) - -#if (BLE_LL_SCHED_DEBUG == 1) -int32_t g_ble_ll_sched_max_late; -int32_t g_ble_ll_sched_max_early; -#endif - -/* XXX: TODO: - * 1) Add some accounting to the schedule code to see how late we are - * (min/max?) - * - * 2) Need to determine how we really want to handle the case when we execute - * a schedule item but there is a current event. We could: - * -> Reschedule the schedule item and let current event finish - * -> Kill the current event and run the scheduled item. - * -> Disable schedule timer while in an event; could cause us to be late. - * -> Wait for current event to finish hoping it does before schedule item. - */ - -/* Queue for timers */ -TAILQ_HEAD(ll_sched_qhead, ble_ll_sched_item) g_ble_ll_sched_q; - -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) -struct ble_ll_sched_obj g_ble_ll_sched_data; -#endif - -/** - * Checks if two events in the schedule will overlap in time. NOTE: consecutive - * schedule items can end and start at the same time. - * - * @param s1 - * @param s2 - * - * @return int 0: dont overlap 1:overlap - */ -static int -ble_ll_sched_is_overlap(struct ble_ll_sched_item *s1, - struct ble_ll_sched_item *s2) -{ - int rc; - - rc = 1; - if (CPUTIME_LT(s1->start_time, s2->start_time)) { - /* Make sure this event does not overlap current event */ - if (CPUTIME_LEQ(s1->end_time, s2->start_time)) { - rc = 0; - } - } else { - /* Check for overlap */ - if (CPUTIME_GEQ(s1->start_time, s2->end_time)) { - rc = 0; - } - } - - return rc; -} - -/* - * Determines if the schedule item overlaps the currently running schedule - * item. We only care about connection schedule items - */ -static int -ble_ll_sched_overlaps_current(struct ble_ll_sched_item *sch) -{ - int rc; - uint32_t ce_end_time; - - rc = 0; - if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) { - ce_end_time = ble_ll_conn_get_ce_end_time(); - if (CPUTIME_GT(ce_end_time, sch->start_time)) { - rc = 1; - } - } - return rc; -} - -static int -ble_ll_sched_conn_overlap(struct ble_ll_sched_item *entry) -{ - int rc; - struct ble_ll_conn_sm *connsm; - - /* Should only be advertising or a connection here */ - if (entry->sched_type == BLE_LL_SCHED_TYPE_CONN) { - connsm = (struct ble_ll_conn_sm *)entry->cb_arg; - entry->enqueued = 0; - TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link); - ble_ll_event_send(&connsm->conn_ev_end); - rc = 0; - } else { - rc = -1; - } - - return rc; -} - -static struct ble_ll_sched_item * -ble_ll_sched_insert_if_empty(struct ble_ll_sched_item *sch) -{ - struct ble_ll_sched_item *entry; - - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (!entry) { - TAILQ_INSERT_HEAD(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - return entry; -} - -int -ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm) -{ - int rc; - os_sr_t sr; - uint32_t usecs; - struct ble_ll_sched_item *sch; - struct ble_ll_sched_item *start_overlap; - struct ble_ll_sched_item *end_overlap; - struct ble_ll_sched_item *entry; - struct ble_ll_conn_sm *tmp; - - /* Get schedule element from connection */ - sch = &connsm->conn_sch; - - /* Set schedule start and end times */ - sch->start_time = connsm->anchor_point - g_ble_ll_sched_offset_ticks; - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - usecs = connsm->slave_cur_window_widening; - sch->start_time -= (os_cputime_usecs_to_ticks(usecs) + 1); - sch->remainder = 0; - } else { - sch->remainder = connsm->anchor_point_usecs; - } - sch->end_time = connsm->ce_end_time; - - /* Better be past current time or we just leave */ - if (CPUTIME_LT(sch->start_time, os_cputime_get32())) { - return -1; - } - - /* We have to find a place for this schedule */ - OS_ENTER_CRITICAL(sr); - - if (ble_ll_sched_overlaps_current(sch)) { - OS_EXIT_CRITICAL(sr); - return -1; - } - - /* Stop timer since we will add an element */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - - start_overlap = NULL; - end_overlap = NULL; - rc = 0; - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - if (ble_ll_sched_is_overlap(sch, entry)) { - if (entry->sched_type == BLE_LL_SCHED_TYPE_CONN && - !ble_ll_conn_is_lru((struct ble_ll_conn_sm *)sch->cb_arg, - (struct ble_ll_conn_sm *)entry->cb_arg)) { - /* Only insert if this element is older than all that we - * overlap - */ - start_overlap = NULL; - rc = -1; - break; - } - - if (start_overlap == NULL) { - start_overlap = entry; - end_overlap = entry; - } else { - end_overlap = entry; - } - } else { - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - break; - } - } - } - - if (!rc) { - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - sch->enqueued = 1; - } - - /* Remove first to last scheduled elements */ - entry = start_overlap; - while (entry) { - start_overlap = TAILQ_NEXT(entry,link); - switch (entry->sched_type) { - case BLE_LL_SCHED_TYPE_CONN: - tmp = (struct ble_ll_conn_sm *)entry->cb_arg; - ble_ll_event_send(&tmp->conn_ev_end); - break; - case BLE_LL_SCHED_TYPE_ADV: - ble_ll_adv_event_rmvd_from_sched((struct ble_ll_adv_sm *)entry->cb_arg); - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - case BLE_LL_SCHED_TYPE_AUX_SCAN: - ble_ll_scan_end_adv_evt((struct ble_ll_aux_data *)entry->cb_arg); - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - case BLE_LL_SCHED_TYPE_PERIODIC: - ble_ll_adv_periodic_rmvd_from_sched((struct ble_ll_adv_sm *)entry->cb_arg); - break; - case BLE_LL_SCHED_TYPE_SYNC: - ble_ll_sync_rmvd_from_sched((struct ble_ll_sync_sm *)entry->cb_arg); - break; -#endif -#endif - default: - BLE_LL_ASSERT(0); - break; - } - - TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link); - entry->enqueued = 0; - - if (entry == end_overlap) { - break; - } - entry = start_overlap; - } - - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (entry == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } else { - sch = entry; - } - - OS_EXIT_CRITICAL(sr); - - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - - return rc; -} - -/** - * Called to schedule a connection when the current role is master. - * - * Context: Interrupt - * - * @param connsm - * @param ble_hdr - * @param pyld_len - * - * @return int - */ -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) -int -ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, - struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len) -{ - int rc; - os_sr_t sr; - uint32_t initial_start; - uint32_t earliest_start; - uint32_t earliest_end; - uint32_t dur; - uint32_t itvl_t; - uint32_t adv_rxend; - int i; - uint32_t tpp; - uint32_t tse; - uint32_t np; - uint32_t cp; - uint32_t tick_in_period; - - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *sch; - - /* Better have a connsm */ - BLE_LL_ASSERT(connsm != NULL); - - /* Get schedule element from connection */ - rc = -1; - sch = &connsm->conn_sch; - - /* XXX: - * The calculations for the 32kHz crystal bear alot of explanation. The - * earliest possible time that the master can start the connection with a - * slave is 1.25 msecs from the end of the connection request. The - * connection request is sent an IFS time from the end of the advertising - * packet that was received plus the time it takes to send the connection - * request. At 1 Mbps, this is 1752 usecs, or 57.41 ticks. Using 57 ticks - * makes us off ~13 usecs. Since we dont want to actually calculate the - * receive end time tick (this would take too long), we assume the end of - * the advertising PDU is 'now' (we call os_cputime_get32). We dont know - * how much time it will take to service the ISR but if we are more than the - * rx to tx time of the chip we will not be successful transmitting the - * connect request. All this means is that we presume that the slave will - * receive the connect request later than we expect but no earlier than - * 13 usecs before (this is important). - * - * The code then attempts to schedule the connection at the - * earliest time although this may not be possible. When the actual - * schedule start time is determined, the master has to determine if this - * time is more than a transmit window offset interval (1.25 msecs). The - * master has to tell the slave how many transmit window offsets there are - * from the earliest possible time to when the actual transmit start will - * occur. Later in this function you will see the calculation. The actual - * transmission start has to occur within the transmit window. The transmit - * window interval is in units of 1.25 msecs and has to be at least 1. To - * make things a bit easier (but less power efficient for the slave), we - * use a transmit window of 2. We do this because we dont quite know the - * exact start of the transmission and if we are too early or too late we - * could miss the transmit window. A final note: the actual transmission - * start (the anchor point) is sched offset ticks from the schedule start - * time. We dont add this to the calculation when calculating the window - * offset. The reason we dont do this is we want to insure we transmit - * after the window offset we tell the slave. For example, say we think - * we are transmitting 1253 usecs from the earliest start. This would cause - * us to send a transmit window offset of 1. Since we are actually - * transmitting earlier than the slave thinks we could end up transmitting - * before the window offset. Transmitting later is fine since we have the - * transmit window to do so. Transmitting before is bad, since the slave - * wont be listening. We could do better calculation if we wanted to use - * a transmit window of 1 as opposed to 2, but for now we dont care. - */ - dur = os_cputime_usecs_to_ticks(g_ble_ll_sched_data.sch_ticks_per_period); - adv_rxend = os_cputime_get32(); - if (ble_hdr->rxinfo.channel >= BLE_PHY_NUM_DATA_CHANS) { - /* - * We received packet on advertising channel which means this is a legacy - * PDU on 1 Mbps - we do as described above. - */ - earliest_start = adv_rxend + 57; - } else { - /* - * The calculations are similar as above. - * - * We received packet on data channel which means this is AUX_ADV_IND - * received on secondary adv channel. We can schedule first packet at - * the earliest after "T_IFS + AUX_CONNECT_REQ + transmitWindowDelay". - * AUX_CONNECT_REQ and transmitWindowDelay times vary depending on which - * PHY we received on. - * - */ - if (ble_hdr->rxinfo.phy == BLE_PHY_1M) { - // 150 + 352 + 2500 = 3002us = 98.37 ticks - earliest_start = adv_rxend + 98; - } else if (ble_hdr->rxinfo.phy == BLE_PHY_2M) { - // 150 + 180 + 2500 = 2830us = 92.73 ticks - earliest_start = adv_rxend + 93; - } else if (ble_hdr->rxinfo.phy == BLE_PHY_CODED) { - // 150 + 2896 + 3750 = 6796us = 222.69 ticks - earliest_start = adv_rxend + 223; - } else { - BLE_LL_ASSERT(0); - } - } - earliest_start += MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET) * - BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT; - itvl_t = connsm->conn_itvl_ticks; - - /* We have to find a place for this schedule */ - OS_ENTER_CRITICAL(sr); - - /* - * Are there any allocated periods? If not, set epoch start to earliest - * time - */ - if (g_ble_ll_sched_data.sch_num_occ_periods == 0) { - g_ble_ll_sched_data.sch_epoch_start = earliest_start; - cp = 0; - } else { - /* - * Earliest start must occur on period boundary. - * (tse = ticks since epoch) - */ - tpp = g_ble_ll_sched_data.sch_ticks_per_period; - tse = earliest_start - g_ble_ll_sched_data.sch_epoch_start; - np = tse / tpp; - cp = np % BLE_LL_SCHED_PERIODS; - tick_in_period = tse - (np * tpp); - if (tick_in_period != 0) { - ++cp; - if (cp == BLE_LL_SCHED_PERIODS) { - cp = 0; - } - earliest_start += (tpp - tick_in_period); - } - - /* Now find first un-occupied period starting from cp */ - for (i = 0; i < BLE_LL_SCHED_PERIODS; ++i) { - if (g_ble_ll_sched_data.sch_occ_period_mask & (1 << cp)) { - ++cp; - if (cp == BLE_LL_SCHED_PERIODS) { - cp = 0; - } - earliest_start += tpp; - } else { - /* not occupied */ - break; - } - } - /* Should never happen but if it does... */ - if (i == BLE_LL_SCHED_PERIODS) { - OS_EXIT_CRITICAL(sr); - return rc; - } - } - - sch->start_time = earliest_start; - initial_start = earliest_start; - earliest_end = earliest_start + dur; - - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible */ - rc = 0; - connsm->tx_win_off = MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET); - } else { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* Set these because overlap function needs them to be set */ - sch->start_time = earliest_start; - sch->end_time = earliest_end; - - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - if ((earliest_start - initial_start) <= itvl_t) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - } - break; - } - - /* Check for overlapping events */ - if (ble_ll_sched_is_overlap(sch, entry)) { - /* Earliest start is end of this event since we overlap */ - earliest_start = entry->end_time; - earliest_end = earliest_start + dur; - } - } - - /* Must be able to schedule within one connection interval */ - if (!entry) { - if ((earliest_start - initial_start) <= itvl_t) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - } - - if (!rc) { - /* calculate number of window offsets. Each offset is 1.25 ms */ - sch->enqueued = 1; - /* - * NOTE: we dont add sched offset ticks as we want to under-estimate - * the transmit window slightly since the window size is currently - * 2 when using a 32768 crystal. - */ - dur = os_cputime_ticks_to_usecs(earliest_start - initial_start); - connsm->tx_win_off = dur / BLE_LL_CONN_TX_OFF_USECS; - } - } - - if (!rc) { - sch->start_time = earliest_start; - sch->end_time = earliest_end; - /* - * Since we have the transmit window to transmit in, we dont need - * to set the anchor point usecs; just transmit to the nearest tick. - */ - connsm->anchor_point = earliest_start + g_ble_ll_sched_offset_ticks; - connsm->anchor_point_usecs = 0; - connsm->ce_end_time = earliest_end; - connsm->period_occ_mask = (1 << cp); - g_ble_ll_sched_data.sch_occ_period_mask |= connsm->period_occ_mask; - ++g_ble_ll_sched_data.sch_num_occ_periods; - } - - - /* Get head of list to restart timer */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - ble_ll_rfmgmt_sched_changed(sch); - - OS_EXIT_CRITICAL(sr); - - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - - return rc; -} -#else -int -ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, - struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len) -{ - int rc; - os_sr_t sr; - uint8_t req_slots; - uint32_t initial_start; - uint32_t earliest_start; - uint32_t earliest_end; - uint32_t dur; - uint32_t itvl_t; - uint32_t adv_rxend; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *sch; - - /* - * XXX: TODO this code assumes the advertisement and connect request were - * sent at 1Mbps. - */ - - /* Get schedule element from connection */ - rc = -1; - sch = &connsm->conn_sch; - req_slots = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS); - - /* XXX: - * The calculations for the 32kHz crystal bear alot of explanation. The - * earliest possible time that the master can start the connection with a - * slave is 1.25 msecs from the end of the connection request. The - * connection request is sent an IFS time from the end of the advertising - * packet that was received plus the time it takes to send the connection - * request. At 1 Mbps, this is 1752 usecs, or 57.41 ticks. Using 57 ticks - * makes us off ~13 usecs. Since we dont want to actually calculate the - * receive end time tick (this would take too long), we assume the end of - * the advertising PDU is 'now' (we call os_cputime_get32). We dont know - * how much time it will take to service the ISR but if we are more than the - * rx to tx time of the chip we will not be successful transmitting the - * connect request. All this means is that we presume that the slave will - * receive the connect request later than we expect but no earlier than - * 13 usecs before (this is important). - * - * The code then attempts to schedule the connection at the - * earliest time although this may not be possible. When the actual - * schedule start time is determined, the master has to determine if this - * time is more than a transmit window offset interval (1.25 msecs). The - * master has to tell the slave how many transmit window offsets there are - * from the earliest possible time to when the actual transmit start will - * occur. Later in this function you will see the calculation. The actual - * transmission start has to occur within the transmit window. The transmit - * window interval is in units of 1.25 msecs and has to be at least 1. To - * make things a bit easier (but less power efficient for the slave), we - * use a transmit window of 2. We do this because we dont quite know the - * exact start of the transmission and if we are too early or too late we - * could miss the transmit window. A final note: the actual transmission - * start (the anchor point) is sched offset ticks from the schedule start - * time. We dont add this to the calculation when calculating the window - * offset. The reason we dont do this is we want to insure we transmit - * after the window offset we tell the slave. For example, say we think - * we are transmitting 1253 usecs from the earliest start. This would cause - * us to send a transmit window offset of 1. Since we are actually - * transmitting earlier than the slave thinks we could end up transmitting - * before the window offset. Transmitting later is fine since we have the - * transmit window to do so. Transmitting before is bad, since the slave - * wont be listening. We could do better calculation if we wanted to use - * a transmit window of 1 as opposed to 2, but for now we dont care. - */ - dur = req_slots * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT; - adv_rxend = os_cputime_get32(); - if (ble_hdr->rxinfo.channel >= BLE_PHY_NUM_DATA_CHANS) { - /* - * We received packet on advertising channel which means this is a legacy - * PDU on 1 Mbps - we do as described above. - */ - earliest_start = adv_rxend + 57; - } else { - /* - * The calculations are similar as above. - * - * We received packet on data channel which means this is AUX_ADV_IND - * received on secondary adv channel. We can schedule first packet at - * the earliest after "T_IFS + AUX_CONNECT_REQ + transmitWindowDelay". - * AUX_CONNECT_REQ and transmitWindowDelay times vary depending on which - * PHY we received on. - * - */ - if (ble_hdr->rxinfo.phy == BLE_PHY_1M) { - // 150 + 352 + 2500 = 3002us = 98.37 ticks - earliest_start = adv_rxend + 98; - } else if (ble_hdr->rxinfo.phy == BLE_PHY_2M) { - // 150 + 180 + 2500 = 2830us = 92.73 ticks - earliest_start = adv_rxend + 93; - } else if (ble_hdr->rxinfo.phy == BLE_PHY_CODED) { - // 150 + 2896 + 3750 = 6796us = 222.69 ticks - earliest_start = adv_rxend + 223; - } else { - BLE_LL_ASSERT(0); - } - } - earliest_start += MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET) * - BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT; - earliest_end = earliest_start + dur; - itvl_t = connsm->conn_itvl_ticks; - - /* We have to find a place for this schedule */ - OS_ENTER_CRITICAL(sr); - - /* The schedule item must occur after current running item (if any) */ - sch->start_time = earliest_start; - initial_start = earliest_start; - - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible */ - rc = 0; - connsm->tx_win_off = MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET); - } else { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* Set these because overlap function needs them to be set */ - sch->start_time = earliest_start; - sch->end_time = earliest_end; - - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - if ((earliest_start - initial_start) <= itvl_t) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - } - break; - } - - /* Check for overlapping events */ - if (ble_ll_sched_is_overlap(sch, entry)) { - /* Earliest start is end of this event since we overlap */ - earliest_start = entry->end_time; - earliest_end = earliest_start + dur; - } - } - - /* Must be able to schedule within one connection interval */ - if (!entry) { - if ((earliest_start - initial_start) <= itvl_t) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - } - - if (!rc) { - /* calculate number of window offsets. Each offset is 1.25 ms */ - sch->enqueued = 1; - /* - * NOTE: we dont add sched offset ticks as we want to under-estimate - * the transmit window slightly since the window size is currently - * 2 when using a 32768 crystal. - */ - dur = os_cputime_ticks_to_usecs(earliest_start - initial_start); - connsm->tx_win_off = dur / BLE_LL_CONN_TX_OFF_USECS; - } - } - - if (!rc) { - sch->start_time = earliest_start; - sch->end_time = earliest_end; - /* - * Since we have the transmit window to transmit in, we dont need - * to set the anchor point usecs; just transmit to the nearest tick. - */ - connsm->anchor_point = earliest_start + g_ble_ll_sched_offset_ticks; - connsm->anchor_point_usecs = 0; - connsm->ce_end_time = earliest_end; - } - - /* Get head of list to restart timer */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - ble_ll_rfmgmt_sched_changed(sch); - - OS_EXIT_CRITICAL(sr); - - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - - return rc; -} -#endif - -/** - * Schedules a slave connection for the first time. - * - * Context: Link Layer - * - * @param connsm - * - * @return int - */ -int -ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm) -{ - int rc; - os_sr_t sr; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *next_sch; - struct ble_ll_sched_item *sch; - int first = 0; - - /* Get schedule element from connection */ - rc = -1; - sch = &connsm->conn_sch; - - /* Set schedule start and end times */ - /* - * XXX: for now, we dont care about anchor point usecs for the slave. It - * does not matter if we turn on the receiver up to one tick before w - * need to. We also subtract one extra tick since the conversion from - * usecs to ticks could be off by up to 1 tick. - */ - sch->start_time = connsm->anchor_point - g_ble_ll_sched_offset_ticks - - os_cputime_usecs_to_ticks(connsm->slave_cur_window_widening) - 1; - sch->end_time = connsm->ce_end_time; - sch->remainder = 0; - - /* We have to find a place for this schedule */ - OS_ENTER_CRITICAL(sr); - - /* The schedule item must occur after current running item (if any) */ - if (ble_ll_sched_overlaps_current(sch)) { - OS_EXIT_CRITICAL(sr); - return rc; - } - - entry = ble_ll_sched_insert_if_empty(sch); - if (!entry) { - /* Nothing in schedule. Schedule as soon as possible */ - rc = 0; - first = 1; - } else { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - while (1) { - next_sch = entry->link.tqe_next; - /* Insert if event ends before next starts */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - break; - } - - if (ble_ll_sched_is_overlap(sch, entry)) { - /* If we overlap with a connection, we re-schedule */ - if (ble_ll_sched_conn_overlap(entry)) { - break; - } - } - - /* Move to next entry */ - entry = next_sch; - - /* Insert at tail if none left to check */ - if (!entry) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - break; - } - } - - if (!rc) { - sch->enqueued = 1; - } - - next_sch = TAILQ_FIRST(&g_ble_ll_sched_q); - if (next_sch == sch) { - first = 1; - } else { - sch = next_sch; - } - } - - if (first) { - ble_ll_rfmgmt_sched_changed(sch); - } - - OS_EXIT_CRITICAL(sr); - - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - - return rc; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) -/* - * Determines if the schedule item overlaps the currently running schedule - * item. This function cares about connection and sync. - */ -static int -ble_ll_sched_sync_overlaps_current(struct ble_ll_sched_item *sch) -{ - uint32_t end_time; - uint8_t state; - - state = ble_ll_state_get(); - switch (state) { - case BLE_LL_STATE_CONNECTION: - end_time = ble_ll_conn_get_ce_end_time(); - break; - case BLE_LL_STATE_SYNC: - end_time = ble_ll_sync_get_event_end_time(); - break; - default: - return 0; - } - - return CPUTIME_GT(end_time, sch->start_time); -} - -int -ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, - uint32_t anchor_point, uint8_t anchor_point_usecs, - uint32_t window_widening, - int8_t phy_mode) -{ - struct ble_ll_sched_item *entry; - uint8_t start_time_rem_usecs; - uint8_t window_rem_usecs; - uint32_t window_ticks; - uint32_t start_time; - uint32_t end_time; - uint32_t dur; - int rc = 0; - os_sr_t sr; - - window_ticks = os_cputime_usecs_to_ticks(window_widening); - window_rem_usecs = window_widening - os_cputime_ticks_to_usecs(window_ticks); - - /* adjust for subtraction */ - anchor_point_usecs += 31; - anchor_point--; - - start_time = anchor_point - window_ticks; - start_time_rem_usecs = anchor_point_usecs - window_rem_usecs; - if (start_time_rem_usecs >= 31) { - start_time++; - start_time_rem_usecs -= 31; - } - - dur = ble_ll_pdu_tx_time_get(MYNEWT_VAL(BLE_LL_SCHED_SCAN_SYNC_PDU_LEN), - phy_mode); - end_time = start_time + os_cputime_usecs_to_ticks(dur); - - start_time -= g_ble_ll_sched_offset_ticks; - - /* Set schedule start and end times */ - sch->start_time = start_time; - sch->remainder = start_time_rem_usecs; - sch->end_time = end_time; - - /* Better be past current time or we just leave */ - if (CPUTIME_LEQ(sch->start_time, os_cputime_get32())) { - return -1; - } - - /* We have to find a place for this schedule */ - OS_ENTER_CRITICAL(sr); - - if (ble_ll_sched_sync_overlaps_current(sch)) { - OS_EXIT_CRITICAL(sr); - return -1; - } - - /* Try to find slot for sync scan. */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; - break; - } - - /* Check for overlapping events. For now drop if it overlaps with - * anything. We can make it smarter later on - */ - if (ble_ll_sched_is_overlap(sch, entry)) { - rc = -1; - break; - } - } - - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (entry == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } else { - sch = entry; - } - - OS_EXIT_CRITICAL(sr); - - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - - return rc; -} - -int -ble_ll_sched_sync(struct ble_ll_sched_item *sch, - uint32_t beg_cputime, uint32_t rem_usecs, - uint32_t offset, int8_t phy_mode) -{ - struct ble_ll_sched_item *entry; - uint32_t start_time_rem_usecs; - uint32_t off_rem_usecs; - uint32_t start_time; - uint32_t off_ticks; - uint32_t end_time; - uint32_t dur; - os_sr_t sr; - int rc = 0; - - off_ticks = os_cputime_usecs_to_ticks(offset); - off_rem_usecs = offset - os_cputime_ticks_to_usecs(off_ticks); - - start_time = beg_cputime + off_ticks; - start_time_rem_usecs = rem_usecs + off_rem_usecs; - if (start_time_rem_usecs >= 31) { - start_time++; - start_time_rem_usecs -= 31; - } - - dur = ble_ll_pdu_tx_time_get(MYNEWT_VAL(BLE_LL_SCHED_SCAN_SYNC_PDU_LEN), - phy_mode); - end_time = start_time + os_cputime_usecs_to_ticks(dur); - - start_time -= g_ble_ll_sched_offset_ticks; - - sch->start_time = start_time; - sch->remainder = start_time_rem_usecs; - sch->end_time = end_time; - - OS_ENTER_CRITICAL(sr); - - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible - * If we are here it means sch has been added to the scheduler */ - goto done; - } - - /* Try to find slot for scan. */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; - break; - } - - /* Check for overlapping events. For now drop if it overlaps with - * anything. We can make it smarter later on - */ - if (ble_ll_sched_is_overlap(sch, entry)) { - rc = -1; - break; - } - } - - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - -done: - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (entry == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } else { - sch = entry; - } - - OS_EXIT_CRITICAL(sr); - - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - - STATS_INC(ble_ll_stats, sync_scheduled); - return rc; -} -#endif - -int -ble_ll_sched_adv_new(struct ble_ll_sched_item *sch, ble_ll_sched_adv_new_cb cb, - void *arg) -{ - os_sr_t sr; - uint32_t adv_start; - uint32_t duration; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *orig; - - /* Get length of schedule item */ - duration = sch->end_time - sch->start_time; - orig = sch; - - OS_ENTER_CRITICAL(sr); - entry = ble_ll_sched_insert_if_empty(sch); - if (!entry) { - adv_start = sch->start_time; - } else { - /* XXX: no need to stop timer if not first on list. Modify code? */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - TAILQ_INSERT_BEFORE(entry, sch, link); - break; - } - - /* Check for overlapping events */ - if (ble_ll_sched_is_overlap(sch, entry)) { - /* Earliest start is end of this event since we overlap */ - sch->start_time = entry->end_time; - sch->end_time = sch->start_time + duration; - } - } - - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - adv_start = sch->start_time; - - sch->enqueued = 1; - - /* Restart with head of list */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - } - - if (cb) { - cb((struct ble_ll_adv_sm *)orig->cb_arg, adv_start, arg); - } - - if (orig == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } - - OS_EXIT_CRITICAL(sr); - - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - - return 0; -} - -int -ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, uint32_t *start, - bool after_overlap) -{ - int rc = 0; - os_sr_t sr; - uint32_t adv_start; - uint32_t duration; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *orig = sch; - - /* Get length of schedule item */ - duration = sch->end_time - sch->start_time; - - OS_ENTER_CRITICAL(sr); - entry = ble_ll_sched_insert_if_empty(sch); - if (!entry) { - adv_start = sch->start_time; - } else { - /* XXX: no need to stop timer if not first on list. Modify code? */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - TAILQ_INSERT_BEFORE(entry, sch, link); - break; - } - - /* Check for overlapping events */ - if (ble_ll_sched_is_overlap(sch, entry)) { - if (after_overlap) { - /* Earliest start is end of this event since we overlap */ - sch->start_time = entry->end_time; - sch->end_time = sch->start_time + duration; - } else { - rc = -1; - break; - } - } - } - - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - adv_start = sch->start_time; - - if (!rc) { - sch->enqueued = 1; - } - - /* Restart with head of list */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - } - - if (!rc) { - *start = adv_start; - } - - if (orig == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } - - OS_EXIT_CRITICAL(sr); - - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - - return rc; -} - -int -ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start, - uint32_t max_delay_ticks) -{ - int rc; - os_sr_t sr; - uint32_t orig_start; - uint32_t duration; - uint32_t rand_ticks; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *next_sch; - struct ble_ll_sched_item *before; - struct ble_ll_sched_item *start_overlap; - struct ble_ll_sched_item *end_overlap; - - /* Get length of schedule item */ - duration = sch->end_time - sch->start_time; - - /* Add maximum randomization delay to end */ - rand_ticks = max_delay_ticks; - sch->end_time += max_delay_ticks; - - start_overlap = NULL; - end_overlap = NULL; - before = NULL; - rc = 0; - OS_ENTER_CRITICAL(sr); - - entry = ble_ll_sched_insert_if_empty(sch); - if (entry) { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - while (1) { - next_sch = entry->link.tqe_next; - if (ble_ll_sched_is_overlap(sch, entry)) { - if (start_overlap == NULL) { - start_overlap = entry; - end_overlap = entry; - } else { - end_overlap = entry; - } - } else { - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - before = entry; - break; - } - } - - entry = next_sch; - if (entry == NULL) { - break; - } - } - - /* - * If there is no overlap, we either insert before the 'before' entry - * or we insert at the end if there is no before entry. - */ - if (start_overlap == NULL) { - if (before) { - TAILQ_INSERT_BEFORE(before, sch, link); - } else { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - } else { - /* - * This item will overlap with others. See if we can fit it in - * with original duration. - */ - before = NULL; - orig_start = sch->start_time; - entry = start_overlap; - sch->end_time = sch->start_time + duration; - while (1) { - next_sch = entry->link.tqe_next; - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - rand_ticks = entry->start_time - sch->end_time; - before = entry; - TAILQ_INSERT_BEFORE(before, sch, link); - break; - } else { - sch->start_time = entry->end_time; - sch->end_time = sch->start_time + duration; - } - - if (entry == end_overlap) { - rand_ticks = (orig_start + max_delay_ticks) - sch->start_time; - if (rand_ticks > max_delay_ticks) { - /* No place for advertisement. */ - rc = -1; - } else { - if (next_sch == NULL) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } else { - TAILQ_INSERT_BEFORE(next_sch, sch, link); - } - } - break; - } - entry = next_sch; - BLE_LL_ASSERT(entry != NULL); - } - } - } - - if (!rc) { - sch->enqueued = 1; - if (rand_ticks) { - sch->start_time += ble_ll_rand() % rand_ticks; - } - sch->end_time = sch->start_time + duration; - *start = sch->start_time; - - if (sch == TAILQ_FIRST(&g_ble_ll_sched_q)) { - ble_ll_rfmgmt_sched_changed(sch); - } - } - - OS_EXIT_CRITICAL(sr); - - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - - return rc; -} - -int -ble_ll_sched_adv_resched_pdu(struct ble_ll_sched_item *sch) -{ - uint8_t lls; - os_sr_t sr; - struct ble_ll_sched_item *entry; - - OS_ENTER_CRITICAL(sr); - - lls = ble_ll_state_get(); - if ((lls == BLE_LL_STATE_ADV) || (lls == BLE_LL_STATE_CONNECTION) || - (lls == BLE_LL_STATE_SYNC)) { - goto adv_resched_pdu_fail; - } - - entry = ble_ll_sched_insert_if_empty(sch); - if (entry) { - /* If we overlap with the first item, simply re-schedule */ - if (ble_ll_sched_is_overlap(sch, entry)) { - goto adv_resched_pdu_fail; - } - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; - } - - ble_ll_rfmgmt_sched_changed(TAILQ_FIRST(&g_ble_ll_sched_q)); - - OS_EXIT_CRITICAL(sr); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - return 0; - -adv_resched_pdu_fail: - OS_EXIT_CRITICAL(sr); - return -1; -} - -/** - * Remove a schedule element - * - * @param sched_type - * - * @return int 0 - removed, 1 - not in the list - */ -int -ble_ll_sched_rmv_elem(struct ble_ll_sched_item *sch) -{ - os_sr_t sr; - struct ble_ll_sched_item *first; - int rc = 1; - - if (!sch) { - return rc; - } - - OS_ENTER_CRITICAL(sr); - if (sch->enqueued) { - first = TAILQ_FIRST(&g_ble_ll_sched_q); - if (first == sch) { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - } - - TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 0; - rc = 0; - - if (first == sch) { - first = TAILQ_FIRST(&g_ble_ll_sched_q); - if (first) { - os_cputime_timer_start(&g_ble_ll_sched_timer, first->start_time); - } - ble_ll_rfmgmt_sched_changed(first); - } - } - OS_EXIT_CRITICAL(sr); - - return rc; -} - -void -ble_ll_sched_rmv_elem_type(uint8_t type, sched_remove_cb_func remove_cb) -{ - os_sr_t sr; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *first; - - OS_ENTER_CRITICAL(sr); - first = TAILQ_FIRST(&g_ble_ll_sched_q); - - if (!first) { - OS_EXIT_CRITICAL(sr); - return; - } - - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - if (entry->sched_type == type) { - if (first == entry) { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - first = NULL; - } - - TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link); - remove_cb(entry); - entry->enqueued = 0; - } - } - - if (!first) { - first = TAILQ_FIRST(&g_ble_ll_sched_q); - if (first) { - os_cputime_timer_start(&g_ble_ll_sched_timer, first->start_time); - } - ble_ll_rfmgmt_sched_changed(first); - } - - OS_EXIT_CRITICAL(sr); -} - -/** - * Executes a schedule item by calling the schedule callback function. - * - * Context: Interrupt - * - * @param sch Pointer to schedule item - * - * @return int 0: schedule item is not over; otherwise schedule item is done. - */ -static int -ble_ll_sched_execute_item(struct ble_ll_sched_item *sch) -{ - int rc; - uint8_t lls; - - lls = ble_ll_state_get(); - - ble_ll_trace_u32x3(BLE_LL_TRACE_ID_SCHED, lls, os_cputime_get32(), - sch->start_time); - - if (lls == BLE_LL_STATE_STANDBY) { - goto sched; - } - - /* If aux scan scheduled and LL is in state when scanner is running - * in 3 states: - * BLE_LL_STATE_SCANNING - * BLE_LL_STATE_INITIATING - * BLE_LL_STATE_STANDBY - * - * Let scanner to decide to disable phy or not. - */ - if (sch->sched_type == BLE_LL_SCHED_TYPE_AUX_SCAN) { - if (lls == BLE_LL_STATE_INITIATING || lls == BLE_LL_STATE_SCANNING) { - goto sched; - } - } - - /* - * This is either an advertising event or connection event start. If - * we are scanning or initiating just stop it. - */ - - /* We have to disable the PHY no matter what */ - ble_phy_disable(); - - if (lls == BLE_LL_STATE_SCANNING) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - ble_ll_scan_halt(); - } else if (lls == BLE_LL_STATE_INITIATING) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - ble_ll_scan_halt(); - /* PHY is disabled - make sure we do not wait for AUX_CONNECT_RSP */ - ble_ll_conn_reset_pending_aux_conn_rsp(); - } else if (lls == BLE_LL_STATE_ADV) { - STATS_INC(ble_ll_stats, sched_state_adv_errs); - ble_ll_adv_halt(); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - } else if (lls == BLE_LL_STATE_SYNC) { - STATS_INC(ble_ll_stats, sched_state_sync_errs); - ble_ll_sync_halt(); -#endif - } else { - STATS_INC(ble_ll_stats, sched_state_conn_errs); - ble_ll_conn_event_halt(); - } - -sched: - BLE_LL_DEBUG_GPIO(SCHED_ITEM_CB, 1); - BLE_LL_ASSERT(sch->sched_cb); - rc = sch->sched_cb(sch); - BLE_LL_DEBUG_GPIO(SCHED_ITEM_CB, 0); - return rc; -} - -/** - * Run the BLE scheduler. Iterate through all items on the schedule queue. - * - * Context: interrupt (scheduler) - * - * @return int - */ -static void -ble_ll_sched_run(void *arg) -{ - struct ble_ll_sched_item *sch; - - BLE_LL_DEBUG_GPIO(SCHED_RUN, 1); - - /* Look through schedule queue */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - if (sch) { -#if (BLE_LL_SCHED_DEBUG == 1) - int32_t dt; - - /* Make sure we have passed the start time of the first event */ - dt = (int32_t)(os_cputime_get32() - sch->start_time); - if (dt > g_ble_ll_sched_max_late) { - g_ble_ll_sched_max_late = dt; - } - if (dt < g_ble_ll_sched_max_early) { - g_ble_ll_sched_max_early = dt; - } -#endif - - /* Remove schedule item and execute the callback */ - TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 0; - ble_ll_sched_execute_item(sch); - - /* Restart if there is an item on the schedule */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - if (sch) { - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - } - ble_ll_rfmgmt_sched_changed(sch); - } - - BLE_LL_DEBUG_GPIO(SCHED_RUN, 0); -} - -/** - * Called to determine when the next scheduled event will occur. - * - * If there are not scheduled events this function returns 0; otherwise it - * returns 1 and *next_event_time is set to the start time of the next event. - * - * @param next_event_time - * - * @return int 0: No events are scheduled 1: there is an upcoming event - */ -int -ble_ll_sched_next_time(uint32_t *next_event_time) -{ - int rc; - os_sr_t sr; - struct ble_ll_sched_item *first; - - rc = 0; - OS_ENTER_CRITICAL(sr); - first = TAILQ_FIRST(&g_ble_ll_sched_q); - if (first) { - *next_event_time = first->start_time; - rc = 1; - } - OS_EXIT_CRITICAL(sr); - - return rc; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -/** - * Called to check if there is place for a planned scan req. - * - * @param chan - * @param phy_mode - * - * @return int 0: Clear for scan req 1: there is an upcoming event - */ -int -ble_ll_sched_scan_req_over_aux_ptr(uint32_t chan, uint8_t phy_mode) -{ - struct ble_ll_sched_item *sch; - uint32_t usec_dur; - uint32_t now = os_cputime_get32(); - - /* Lets calculate roughly how much time we need for scan req and scan rsp */ - usec_dur = ble_ll_pdu_tx_time_get(BLE_SCAN_REQ_LEN, phy_mode); - if (chan >= BLE_PHY_NUM_DATA_CHANS) { - usec_dur += ble_ll_pdu_tx_time_get(BLE_SCAN_RSP_MAX_LEN, phy_mode); - } else { - usec_dur += ble_ll_pdu_tx_time_get(BLE_SCAN_RSP_MAX_EXT_LEN, phy_mode); - } - - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - while (sch) { - /* Let's check if there is no scheduled item which want to start within - * given usecs.*/ - if (CPUTIME_GT(sch->start_time, now + os_cputime_usecs_to_ticks(usec_dur))) { - /* We are fine. Have time for scan req */ - return 0; - } - - /* There is something in the scheduler. If it is not aux ptr we assume - * it is more important that scan req - */ - if (sch->sched_type != BLE_LL_SCHED_TYPE_AUX_SCAN) { - return 1; - } - - ble_ll_scan_end_adv_evt((struct ble_ll_aux_data *)sch->cb_arg); - TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 0; - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - } - return 0; -} - -/** - * Called to schedule a aux scan. - * - * Context: Interrupt - * - * @param ble_hdr - * @param scansm - * @param aux_scan - * - * @return 0 on success, 1 otherwise - */ -int -ble_ll_sched_aux_scan(struct ble_mbuf_hdr *ble_hdr, - struct ble_ll_scan_sm *scansm, - struct ble_ll_aux_data *aux_scan) -{ - int rc = 1; - os_sr_t sr; - uint32_t off_ticks; - uint32_t off_rem_usecs; - uint32_t start_time; - uint32_t start_time_rem_usecs; - uint32_t end_time; - uint32_t dur; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *sch; - int phy_mode; - - sch = &aux_scan->sch; - BLE_LL_ASSERT(sch->cb_arg == NULL); - - off_ticks = os_cputime_usecs_to_ticks(aux_scan->offset); - off_rem_usecs = aux_scan->offset - os_cputime_ticks_to_usecs(off_ticks); - - start_time = ble_hdr->beg_cputime + off_ticks; - start_time_rem_usecs = ble_hdr->rem_usecs + off_rem_usecs; - if (start_time_rem_usecs >= 31) { - start_time++; - start_time_rem_usecs -= 31; - } - start_time -= g_ble_ll_sched_offset_ticks; - - /* Let's calculate time we reserve for aux packet. For now we assume to wait - * for fixed number of bytes and handle possible interrupting it in - * ble_ll_sched_execute_item(). This is because aux packet can be up to - * 256bytes and we don't want to block sched that long - */ - phy_mode = ble_ll_phy_to_phy_mode(aux_scan->aux_phy, - BLE_HCI_LE_PHY_CODED_ANY); - dur = ble_ll_pdu_tx_time_get(MYNEWT_VAL(BLE_LL_SCHED_SCAN_AUX_PDU_LEN), - phy_mode); - end_time = start_time + os_cputime_usecs_to_ticks(dur); - - sch->start_time = start_time; - sch->remainder = start_time_rem_usecs; - sch->end_time = end_time; - - OS_ENTER_CRITICAL(sr); - - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible - * If we are here it means sch has been added to the scheduler */ - rc = 0; - goto done; - } - - /* Try to find slot for aux scan. */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; - break; - } - - /* Check for overlapping events. For now drop if it overlaps with - * anything. We can make it smarter later on - */ - if (ble_ll_sched_is_overlap(sch, entry)) { - break; - } - } - - if (!entry) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - -done: - - if (rc == 0) { - sch->cb_arg = ble_ll_scan_aux_data_ref(aux_scan); - STATS_INC(ble_ll_stats, aux_scheduled); - } - - /* Get head of list to restart timer */ - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (entry == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } else { - sch = entry; - } - - OS_EXIT_CRITICAL(sr); - - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - - return rc; -} -#endif - -#if MYNEWT_VAL(BLE_LL_DTM) -int ble_ll_sched_dtm(struct ble_ll_sched_item *sch) -{ - int rc; - os_sr_t sr; - struct ble_ll_sched_item *entry; - - OS_ENTER_CRITICAL(sr); - - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible - * If we are here it means sch has been added to the scheduler */ - rc = 0; - goto done; - } - - /* Try to find slot for test. */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (sch->end_time <= entry->start_time) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; - break; - } - - /* Check for overlapping events. For now drop if it overlaps with - * anything. We can make it smarter later on - */ - if (ble_ll_sched_is_overlap(sch, entry)) { - OS_EXIT_CRITICAL(sr); - return -1; - } - } - - if (!entry) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - -done: - - /* Get head of list to restart timer */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - - ble_ll_rfmgmt_sched_changed(sch); - - OS_EXIT_CRITICAL(sr); - - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - - return rc; -} -#endif -/** - * Stop the scheduler - * - * Context: Link Layer task - */ -void -ble_ll_sched_stop(void) -{ - os_cputime_timer_stop(&g_ble_ll_sched_timer); -} - -/** - * Initialize the scheduler. Should only be called once and should be called - * before any of the scheduler API are called. - * - * @return int - */ -int -ble_ll_sched_init(void) -{ - BLE_LL_DEBUG_GPIO_INIT(SCHED_ITEM_CB); - BLE_LL_DEBUG_GPIO_INIT(SCHED_RUN); - - /* - * Initialize max early to large negative number. This is used - * to determine the worst-case "early" time the schedule was called. Dont - * expect this to be less than -3 or -4. - */ -#if (BLE_LL_SCHED_DEBUG == 1) - g_ble_ll_sched_max_early = -50000; -#endif - - /* - * This is the offset from the start of the scheduled item until the actual - * tx/rx should occur, in ticks. We also "round up" to the nearest tick. - */ - g_ble_ll_sched_offset_ticks = - (uint8_t) os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS + 30); - - /* Initialize cputimer for the scheduler */ - os_cputime_timer_init(&g_ble_ll_sched_timer, ble_ll_sched_run, NULL); - -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) - memset(&g_ble_ll_sched_data, 0, sizeof(struct ble_ll_sched_obj)); - g_ble_ll_sched_data.sch_ticks_per_period = - os_cputime_usecs_to_ticks(MYNEWT_VAL(BLE_LL_USECS_PER_PERIOD)); - g_ble_ll_sched_data.sch_ticks_per_epoch = BLE_LL_SCHED_PERIODS * - g_ble_ll_sched_data.sch_ticks_per_period; -#endif - - return 0; -} - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_supp_cmd.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_supp_cmd.c deleted file mode 100644 index e4db5f778..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_supp_cmd.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include - -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_hci.h" - -/* Octet 0 */ -#define BLE_SUPP_CMD_DISCONNECT (1 << 5) -#define BLE_LL_SUPP_CMD_OCTET_0 (BLE_SUPP_CMD_DISCONNECT) - -/* Octet 5 */ -#define BLE_SUPP_CMD_SET_EVENT_MASK (1 << 6) -#define BLE_LL_SUPP_CMD_OCTET_5 (BLE_SUPP_CMD_SET_EVENT_MASK) - -/* Octet 10 */ -#define BLE_SUPP_CMD_RD_TX_PWR (0 << 2) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) -#define BLE_SUPP_CMD_SET_CTRL_TO_HOST_FLOW (1 << 5) -#define BLE_SUPP_CMD_HOST_BUFFER_SIZE (1 << 6) -#define BLE_SUPP_CMD_HOST_NUM_COMP_PACKETS (1 << 7) -#else -#define BLE_SUPP_CMD_SET_CTRL_TO_HOST_FLOW (0 << 5) -#define BLE_SUPP_CMD_HOST_BUFFER_SIZE (0 << 6) -#define BLE_SUPP_CMD_HOST_NUM_COMP_PACKETS (0 << 7) -#endif -#define BLE_LL_SUPP_CMD_OCTET_10 \ -( \ - BLE_SUPP_CMD_RD_TX_PWR | \ - BLE_SUPP_CMD_SET_CTRL_TO_HOST_FLOW | \ - BLE_SUPP_CMD_HOST_BUFFER_SIZE | \ - BLE_SUPP_CMD_HOST_NUM_COMP_PACKETS \ -) - -/* Octet 14 */ -#define BLE_SUPP_CMD_RD_LOC_VER (1 << 3) -#define BLE_SUPP_CMD_RD_LOC_SUPP_FEAT (1 << 5) -#define BLE_LL_SUPP_CMD_OCTET_14 \ -( \ - BLE_SUPP_CMD_RD_LOC_VER | \ - BLE_SUPP_CMD_RD_LOC_SUPP_FEAT \ -) - -/* Octet 15 */ -#define BLE_SUPP_CMD_RD_BD_ADDR (1 << 1) -#define BLE_SUPP_CMD_RD_RSSI (1 << 5) - -#define BLE_LL_SUPP_CMD_OCTET_15 \ -( \ - BLE_SUPP_CMD_RD_BD_ADDR | \ - BLE_SUPP_CMD_RD_RSSI \ -) - -/* Octet 25 */ -#define BLE_SUPP_CMD_LE_SET_EV_MASK (1 << 0) -#define BLE_SUPP_CMD_LE_RD_BUF_SIZE (1 << 1) -#define BLE_SUPP_CMD_LE_RD_LOC_FEAT (1 << 2) -#define BLE_SUPP_CMD_LE_SET_RAND_ADDR (1 << 4) -#define BLE_SUPP_CMD_LE_SET_ADV_PARAMS (1 << 5) -#define BLE_SUPP_CMD_LE_SET_ADV_TX_PWR (1 << 6) -#define BLE_SUPP_CMD_LE_SET_ADV_DATA (1 << 7) - -#define BLE_LL_SUPP_CMD_OCTET_25 \ -( \ - BLE_SUPP_CMD_LE_SET_EV_MASK | \ - BLE_SUPP_CMD_LE_RD_BUF_SIZE | \ - BLE_SUPP_CMD_LE_RD_LOC_FEAT | \ - BLE_SUPP_CMD_LE_SET_RAND_ADDR | \ - BLE_SUPP_CMD_LE_SET_ADV_PARAMS | \ - BLE_SUPP_CMD_LE_SET_ADV_TX_PWR | \ - BLE_SUPP_CMD_LE_SET_ADV_DATA \ -) - -/* Octet 26 */ -#define BLE_SUPP_CMD_LE_SET_SCAN_RSP_DATA (1 << 0) -#define BLE_SUPP_CMD_LE_SET_ADV_ENABLE (1 << 1) -#define BLE_SUPP_CMD_LE_SET_SCAN_PARAMS (1 << 2) -#define BLE_SUPP_CMD_LE_SET_SCAN_ENABLE (1 << 3) -#define BLE_SUPP_CMD_LE_CREATE_CONN (1 << 4) -#define BLE_SUPP_CMD_LE_CREATE_CONN_CANCEL (1 << 5) -#define BLE_SUPP_CMD_LE_RD_WHITELIST_SIZE (1 << 6) -#define BLE_SUPP_CMD_LE_CLR_WHITELIST (1 << 7) - -#define BLE_LL_SUPP_CMD_OCTET_26 \ -( \ - BLE_SUPP_CMD_LE_SET_SCAN_RSP_DATA | \ - BLE_SUPP_CMD_LE_SET_ADV_ENABLE | \ - BLE_SUPP_CMD_LE_SET_SCAN_PARAMS | \ - BLE_SUPP_CMD_LE_SET_SCAN_ENABLE | \ - BLE_SUPP_CMD_LE_CREATE_CONN | \ - BLE_SUPP_CMD_LE_CREATE_CONN_CANCEL | \ - BLE_SUPP_CMD_LE_RD_WHITELIST_SIZE | \ - BLE_SUPP_CMD_LE_CLR_WHITELIST \ -) - -/* Octet 27 */ -#define BLE_SUPP_CMD_LE_ADD_DEV_WHITELIST (1 << 0) -#define BLE_SUPP_CMD_LE_RMV_DEV_WHITELIST (1 << 1) -#define BLE_SUPP_CMD_LE_CONN_UPDATE (1 << 2) -#define BLE_SUPP_CMD_LE_SET_HOST_CHAN_CLASS (1 << 3) -#define BLE_SUPP_CMD_LE_RD_CHAN_MAP (1 << 4) -#define BLE_SUPP_CMD_LE_RD_REM_USED_FEAT (1 << 5) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -#define BLE_SUPP_CMD_LE_ENCRYPT (1 << 6) -#else -#define BLE_SUPP_CMD_LE_ENCRYPT (0 << 6) -#endif -#define BLE_SUPP_CMD_LE_RAND (1 << 7) - -#define BLE_LL_SUPP_CMD_OCTET_27 \ -( \ - BLE_SUPP_CMD_LE_ENCRYPT | \ - BLE_SUPP_CMD_LE_RAND | \ - BLE_SUPP_CMD_LE_ADD_DEV_WHITELIST | \ - BLE_SUPP_CMD_LE_RMV_DEV_WHITELIST | \ - BLE_SUPP_CMD_LE_CONN_UPDATE | \ - BLE_SUPP_CMD_LE_SET_HOST_CHAN_CLASS | \ - BLE_SUPP_CMD_LE_RD_CHAN_MAP | \ - BLE_SUPP_CMD_LE_RD_REM_USED_FEAT \ -) - -/* Octet 28 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -#define BLE_SUPP_CMD_LE_START_ENCRYPT (1 << 0) -#define BLE_SUPP_CMD_LE_LTK_REQ_REPLY (1 << 1) -#define BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY (1 << 2) -#else -#define BLE_SUPP_CMD_LE_START_ENCRYPT (0 << 0) -#define BLE_SUPP_CMD_LE_LTK_REQ_REPLY (0 << 1) -#define BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY (0 << 2) -#endif -#define BLE_SUPP_CMD_LE_READ_SUPP_STATES (1 << 3) - -#if MYNEWT_VAL(BLE_LL_DTM) -#define BLE_SUPP_CMD_LE_RX_TEST (1 << 4) -#define BLE_SUPP_CMD_LE_TX_TEST (1 << 5) -#define BLE_SUPP_CMD_LE_TEST_END (1 << 6) - -#else -#define BLE_SUPP_CMD_LE_RX_TEST (0 << 4) -#define BLE_SUPP_CMD_LE_TX_TEST (0 << 5) -#define BLE_SUPP_CMD_LE_TEST_END (0 << 6) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_28 \ -( \ - BLE_SUPP_CMD_LE_START_ENCRYPT | \ - BLE_SUPP_CMD_LE_LTK_REQ_REPLY | \ - BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY | \ - BLE_SUPP_CMD_LE_READ_SUPP_STATES | \ - BLE_SUPP_CMD_LE_RX_TEST | \ - BLE_SUPP_CMD_LE_TX_TEST | \ - BLE_SUPP_CMD_LE_TEST_END \ -) - -/* Octet 33 */ -#define BLE_SUPP_CMD_LE_REM_CONN_PRR (1 << 4) -#define BLE_SUPP_CMD_LE_REM_CONN_PRNR (1 << 5) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) -#define BLE_SUPP_CMD_LE_SET_DATALEN (1 << 6) -#define BLE_SUPP_CMD_LE_RD_SUGG_DATALEN (1 << 7) -#else -#define BLE_SUPP_CMD_LE_SET_DATALEN (0 << 6) -#define BLE_SUPP_CMD_LE_RD_SUGG_DATALEN (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_33 \ -( \ - BLE_SUPP_CMD_LE_REM_CONN_PRR | \ - BLE_SUPP_CMD_LE_REM_CONN_PRNR | \ - BLE_SUPP_CMD_LE_SET_DATALEN | \ - BLE_SUPP_CMD_LE_RD_SUGG_DATALEN \ -) - -/* Octet 34 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) -#define BLE_SUPP_CMD_LE_WR_SUGG_DATALEN (1 << 0) -#else -#define BLE_SUPP_CMD_LE_WR_SUGG_DATALEN (0 << 0) -#endif -#define BLE_SUPP_CMD_LE_READ_LOCAL_P256_PK (0 << 1) -#define BLE_SUPP_CMD_LE_GENERATE_DH_KEY (0 << 2) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -#define BLE_SUPP_CMD_LE_ADD_RESOLV_LIST (1 << 3) -#define BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST (1 << 4) -#define BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST (1 << 5) -#define BLE_SUPP_CMD_LE_RD_RESOLV_SIZE (1 << 6) -#define BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR (1 << 7) -#else -#define BLE_SUPP_CMD_LE_ADD_RESOLV_LIST (0 << 3) -#define BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST (0 << 4) -#define BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST (0 << 5) -#define BLE_SUPP_CMD_LE_RD_RESOLV_SIZE (0 << 6) -#define BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_34 \ -( \ - BLE_SUPP_CMD_LE_WR_SUGG_DATALEN | \ - BLE_SUPP_CMD_LE_READ_LOCAL_P256_PK | \ - BLE_SUPP_CMD_LE_GENERATE_DH_KEY | \ - BLE_SUPP_CMD_LE_ADD_RESOLV_LIST | \ - BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST | \ - BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST | \ - BLE_SUPP_CMD_LE_RD_RESOLV_SIZE | \ - BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR \ -) - -/* Octet 35 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -#define BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR (1 << 0) -#define BLE_SUPP_CMD_LE_SET_ADDR_RES_EN (1 << 1) -#define BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO (1 << 2) -#else -#define BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR (0 << 0) -#define BLE_SUPP_CMD_LE_SET_ADDR_RES_EN (0 << 1) -#define BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO (0 << 2) -#endif -#define BLE_SUPP_CMD_LE_RD_MAX_DATALEN (1 << 3) -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) -#define BLE_SUPP_CMD_LE_READ_PHY (1 << 4) -#define BLE_SUPP_CMD_LE_SET_DEFAULT_PHY (1 << 5) -#define BLE_SUPP_CMD_LE_SET_PHY (1 << 6) -#else -#define BLE_SUPP_CMD_LE_READ_PHY (0 << 4) -#define BLE_SUPP_CMD_LE_SET_DEFAULT_PHY (0 << 5) -#define BLE_SUPP_CMD_LE_SET_PHY (0 << 6) -#endif - -#if MYNEWT_VAL(BLE_LL_DTM) -#define BLE_SUPP_CMD_LE_ENHANCED_RX_TEST (1 << 7) -#else -#define BLE_SUPP_CMD_LE_ENHANCED_RX_TEST (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_35 \ -( \ - BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR | \ - BLE_SUPP_CMD_LE_SET_ADDR_RES_EN | \ - BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO | \ - BLE_SUPP_CMD_LE_RD_MAX_DATALEN | \ - BLE_SUPP_CMD_LE_READ_PHY | \ - BLE_SUPP_CMD_LE_SET_DEFAULT_PHY | \ - BLE_SUPP_CMD_LE_SET_PHY | \ - BLE_SUPP_CMD_LE_ENHANCED_RX_TEST \ -) - -/* Octet 36 */ -#if MYNEWT_VAL(BLE_LL_DTM) -#define BLE_SUPP_CMD_LE_ENHANCED_TX_TEST (1 << 0) -#else -#define BLE_SUPP_CMD_LE_ENHANCED_TX_TEST (0 << 0) -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#define BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR (1 << 1) -#define BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM (1 << 2) -#define BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA (1 << 3) -#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP (1 << 4) -#define BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE (1 << 5) -#define BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN (1 << 6) -#define BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS (1 << 7) -#else -#define BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR (0 << 1) -#define BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM (0 << 2) -#define BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA (0 << 3) -#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP (0 << 4) -#define BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE (0 << 5) -#define BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN (0 << 6) -#define BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_36 \ -( \ - BLE_SUPP_CMD_LE_ENHANCED_TX_TEST | \ - BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR | \ - BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM | \ - BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA | \ - BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP | \ - BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE | \ - BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN | \ - BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS \ -) - -/* Octet 37 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#define BLE_SUPP_CMD_LE_REMOVE_ADVS (1 << 0) -#define BLE_SUPP_CMD_LE_CLEAR_ADVS (1 << 1) -#else -#define BLE_SUPP_CMD_LE_REMOVE_ADVS (0 << 0) -#define BLE_SUPP_CMD_LE_CLEAR_ADVS (0 << 1) -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) -#define BLE_SUPP_CMD_LE_SET_PADV_PARAM (1 << 2) -#define BLE_SUPP_CMD_LE_SET_PADV_DATA (1 << 3) -#define BLE_SUPP_CMD_LE_SET_PADV_ENABLE (1 << 4) -#else -#define BLE_SUPP_CMD_LE_SET_PADV_PARAM (0 << 2) -#define BLE_SUPP_CMD_LE_SET_PADV_DATA (0 << 3) -#define BLE_SUPP_CMD_LE_SET_PADV_ENABLE (0 << 4) -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM (1 << 5) -#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE (1 << 6) -#define BLE_SUPP_CMD_LE_EXT_CREATE_CONN (1 << 7) -#else -#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM (0 << 5) -#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE (0 << 6) -#define BLE_SUPP_CMD_LE_EXT_CREATE_CONN (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_37 \ -( \ - BLE_SUPP_CMD_LE_REMOVE_ADVS | \ - BLE_SUPP_CMD_LE_CLEAR_ADVS | \ - BLE_SUPP_CMD_LE_SET_PADV_PARAM | \ - BLE_SUPP_CMD_LE_SET_PADV_DATA | \ - BLE_SUPP_CMD_LE_SET_PADV_ENABLE | \ - BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM | \ - BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE | \ - BLE_SUPP_CMD_LE_EXT_CREATE_CONN \ -) - -/* Octet 38 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) -#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC (1 << 0) -#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C (1 << 1) -#define BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC (1 << 2) -#define BLE_SUPP_CMD_LE_ADD_PADV_LIST (1 << 3) -#define BLE_SUPP_CMD_LE_REMOVE_PADV_LIST (1 << 4) -#define BLE_SUPP_CMD_LE_CLEAR_PADV_LIST (1 << 5) -#define BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE (1 << 6) -#else -#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC (0 << 0) -#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C (0 << 1) -#define BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC (0 << 2) -#define BLE_SUPP_CMD_LE_ADD_PADV_LIST (0 << 3) -#define BLE_SUPP_CMD_LE_REMOVE_PADV_LIST (0 << 4) -#define BLE_SUPP_CMD_LE_CLEAR_PADV_LIST (0 << 5) -#define BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE (0 << 6) -#endif -#define BLE_SUPP_CMD_LE_RD_TX_POWER (1 << 7) - -#define BLE_LL_SUPP_CMD_OCTET_38 \ -( \ - BLE_SUPP_CMD_LE_PADV_CREATE_SYNC | \ - BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C | \ - BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC | \ - BLE_SUPP_CMD_LE_ADD_PADV_LIST | \ - BLE_SUPP_CMD_LE_REMOVE_PADV_LIST | \ - BLE_SUPP_CMD_LE_CLEAR_PADV_LIST | \ - BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE | \ - BLE_SUPP_CMD_LE_RD_TX_POWER \ -) - -/* Octet 39 */ -#define BLE_SUPP_CMD_LE_RD_RF_PATH_COMP (1 << 0) -#define BLE_SUPP_CMD_LE_WR_RF_PATH_COMP (1 << 1) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -#define BLE_SUPP_CMD_LE_SET_PRIVACY_MODE (1 << 2) -#else -#define BLE_SUPP_CMD_LE_SET_PRIVACY_MODE (0 << 2) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_39 \ -( \ - BLE_SUPP_CMD_LE_RD_RF_PATH_COMP | \ - BLE_SUPP_CMD_LE_WR_RF_PATH_COMP | \ - BLE_SUPP_CMD_LE_SET_PRIVACY_MODE \ -) - -/* Octet 40 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_VERSION) >= 51 -#define BLE_SUPP_CMD_LE_PADV_RECV_ENABLE (1 << 5) -#else -#define BLE_SUPP_CMD_LE_PADV_RECV_ENABLE (0 << 5) -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER (1 << 6) -#define BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER (1 << 7) -#else -#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER (0 << 6) -#define BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_40 \ -( \ - BLE_SUPP_CMD_LE_PADV_RECV_ENABLE | \ - BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER | \ - BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER \ -) - -/* Octet 41 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS (1 << 0) -#define BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS (1 << 1) -#else -#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS (0 << 0) -#define BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS (0 << 1) -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) -#define BLE_SUPP_CMD_LE_READ_BUF_SIZE_V2 (1 << 5) -#define BLE_SUPP_CMD_LE_READ_ISO_TX_SYNC (1 << 6) -#define BLE_SUPP_CMD_LE_SET_CIG_PARAM (1 << 7) -#else -#define BLE_SUPP_CMD_LE_READ_BUF_SIZE_V2 (0 << 5) -#define BLE_SUPP_CMD_LE_READ_ISO_TX_SYNC (0 << 6) -#define BLE_SUPP_CMD_LE_SET_CIG_PARAM (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_41 \ -( \ - BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS | \ - BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS | \ - BLE_SUPP_CMD_LE_READ_BUF_SIZE_V2 | \ - BLE_SUPP_CMD_LE_READ_ISO_TX_SYNC | \ - BLE_SUPP_CMD_LE_SET_CIG_PARAM \ -) - -/* Octet 42 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) -#define BLE_SUPP_CMD_LE_SET_CIG_PARAM_TEST (1 << 0) -#define BLE_SUPP_CMD_LE_CREATE_CIS (1 << 1) -#define BLE_SUPP_CMD_LE_REMOVE_CIG (1 << 2) -#define BLE_SUPP_CMD_LE_ACCEPT_CIS_REQ (1 << 3) -#define BLE_SUPP_CMD_LE_REJECT_CIS_REQ (1 << 4) -#define BLE_SUPP_CMD_LE_CREATE_BIG (1 << 5) -#define BLE_SUPP_CMD_LE_CREATE_BIG_TEST (1 << 6) -#define BLE_SUPP_CMD_LE_TERMINATE_BIG (1 << 7) -#else -#define BLE_SUPP_CMD_LE_SET_CIG_PARAM_TEST (0 << 0) -#define BLE_SUPP_CMD_LE_CREATE_CIS (0 << 1) -#define BLE_SUPP_CMD_LE_REMOVE_CIG (0 << 2) -#define BLE_SUPP_CMD_LE_ACCEPT_CIS_REQ (0 << 3) -#define BLE_SUPP_CMD_LE_REJECT_CIS_REQ (0 << 4) -#define BLE_SUPP_CMD_LE_CREATE_BIG (0 << 5) -#define BLE_SUPP_CMD_LE_CREATE_BIG_TEST (0 << 6) -#define BLE_SUPP_CMD_LE_TERMINATE_BIG (0 << 7) -#endif -#define BLE_LL_SUPP_CMD_OCTET_42 \ -( \ - BLE_SUPP_CMD_LE_SET_CIG_PARAM_TEST | \ - BLE_SUPP_CMD_LE_CREATE_CIS | \ - BLE_SUPP_CMD_LE_REMOVE_CIG | \ - BLE_SUPP_CMD_LE_ACCEPT_CIS_REQ | \ - BLE_SUPP_CMD_LE_REJECT_CIS_REQ | \ - BLE_SUPP_CMD_LE_CREATE_BIG | \ - BLE_SUPP_CMD_LE_CREATE_BIG_TEST | \ - BLE_SUPP_CMD_LE_TERMINATE_BIG \ -) - -/* Octet 43 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) -#define BLE_SUPP_CMD_LE_REQUEST_PEER_SCA (1 << 2) -#else -#define BLE_SUPP_CMD_LE_REQUEST_PEER_SCA (0 << 0) -#endif -#define BLE_LL_SUPP_CMD_OCTET_43 \ -( \ - BLE_SUPP_CMD_LE_REQUEST_PEER_SCA \ -) - -/* Octet 44 */ -#if MYNEWT_VAL(BLE_VERSION) >= 52 -#define BLE_SUPP_CMD_LE_SET_HOST_FEATURE (1 << 0) -#else -#define BLE_SUPP_CMD_LE_SET_HOST_FEATURE (0 << 0) -#endif -#define BLE_LL_SUPP_CMD_OCTET_44 \ -( \ - BLE_SUPP_CMD_LE_SET_HOST_FEATURE \ -) - -/* Defines the array of supported commands */ -const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN] = -{ - BLE_LL_SUPP_CMD_OCTET_0, /* Octet 0 */ - 0, - 0, - 0, - 0, - BLE_LL_SUPP_CMD_OCTET_5, - 0, - 0, - 0, /* Octet 8 */ - 0, - BLE_LL_SUPP_CMD_OCTET_10, - 0, - 0, - 0, - BLE_LL_SUPP_CMD_OCTET_14, - BLE_LL_SUPP_CMD_OCTET_15, - 0, /* Octet 16 */ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, /* Octet 24 */ - BLE_LL_SUPP_CMD_OCTET_25, - BLE_LL_SUPP_CMD_OCTET_26, - BLE_LL_SUPP_CMD_OCTET_27, - BLE_LL_SUPP_CMD_OCTET_28, - 0, - 0, - 0, - 0, /* Octet 32 */ - BLE_LL_SUPP_CMD_OCTET_33, - BLE_LL_SUPP_CMD_OCTET_34, - BLE_LL_SUPP_CMD_OCTET_35, - BLE_LL_SUPP_CMD_OCTET_36, - BLE_LL_SUPP_CMD_OCTET_37, - BLE_LL_SUPP_CMD_OCTET_38, - BLE_LL_SUPP_CMD_OCTET_39, - BLE_LL_SUPP_CMD_OCTET_40, /* Octet 40 */ - BLE_LL_SUPP_CMD_OCTET_41, - BLE_LL_SUPP_CMD_OCTET_42, - BLE_LL_SUPP_CMD_OCTET_43, - BLE_LL_SUPP_CMD_OCTET_44, -}; - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_sync.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_sync.c deleted file mode 100644 index f1908c329..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_sync.c +++ /dev/null @@ -1,2346 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include -#include - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" - -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_hci.h" -#include "../include/controller/ble_ll_sync.h" -#include "../include/controller/ble_ll_utils.h" -#include "../include/controller/ble_ll_sched.h" -#include "../include/controller/ble_ll_whitelist.h" -#include "../include/controller/ble_ll_scan.h" -#include "../include/controller/ble_ll_resolv.h" -#include "../include/controller/ble_ll_rfmgmt.h" - -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "nimble/nimble/include/nimble/ble_hci_trans.h" - -#include "ble_ll_conn_priv.h" - -#include "nimble/porting/nimble/include/stats/stats.h" - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - -/* defines number of events that can be lost during sync establishment - * before failed to be established error is reported - */ -#define BLE_LL_SYNC_ESTABLISH_CNT 6 - -#define BLE_LL_SYNC_CNT MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_CNT) -#define BLE_LL_SYNC_LIST_CNT MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_LIST_CNT) - -#define BLE_LL_SYNC_SM_FLAG_RESERVED 0x0001 -#define BLE_LL_SYNC_SM_FLAG_ESTABLISHING 0x0002 -#define BLE_LL_SYNC_SM_FLAG_ESTABLISHED 0x0004 -#define BLE_LL_SYNC_SM_FLAG_SET_ANCHOR 0x0008 -#define BLE_LL_SYNC_SM_FLAG_OFFSET_300 0x0010 -#define BLE_LL_SYNC_SM_FLAG_SYNC_INFO 0x0020 -#define BLE_LL_SYNC_SM_FLAG_DISABLED 0x0040 -#define BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED 0x0080 -#define BLE_LL_SYNC_SM_FLAG_HCI_TRUNCATED 0x0100 -#define BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP 0x0200 - -#define BLE_LL_SYNC_CHMAP_LEN 5 -#define BLE_LL_SYNC_ITVL_USECS 1250 - -struct ble_ll_sync_sm { - uint16_t flags; - - uint8_t adv_sid; - uint8_t adv_addr[BLE_DEV_ADDR_LEN]; - uint8_t adv_addr_type; - - uint8_t sca; - uint8_t chanmap[BLE_LL_SYNC_CHMAP_LEN]; - uint8_t num_used_chans; - - uint8_t chanmap_new[BLE_LL_SYNC_CHMAP_LEN]; - uint16_t chanmap_new_instant; - - uint8_t chan_index; - uint8_t chan_chain; - - uint8_t phy_mode; - - uint8_t sync_pending_cnt; - - uint32_t timeout; - uint16_t skip; - - uint16_t itvl; - uint8_t itvl_usecs; - uint32_t itvl_ticks; - - uint32_t crcinit; /* only 3 bytes are used */ - uint32_t access_addr; - uint16_t event_cntr; - uint16_t channel_id; - - uint32_t window_widening; - uint32_t last_anchor_point; - uint32_t anchor_point; - uint8_t anchor_point_usecs; - - struct ble_ll_sched_item sch; - - struct ble_npl_event sync_ev_end; - - uint8_t *next_report; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - struct ble_ll_conn_sm *transfer_conn; - uint8_t *transfer_received_ev; - uint16_t transfer_id; - uint16_t event_cntr_last_received; - uint8_t adv_addr_rpa[6]; -#endif -}; - -static struct ble_ll_sync_sm g_ble_ll_sync_sm[BLE_LL_SYNC_CNT]; - -static struct { - uint8_t adv_sid; - uint8_t adv_addr[BLE_DEV_ADDR_LEN]; - uint8_t adv_addr_type; -} g_ble_ll_sync_adv_list[BLE_LL_SYNC_LIST_CNT]; - -static struct { - uint32_t timeout; - uint16_t max_skip; - uint16_t options; -} g_ble_ll_sync_create_params; - -/* if this is set HCI LE Sync Create is pending */ -static uint8_t *g_ble_ll_sync_create_comp_ev; - -static struct ble_ll_sync_sm *g_ble_ll_sync_sm_current; - -static int -ble_ll_sync_on_list(const uint8_t *addr, uint8_t addr_type, uint8_t sid) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { - if ((g_ble_ll_sync_adv_list[i].adv_sid == sid) && - (g_ble_ll_sync_adv_list[i].adv_addr_type == addr_type) && - !memcmp(g_ble_ll_sync_adv_list[i].adv_addr, addr, BLE_DEV_ADDR_LEN)) { - return i; - } - } - - return -1; -} - -static int -ble_ll_sync_list_get_free(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { - if (g_ble_ll_sync_adv_list[i].adv_sid == 0xff) { - return i; - } - } - - return -1; -} - -static bool -ble_ll_sync_list_empty(void) { - int i; - - for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { - if (g_ble_ll_sync_adv_list[i].adv_sid != 0xff) { - return false; - } - } - - return true; -} - -static uint8_t -ble_ll_sync_get_handle(struct ble_ll_sync_sm *sm) -{ - /* handle number is offset in global array */ - return sm - g_ble_ll_sync_sm; -} - -static void -ble_ll_sync_sm_clear(struct ble_ll_sync_sm *sm) -{ - if (sm->flags & (BLE_LL_SYNC_SM_FLAG_ESTABLISHING | - BLE_LL_SYNC_SM_FLAG_ESTABLISHED)) { - ble_ll_sched_rmv_elem(&sm->sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &sm->sync_ev_end); - } - - if (sm->next_report) { - ble_hci_trans_buf_free(sm->next_report); - } - - if (g_ble_ll_sync_sm_current == sm) { - ble_phy_disable(); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - g_ble_ll_sync_sm_current = NULL; - ble_ll_scan_chk_resume(); - } - - ble_ll_rfmgmt_release(); - - BLE_LL_ASSERT(sm->sync_ev_end.ev.ev_queued == 0); - BLE_LL_ASSERT(sm->sch.enqueued == 0); - memset(sm, 0, sizeof(*sm)); -} - -static uint8_t -ble_ll_sync_phy_mode_to_hci(int8_t phy_mode) -{ -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - switch (phy_mode) { - case BLE_PHY_MODE_1M: - return BLE_HCI_LE_PHY_1M; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - case BLE_PHY_MODE_2M: - return BLE_HCI_LE_PHY_2M; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case BLE_PHY_MODE_CODED_125KBPS: - case BLE_PHY_MODE_CODED_500KBPS: - return BLE_HCI_LE_PHY_CODED; -#endif - default: - BLE_LL_ASSERT(false); - return BLE_PHY_MODE_1M; - } -#else - return BLE_PHY_MODE_1M; -#endif -} - -static struct ble_ll_sync_sm * -ble_ll_sync_find(const uint8_t *addr, uint8_t addr_type, uint8_t sid) -{ - struct ble_ll_sync_sm *sm; - int i; - - for (i = 0; i < BLE_LL_SYNC_CNT; i++) { - sm = &g_ble_ll_sync_sm[i]; - - if (!sm->flags) { - continue; - } - if ((sm->adv_sid == sid) && (sm->adv_addr_type == addr_type) && - !memcmp(&sm->adv_addr, addr, BLE_DEV_ADDR_LEN)) { - return sm; - } - } - - return NULL; -} - -static uint16_t -get_max_skip(uint32_t interval_us, uint32_t timeout_us) -{ - uint16_t max_skip; - - BLE_LL_ASSERT(interval_us); - BLE_LL_ASSERT(timeout_us); - - if (timeout_us <= interval_us) { - return 0; - } - - /* - * Calculate max allowed skip to receive something before timeout. We adjust - * current skip value to be no more than max_skip-6 so we have at least few - * attempts to receive an event (so we don't timeout immediately after just - * one missed event). - */ - - max_skip = (timeout_us / interval_us) - 1; - - if (max_skip < 6) { - return 0; - } - - return max_skip - 6; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -static void -ble_ll_sync_transfer_received(struct ble_ll_sync_sm *sm, uint8_t status) -{ - struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev; - struct ble_hci_ev *hci_ev; - - BLE_LL_ASSERT(sm->transfer_received_ev); - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER)) { - hci_ev = (void *) sm->transfer_received_ev; - - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - - ev = (void *) hci_ev->data; - ev->subev_code = BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER; - - ev->status = status; - ev->conn_handle = htole16(sm->transfer_conn->conn_handle); - ev->service_data = htole16(sm->transfer_id); - - /* this is ignored by host on error */ - ev->sync_handle = htole16(ble_ll_sync_get_handle(sm)); - ev->sid = sm->adv_sid; - ev->peer_addr_type = sm->adv_addr_type; - if (sm->flags & BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED) { - ev->peer_addr_type += 2; - } - memcpy(ev->peer_addr, sm->adv_addr, BLE_DEV_ADDR_LEN); - ev->phy = ble_ll_sync_phy_mode_to_hci(sm->phy_mode); - ev->interval = htole16(sm->itvl); - ev->aca = sm->sca; - - ble_ll_hci_event_send(hci_ev); - } else { - ble_hci_trans_buf_free(sm->transfer_received_ev); - } - - sm->transfer_received_ev = NULL; - sm->transfer_conn = NULL; -} -#endif - -static void -ble_ll_sync_est_event_success(struct ble_ll_sync_sm *sm) -{ - struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev; - struct ble_hci_ev *hci_ev; - - BLE_LL_ASSERT(g_ble_ll_sync_create_comp_ev); - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB)) { - hci_ev = (void *) g_ble_ll_sync_create_comp_ev; - - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB; - ev->status = BLE_ERR_SUCCESS; - ev->sync_handle = htole16(ble_ll_sync_get_handle(sm)); - ev->sid = sm->adv_sid; - ev->peer_addr_type = sm->adv_addr_type; - if (sm->flags & BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED) { - ev->peer_addr_type += 2; - } - memcpy(ev->peer_addr, sm->adv_addr, BLE_DEV_ADDR_LEN); - ev->phy = ble_ll_sync_phy_mode_to_hci(sm->phy_mode); - ev->interval = htole16(sm->itvl); - ev->aca = sm->sca; - - ble_ll_hci_event_send(hci_ev); - } else { - ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev); - } - - g_ble_ll_sync_create_comp_ev = NULL; -} - -static void -ble_ll_sync_est_event_failed(uint8_t status) -{ - struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev; - struct ble_hci_ev *hci_ev; - - BLE_LL_ASSERT(g_ble_ll_sync_create_comp_ev); - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB)) { - hci_ev = (void *) g_ble_ll_sync_create_comp_ev; - - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - memset(ev, 0, sizeof(*ev)); - - ev->subev_code = BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB; - ev->status = status; - - ble_ll_hci_event_send(hci_ev); - } else { - ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev); - } - - g_ble_ll_sync_create_comp_ev = NULL; -} - -static void -ble_ll_sync_lost_event(struct ble_ll_sync_sm *sm) -{ - struct ble_hci_ev_le_subev_periodic_adv_sync_lost *ev; - struct ble_hci_ev *hci_ev; - - if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_LOST)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_LOST; - ev->sync_handle = htole16(ble_ll_sync_get_handle(sm)); - - ble_ll_hci_event_send(hci_ev); - } - } -} - -static void -ble_ll_sync_current_sm_over(void) -{ - /* Disable the PHY */ - ble_phy_disable(); - - /* Link-layer is in standby state now */ - ble_ll_state_set(BLE_LL_STATE_STANDBY); - - /* Set current LL sync to NULL */ - g_ble_ll_sync_sm_current = NULL; -} - -static int -ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch) -{ - struct ble_ll_sync_sm *sm; - uint32_t wfr_usecs; - uint32_t start; - int rc; - - /* Set current connection state machine */ - sm = sch->cb_arg; - BLE_LL_ASSERT(sm); - - g_ble_ll_sync_sm_current = sm; - - /* Disable whitelisting */ - ble_ll_whitelist_disable(); - - /* Set LL state */ - ble_ll_state_set(BLE_LL_STATE_SYNC); - - /* Set channel */ - ble_phy_setchan(sm->chan_index, sm->access_addr, sm->crcinit); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - ble_phy_resolv_list_disable(); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - ble_phy_encrypt_disable(); -#endif - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_set(sm->phy_mode, sm->phy_mode); -#endif - - start = sch->start_time + g_ble_ll_sched_offset_ticks; - rc = ble_phy_rx_set_start_time(start, sch->remainder); - if (rc && rc != BLE_PHY_ERR_RX_LATE) { - STATS_INC(ble_ll_stats, sync_event_failed); - rc = BLE_LL_SCHED_STATE_DONE; - ble_ll_event_send(&sm->sync_ev_end); - ble_ll_sync_current_sm_over(); - } else { - /* - * Set flag that tells to set last anchor point if a packet - * has been received. - */ - sm->flags |= BLE_LL_SYNC_SM_FLAG_SET_ANCHOR; - - /* Set WFR timer. - * If establishing we always adjust with offset unit. - * If this is first packet of sync (one that was pointed by from - * SyncInfo we don't adjust WFT with window widening. - */ - if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) { - wfr_usecs = (sm->flags & BLE_LL_SYNC_SM_FLAG_OFFSET_300) ? 300 : 30; - if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_SYNC_INFO)) { - wfr_usecs += 2 * sm->window_widening; - } - } else { - wfr_usecs = 2 * sm->window_widening; - } - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_usecs); - - rc = BLE_LL_SCHED_STATE_RUNNING; - } - - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_SYNC_INFO; - - return rc; -} - -/** - * Called when a receive PDU has started. - * - * Context: interrupt - * - * @return int - * < 0: A frame we dont want to receive. - * = 0: Continue to receive frame. Dont go from rx to tx - */ -int -ble_ll_sync_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr) -{ - BLE_LL_ASSERT(g_ble_ll_sync_sm_current); - - /* this also handles chains as those have same PDU type */ - if (pdu_type != BLE_ADV_PDU_TYPE_AUX_SYNC_IND) { - ble_ll_event_send(&g_ble_ll_sync_sm_current->sync_ev_end); - ble_ll_sync_current_sm_over(); - STATS_INC(ble_ll_stats, sched_invalid_pdu); - return -1; - } - - STATS_INC(ble_ll_stats, sync_received); - return 0; -} - -static int -ble_ll_sync_parse_ext_hdr(struct os_mbuf *om, uint8_t **aux, int8_t *tx_power, - uint8_t **acad, uint8_t *acad_len) -{ - uint8_t *rxbuf = om->om_data; - uint8_t ext_hdr_flags; - uint8_t ext_hdr_len; - uint8_t *ext_hdr; - uint8_t pdu_len; - int i; - - pdu_len = rxbuf[1]; - if (pdu_len == 0) { - return -1; - } - ext_hdr_len = rxbuf[2] & 0x3F; - if (ext_hdr_len > (pdu_len - 1)) { - return -1; - } - - if (ext_hdr_len) { - ext_hdr_flags = rxbuf[3]; - ext_hdr = &rxbuf[4]; - - i = 0; - - /* there should be no AdvA in Sync or chain, skip it */ - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - i += BLE_LL_EXT_ADV_ADVA_SIZE; - } - - /* there should be no TargetA in Sync or chain, skip it */ - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - i += BLE_LL_EXT_ADV_TARGETA_SIZE; - } - - /* Ignore CTE for now */ - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { - i += 1; - } - - /* there should be no ADI in Sync or chain, skip it */ - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { - i += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - } - - /* get AuXPTR if present */ - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { - *aux = ext_hdr + i; - i += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - } - - /* there should be no SyncInfo in Sync or chain, skip it */ - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { - i += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { - *tx_power = *(ext_hdr + i); - i += BLE_LL_EXT_ADV_TX_POWER_SIZE; - } - - /* sanity check */ - if (i > ext_hdr_len) { - return -1; - } - - /* ACAD */ - if (ext_hdr_len > (i + 1)) { - *acad = ext_hdr + i; - *acad_len = ext_hdr_len - i - 1; - } - - } - - return pdu_len - ext_hdr_len - 1; -} - -static void -ble_ll_sync_adjust_ext_hdr(struct os_mbuf *om) -{ - uint8_t *rxbuf = om->om_data; - uint8_t ext_hdr_len; - - /* this was already verified in ble_ll_sync_parse_ext_hdr() */ - ext_hdr_len = rxbuf[2] & 0x3F; - - os_mbuf_adj(om, 3 + ext_hdr_len); -} - -static void -ble_ll_sync_send_truncated_per_adv_rpt(struct ble_ll_sync_sm *sm, uint8_t *evbuf) -{ - struct ble_hci_ev_le_subev_periodic_adv_rpt *ev; - struct ble_hci_ev *hci_ev; - - if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT) || - (sm->flags & BLE_LL_SYNC_SM_FLAG_DISABLED)) { - ble_hci_trans_buf_free(evbuf); - return; - } - - hci_ev = (void *) evbuf; - - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT; - ev->sync_handle = htole16(ble_ll_sync_get_handle(sm)); - ev->tx_power = 127; /* not available */ - ev->rssi = 127; /* not available */ - ev->cte_type = 0xff; - ev->data_status = BLE_HCI_PERIODIC_DATA_STATUS_TRUNCATED; - ev->data_len = 0; - - ble_ll_hci_event_send(hci_ev); -} - -static void -ble_ll_sync_send_per_adv_rpt(struct ble_ll_sync_sm *sm, struct os_mbuf *rxpdu, - int8_t rssi, int8_t tx_power, int datalen, - uint8_t *aux, bool aux_scheduled) -{ - struct ble_hci_ev_le_subev_periodic_adv_rpt *ev; - struct ble_hci_ev *hci_ev; - struct ble_hci_ev *hci_ev_next = NULL; - uint8_t max_data_len; - int offset; - - /* use next report buffer if present, this means we are chaining */ - if (sm->next_report) { - hci_ev = (void *) sm->next_report; - sm->next_report = NULL; - } else { - hci_ev = (void * )ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - if (!hci_ev) { - goto done; - } - } - - max_data_len = BLE_LL_MAX_EVT_LEN - sizeof(*hci_ev) - sizeof(*ev); - offset = 0; - - do { - if (hci_ev_next) { - hci_ev = hci_ev_next; - hci_ev_next = NULL; - } - - hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT; - ev->sync_handle = htole16(ble_ll_sync_get_handle(sm)); - ev->tx_power = tx_power; - ev->rssi = rssi; - ev->cte_type = 0xff; - - ev->data_len = min(max_data_len, datalen - offset); - /* adjust event length */ - hci_ev->length += ev->data_len; - - os_mbuf_copydata(rxpdu, offset, ev->data_len, ev->data); - offset += ev->data_len; - - /* Need another event for next fragment of this PDU */ - if (offset < datalen) { - hci_ev_next = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - if (hci_ev_next) { - ev->data_status = BLE_HCI_PERIODIC_DATA_STATUS_INCOMPLETE; - } else { - ev->data_status = BLE_HCI_PERIODIC_DATA_STATUS_TRUNCATED; - } - } else { - /* last report of this PDU */ - if (aux) { - if (aux_scheduled) { - /* if we scheduled aux, we need buffer for next report */ - hci_ev_next = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - if (hci_ev_next) { - ev->data_status = BLE_HCI_PERIODIC_DATA_STATUS_INCOMPLETE; - } else { - ev->data_status = BLE_HCI_PERIODIC_DATA_STATUS_TRUNCATED; - } - } else { - ev->data_status = BLE_HCI_PERIODIC_DATA_STATUS_TRUNCATED; - } - } else { - ev->data_status = BLE_HCI_PERIODIC_DATA_STATUS_COMPLETE; - } - } - ble_ll_hci_event_send(hci_ev); - } while ((offset < datalen) && hci_ev_next); - -done: - /* this means that we already truncated data (or didn't sent first at all) - * in HCI report but has scheduled for next PDU in chain. In that case mark - * it so that we end event properly when next PDU is received. - * */ - if (aux_scheduled && !hci_ev_next) { - sm->flags |= BLE_LL_SYNC_SM_FLAG_HCI_TRUNCATED; - } - - /* store for chain */ - sm->next_report = (void *) hci_ev_next; -} - -/** - * Called when a receive PDU has ended. - * - * Context: Interrupt - * - * @param rxpdu - * - * @return int - * < 0: Disable the phy after reception. - * == 0: Success. Do not disable the PHY. - * > 0: Do not disable PHY as that has already been done. - */ -int -ble_ll_sync_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) -{ - struct ble_mbuf_hdr *ble_hdr; - struct os_mbuf *rxpdu; - - BLE_LL_ASSERT(g_ble_ll_sync_sm_current); - - /* type was verified in isr_start */ - - rxpdu = ble_ll_rxpdu_alloc(rxbuf[1] + BLE_LL_PDU_HDR_LEN); - if (rxpdu) { - ble_phy_rxpdu_copy(rxbuf, rxpdu); - - ble_hdr = BLE_MBUF_HDR_PTR(rxpdu); - ble_hdr->rxinfo.user_data = g_ble_ll_sync_sm_current; - - ble_ll_rx_pdu_in(rxpdu); - } else { - STATS_INC(ble_ll_stats, sync_rx_buf_err); - ble_ll_event_send(&g_ble_ll_sync_sm_current->sync_ev_end); - } - - /* PHY is disabled here */ - ble_ll_sync_current_sm_over(); - - return 1; -} - -/** - * Called when the wait for response timer expires while in the sync state. - * - * Context: Interrupt. - */ -void -ble_ll_sync_wfr_timer_exp(void) -{ - struct ble_ll_sync_sm *sm = g_ble_ll_sync_sm_current; - - BLE_LL_ASSERT(g_ble_ll_sync_sm_current); - STATS_INC(ble_ll_stats, sync_missed_err); - - ble_ll_sync_current_sm_over(); - ble_ll_event_send(&sm->sync_ev_end); -} - -/** - * Called when sync event needs to be halted. This normally should not be called - * and is only called when a scheduled item executes but scanning for sync/chain - * is stil ongoing - * Context: Interrupt - */ -void -ble_ll_sync_halt(void) -{ - struct ble_ll_sync_sm *sm = g_ble_ll_sync_sm_current; - - ble_ll_sync_current_sm_over(); - - if (sm) { - ble_ll_event_send(&sm->sync_ev_end); - } -} - -uint32_t -ble_ll_sync_get_event_end_time(void) -{ - uint32_t end_time; - - if (g_ble_ll_sync_sm_current) { - end_time = g_ble_ll_sync_sm_current->sch.end_time; - } else { - end_time = os_cputime_get32(); - } - return end_time; -} - -static uint8_t -ble_ll_sync_phy_mode_to_aux_phy(uint8_t phy_mode) -{ - switch (phy_mode) { - case BLE_PHY_MODE_1M: - return 0x00; - case BLE_PHY_MODE_2M: - return 0x01; - case BLE_PHY_MODE_CODED_125KBPS: - case BLE_PHY_MODE_CODED_500KBPS: - return 0x02; - default: - BLE_LL_ASSERT(false); - return 0x00; - } -} - -static void -ble_ll_sync_parse_aux_ptr(const uint8_t *buf, uint8_t *chan, uint32_t *offset, - uint8_t *offset_units, uint8_t *phy) -{ - uint32_t aux_ptr_field = get_le32(buf) & 0x00FFFFFF; - - *chan = aux_ptr_field & 0x3F; - - /* TODO use CA aux_ptr_field >> 6 */ - - if ((aux_ptr_field >> 7) & 0x01) { - *offset = 300 * ((aux_ptr_field >> 8) & 0x1FFF); - *offset_units = 1; - } else { - *offset = 30 * ((aux_ptr_field >> 8) & 0x1FFF); - *offset_units = 0; - } - - *phy = (aux_ptr_field >> 21) & 0x07; -} - -static int -ble_ll_sync_chain_start_cb(struct ble_ll_sched_item *sch) -{ - struct ble_ll_sync_sm *sm; - uint32_t wfr_usecs; - uint32_t start; - int rc; - - /* Set current connection state machine */ - sm = sch->cb_arg; - g_ble_ll_sync_sm_current = sm; - BLE_LL_ASSERT(sm); - - /* Disable whitelisting */ - ble_ll_whitelist_disable(); - - /* Set LL state */ - ble_ll_state_set(BLE_LL_STATE_SYNC); - - /* Set channel */ - ble_phy_setchan(sm->chan_chain, sm->access_addr, sm->crcinit); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - ble_phy_resolv_list_disable(); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - ble_phy_encrypt_disable(); -#endif - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_set(sm->phy_mode, sm->phy_mode); -#endif - - start = sch->start_time + g_ble_ll_sched_offset_ticks; - rc = ble_phy_rx_set_start_time(start, sch->remainder); - if (rc && rc != BLE_PHY_ERR_RX_LATE) { - STATS_INC(ble_ll_stats, sync_chain_failed); - rc = BLE_LL_SCHED_STATE_DONE; - ble_ll_event_send(&sm->sync_ev_end); - ble_ll_sync_current_sm_over(); - } else { - /* - * Clear flag that tells to set last anchor point if a packet - * has been received, this is chain and we don't need it. - */ - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_SET_ANCHOR; - - wfr_usecs = (sm->flags & BLE_LL_SYNC_SM_FLAG_OFFSET_300) ? 300 : 30; - - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_usecs); - rc = BLE_LL_SCHED_STATE_RUNNING; - } - - return rc; -} - -static int -ble_ll_sync_schedule_chain(struct ble_ll_sync_sm *sm, struct ble_mbuf_hdr *hdr, - const uint8_t *aux) -{ - uint8_t offset_units; - uint32_t offset; - uint8_t chan; - uint8_t phy; - - ble_ll_sync_parse_aux_ptr(aux, &chan, &offset, &offset_units, &phy); - - if (chan >= BLE_PHY_NUM_DATA_CHANS) { - return -1; - } - - if (offset < BLE_LL_MAFS) { - return -1; - } - - /* chain should use same PHY as master PDU */ - if (phy != ble_ll_sync_phy_mode_to_aux_phy(sm->phy_mode)) { - return -1; - } - - if (offset_units) { - sm->flags |= BLE_LL_SYNC_SM_FLAG_OFFSET_300; - } else { - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_OFFSET_300; - } - - sm->chan_chain = chan; - - sm->sch.sched_cb = ble_ll_sync_chain_start_cb; - sm->sch.cb_arg = sm; - sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; - - return ble_ll_sched_sync(&sm->sch, hdr->beg_cputime, hdr->rem_usecs, - offset, sm->phy_mode); -} - -static void -ble_ll_sync_established(struct ble_ll_sync_sm *sm) -{ - BLE_LL_ASSERT(sm->sync_pending_cnt); - - /* mark as established */ - - sm->flags |= BLE_LL_SYNC_SM_FLAG_ESTABLISHED; - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_ESTABLISHING; - - sm->sync_pending_cnt = 0; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - if (sm->transfer_conn) { - ble_ll_sync_transfer_received(sm, BLE_ERR_SUCCESS); - return; - } -#endif - - ble_ll_sync_est_event_success(sm); -} - -static void -ble_ll_sync_check_failed(struct ble_ll_sync_sm *sm) -{ - BLE_LL_ASSERT(sm->sync_pending_cnt); - - /* if we can retry on next event */ - if (--sm->sync_pending_cnt) { - return; - } - - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_ESTABLISHING; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - if (sm->transfer_conn) { - ble_ll_sync_transfer_received(sm, BLE_ERR_CONN_ESTABLISHMENT); - return; - } -#endif - - ble_ll_sync_est_event_failed(BLE_ERR_CONN_ESTABLISHMENT); -} - -static bool -ble_ll_sync_check_acad(struct ble_ll_sync_sm *sm, - const uint8_t *acad, uint8_t acad_len) -{ - const struct ble_ll_acad_channel_map_update_ind *chmu; - unsigned int ad_len; - uint8_t ad_type; - - /* assume no empty fields */ - while (acad_len > 2) { - ad_len = acad[0]; - ad_type = acad[1]; - - /* early termination should not happen in ACAD */ - if (ad_len == 0) { - return false; - } - - /* check if not passing pass acad data */ - if (ad_len + 1 > acad_len) { - return false; - } - - switch (ad_type) { - case BLE_LL_ACAD_CHANNEL_MAP_UPDATE_IND: - chmu = (const void *)&acad[2]; - - if (ad_len - 1 != sizeof(*chmu)) { - return false; - } - - /* Channels Mask (37 bits) - * TODO should we check this? - */ - sm->chanmap_new[0] = chmu->map[0]; - sm->chanmap_new[1] = chmu->map[1]; - sm->chanmap_new[2] = chmu->map[2]; - sm->chanmap_new[3] = chmu->map[3]; - sm->chanmap_new[4] = chmu->map[4] & 0x1f; - - /* drop if channel map is invalid */ - if (ble_ll_utils_calc_num_used_chans(sm->chanmap_new) == 0) { - return false; - } - - sm->chanmap_new_instant = le16toh(chmu->instant); - sm->flags |= BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP; - break; - default: - break; - } - - acad += ad_len + 1; - acad_len -= ad_len + 1; - } - - /* should have no trailing zeros */ - if (acad_len) { - return false; - } - - return true; -} - -void -ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) -{ - struct ble_ll_sync_sm *sm = hdr->rxinfo.user_data; - bool aux_scheduled = false; - int8_t tx_power = 127; /* defaults to not available */ - uint8_t *aux = NULL; - uint8_t *acad = NULL; - uint8_t acad_len; - int datalen; - bool reports_enabled; - - BLE_LL_ASSERT(sm); - - /* this could happen if sync was cancelled or terminated while pkt_in was - * already in LL queue, just drop in that case - */ - if (!sm->flags) { - ble_ll_scan_chk_resume(); - ble_ll_rfmgmt_release(); - return; - } - - /* Set anchor point (and last) if 1st rxd frame in sync event. - * According to spec this should be done even if CRC is not valid so we - * can store it here - */ - if (sm->flags & BLE_LL_SYNC_SM_FLAG_SET_ANCHOR) { - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_SET_ANCHOR; - - sm->anchor_point = hdr->beg_cputime; - sm->anchor_point_usecs = hdr->rem_usecs; - sm->last_anchor_point = sm->anchor_point; - } - - /* CRC error, end event */ - if (!BLE_MBUF_HDR_CRC_OK(hdr)) { - STATS_INC(ble_ll_stats, sync_crc_err); - goto end_event; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - /* save last pa counter */ - sm->event_cntr_last_received = sm->event_cntr; -#endif - - /* this means we are chaining but due to low buffers already sent data - * truncated report to host (or didn't sent any at all). If this happens - * next_buf should be already set to NULL and we just end event. - */ - if (sm->flags & BLE_LL_SYNC_SM_FLAG_HCI_TRUNCATED) { - BLE_LL_ASSERT(!sm->next_report); - goto end_event; - } - - /* get ext header data */ - datalen = ble_ll_sync_parse_ext_hdr(rxpdu, &aux, &tx_power, &acad, &acad_len); - if (datalen < 0) { - /* we got bad packet, end event */ - goto end_event; - } - - reports_enabled = ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT) && - !(sm->flags & BLE_LL_SYNC_SM_FLAG_DISABLED); - - /* no need to schedule for chain if reporting is disabled */ - if (reports_enabled) { - /* if aux is present, we need to schedule ASAP */ - if (aux && (ble_ll_sync_schedule_chain(sm, hdr, aux) == 0)) { - aux_scheduled = true; - } - } - - /* check ACAD, needs to be done before rxpdu is adjusted for ADV data */ - if (acad && !ble_ll_sync_check_acad(sm, acad, acad_len)) { - /* we got bad packet (bad ACAD data), end event */ - goto end_event; - } - - /* we need to establish link even if reporting was disabled */ - if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) { - ble_ll_sync_established(sm); - } - - /* only if reporting is enabled */ - if (reports_enabled) { - /* Adjust rxpdu to contain advertising data only */ - ble_ll_sync_adjust_ext_hdr(rxpdu); - - /* send reports from this PDU */ - ble_ll_sync_send_per_adv_rpt(sm, rxpdu, hdr->rxinfo.rssi, tx_power, - datalen, aux, aux_scheduled); - } - - /* if chain was scheduled we don't end event yet */ - /* TODO should we check resume only if offset is high? */ - if (aux_scheduled) { - ble_ll_scan_chk_resume(); - ble_ll_rfmgmt_release(); - return; - } - -end_event: - ble_ll_event_send(&sm->sync_ev_end); - ble_ll_rfmgmt_release(); -} - -static int -ble_ll_sync_next_event(struct ble_ll_sync_sm *sm, uint32_t cur_ww_adjust) -{ - uint32_t cur_ww; - uint32_t max_ww; - uint32_t ticks; - uint32_t itvl; - uint8_t usecs; - uint16_t skip = sm->skip; - - /* don't skip if are establishing sync or we missed last event */ - if (skip && ((sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) || - CPUTIME_LT(sm->last_anchor_point, sm->anchor_point))) { - skip = 0; - } - - /* Set next event start time, we can use pre-calculated values for one - * interval if not skipping - */ - if (skip == 0) { - ticks = sm->itvl_ticks; - usecs = sm->itvl_usecs; - } else { - itvl = sm->itvl * BLE_LL_SYNC_ITVL_USECS * (1 + skip); - ticks = os_cputime_usecs_to_ticks(itvl); - usecs = itvl - os_cputime_ticks_to_usecs(ticks); - } - - sm->anchor_point += ticks; - sm->anchor_point_usecs += usecs; - if (sm->anchor_point_usecs >= 31) { - sm->anchor_point++; - sm->anchor_point_usecs -= 31; - } - - /* Set event counter to the next event */ - sm->event_cntr += 1 + skip; - - /* update channel map if needed */ - if (sm->flags & BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP) { - if (((int16_t)(sm->event_cntr - sm->chanmap_new_instant)) >= 0) { - /* map was verified on reception */ - sm->chanmap[0] = sm->chanmap_new[0]; - sm->chanmap[1] = sm->chanmap_new[1]; - sm->chanmap[2] = sm->chanmap_new[2]; - sm->chanmap[3] = sm->chanmap_new[3]; - sm->chanmap[4] = sm->chanmap_new[4]; - sm->num_used_chans = ble_ll_utils_calc_num_used_chans(sm->chanmap); - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP; - } - } - - /* Calculate channel index of next event */ - sm->chan_index = ble_ll_utils_calc_dci_csa2(sm->event_cntr, sm->channel_id, - sm->num_used_chans, sm->chanmap); - - cur_ww = ble_ll_utils_calc_window_widening(sm->anchor_point, - sm->last_anchor_point, - sm->sca); - - cur_ww += cur_ww_adjust; - - max_ww = (sm->itvl * (BLE_LL_SYNC_ITVL_USECS / 2)) - BLE_LL_IFS; - if (cur_ww >= max_ww) { - return -1; - } - - cur_ww += BLE_LL_JITTER_USECS; - - /* if updated anchor is pass last anchor + timeout it means we will not be - * able to get it in time and hit sync timeout - * - * note that this may result in sync timeout being sent before real - * timeout but we won't be able to fit in time anyway.. - * - * We don't do that when establishing since we try up to - * BLE_LL_SYNC_ESTABLISH_CNT events before failing regardless of timeout - */ - if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING)) { - if (CPUTIME_GT(sm->anchor_point - os_cputime_usecs_to_ticks(cur_ww), - sm->last_anchor_point + sm->timeout )) { - return -1; - } - } - - sm->window_widening = cur_ww; - - return 0; -} - -static void -ble_ll_sync_event_end(struct ble_npl_event *ev) -{ - struct ble_ll_sync_sm *sm; - - /* Better be a connection state machine! */ - sm = ble_npl_event_get_arg(ev); - BLE_LL_ASSERT(sm); - - ble_ll_rfmgmt_release(); - - if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) { - ble_ll_sync_check_failed(sm); - } - - /* Check if we need to resume scanning */ - ble_ll_scan_chk_resume(); - - /* Remove any end events that might be enqueued */ - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &sm->sync_ev_end); - - /* don't schedule next event if sync is not established nor establishing - * at this point SM is no longer valid - */ - if (!(sm->flags & (BLE_LL_SYNC_SM_FLAG_ESTABLISHED | - BLE_LL_SYNC_SM_FLAG_ESTABLISHING))) { - ble_ll_sync_sm_clear(sm); - return; - } - - /* if we had prepared buffer for next even it means we were chaining and - * must send truncated report to host - */ - if (sm->next_report) { - BLE_LL_ASSERT(!(sm->flags & BLE_LL_SYNC_SM_FLAG_HCI_TRUNCATED)); - ble_ll_sync_send_truncated_per_adv_rpt(sm, sm->next_report); - sm->next_report = NULL; - } - - /* Event ended so we are no longer chaining */ - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_HCI_TRUNCATED; - - sm->sch.sched_cb = ble_ll_sync_event_start_cb; - sm->sch.cb_arg = sm; - sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; - - do { - if (ble_ll_sync_next_event(sm, 0) < 0) { - if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) { - /* don't allow any retry if this failed */ - sm->sync_pending_cnt = 1; - ble_ll_sync_check_failed(sm); - } else { - ble_ll_sync_lost_event(sm); - } - - /* at this point SM is no longer valid */ - ble_ll_sync_sm_clear(sm); - return; - } - } while (ble_ll_sched_sync_reschedule(&sm->sch, sm->anchor_point, - sm->anchor_point_usecs, - sm->window_widening, sm->phy_mode)); -} - -void -ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, int rpa_index, - uint8_t sid, struct ble_mbuf_hdr *rxhdr, - const uint8_t *syncinfo) -{ - struct ble_ll_sync_sm *sm = NULL; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - const uint8_t *rpa = NULL; -#endif - uint16_t max_skip; - uint32_t offset; - uint32_t usecs; - uint16_t itvl; - int i; - - /* ignore if not synchronizing */ - if (!g_ble_ll_sync_create_comp_ev) { - return; - } - - /* get reserved SM */ - for (i = 0; i < BLE_LL_SYNC_CNT; i++) { - if (g_ble_ll_sync_sm[i].flags & BLE_LL_SYNC_SM_FLAG_RESERVED) { - sm = &g_ble_ll_sync_sm[i]; - break; - } - } - - /* this means we already got sync info event and pending sync */ - if (!sm) { - return; - } - - /* check if resolved */ - if (rpa_index >= 0) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - rpa = addr; -#endif - addr = g_ble_ll_resolv_list[rpa_index].rl_identity_addr; - addr_type = g_ble_ll_resolv_list[rpa_index].rl_addr_type; - } - - /* check peer */ - if (g_ble_ll_sync_create_params.options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER) { - if (ble_ll_sync_on_list(addr, addr_type, sid) < 0) { - return; - } - - /* set addr and sid in sm */ - sm->adv_sid = sid; - sm->adv_addr_type = addr_type; - memcpy(sm->adv_addr, addr, BLE_DEV_ADDR_LEN); - } else { - if ((sm->adv_sid != sid) || (sm->adv_addr_type != addr_type) || - memcmp(sm->adv_addr, addr, BLE_DEV_ADDR_LEN)) { - return; - } - } - - /* Sync Packet Offset (13 bits), Offset Units (1 bit), RFU (2 bits) */ - offset = syncinfo[0]; - offset |= (uint16_t)(syncinfo[1] & 0x1f) << 8; - - /* ignore if offset is not valid */ - if (!offset) { - return; - } - - /* Interval (2 bytes), ignore if invalid */ - itvl = get_le16(&syncinfo[2]); - if (itvl < 6) { - return; - } - - if (rpa_index >= 0) { - sm->flags |= BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - memcpy(sm->adv_addr_rpa, rpa, BLE_DEV_ADDR_LEN); -#endif - } - - /* set params from HCI LE Create Periodic Sync */ - sm->timeout = g_ble_ll_sync_create_params.timeout; - sm->skip = g_ble_ll_sync_create_params.max_skip; - sm->sync_pending_cnt = BLE_LL_SYNC_ESTABLISH_CNT; - - if (syncinfo[1] & 0x20) { - offset *= 300; - sm->flags |= BLE_LL_SYNC_SM_FLAG_OFFSET_300; - } else { - offset *= 30; - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_OFFSET_300; - } - - /* sync end event */ - ble_npl_event_init(&sm->sync_ev_end, ble_ll_sync_event_end, sm); - - sm->itvl = itvl; - - /* precalculate interval ticks and usecs */ - usecs = sm->itvl * BLE_LL_SYNC_ITVL_USECS; - sm->itvl_ticks = os_cputime_usecs_to_ticks(usecs); - sm->itvl_usecs = (uint8_t)(usecs - - os_cputime_ticks_to_usecs(sm->itvl_ticks)); - if (sm->itvl_usecs == 31) { - sm->itvl_usecs = 0; - sm->itvl_ticks++; - } - - /* Channels Mask (37 bits) */ - sm->chanmap[0] = syncinfo[4]; - sm->chanmap[1] = syncinfo[5]; - sm->chanmap[2] = syncinfo[6]; - sm->chanmap[3] = syncinfo[7]; - sm->chanmap[4] = syncinfo[8] & 0x1f; - sm->num_used_chans = ble_ll_utils_calc_num_used_chans(sm->chanmap); - - /* SCA (3 bits) */ - sm->sca = syncinfo[8] >> 5; - - /* AA (4 bytes) */ - sm->access_addr = get_le32(&syncinfo[9]); - sm->channel_id = ((sm->access_addr & 0xffff0000) >> 16) ^ - (sm->access_addr & 0x0000ffff); - - /* CRCInit (3 bytes) */ - sm->crcinit = syncinfo[15]; - sm->crcinit = (sm->crcinit << 8) | syncinfo[14]; - sm->crcinit = (sm->crcinit << 8) | syncinfo[13]; - - /* Event Counter (2 bytes) */ - sm->event_cntr = get_le16(&syncinfo[16]); - - /* adjust skip if pass timeout */ - max_skip = get_max_skip(sm->itvl * BLE_LL_SYNC_ITVL_USECS, sm->timeout); - if (sm->skip > max_skip) { - sm->skip = max_skip; - } - - /* from now on we only need timeout in ticks */ - sm->timeout = os_cputime_usecs_to_ticks(sm->timeout); - - sm->phy_mode = rxhdr->rxinfo.phy_mode; - sm->window_widening = BLE_LL_JITTER_USECS; - - /* Calculate channel index of first event */ - sm->chan_index = ble_ll_utils_calc_dci_csa2(sm->event_cntr, sm->channel_id, - sm->num_used_chans, sm->chanmap); - - sm->sch.sched_cb = ble_ll_sync_event_start_cb; - sm->sch.cb_arg = sm; - sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; - - if (ble_ll_sched_sync(&sm->sch, rxhdr->beg_cputime, rxhdr->rem_usecs, - offset, sm->phy_mode)) { - return; - } - - sm->anchor_point = sm->sch.start_time + g_ble_ll_sched_offset_ticks; - sm->anchor_point_usecs = sm->sch.remainder; - sm->last_anchor_point = sm->anchor_point; - -#if MYNEWT_VAL(BLE_VERSION) >= 51 - if (g_ble_ll_sync_create_params.options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DISABLED) { - sm->flags |= BLE_LL_SYNC_SM_FLAG_DISABLED; - } -#endif - - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_RESERVED; - sm->flags |= BLE_LL_SYNC_SM_FLAG_ESTABLISHING; - sm->flags |= BLE_LL_SYNC_SM_FLAG_SYNC_INFO; -} - -static struct ble_ll_sync_sm * -ble_ll_sync_reserve(void) -{ - struct ble_ll_sync_sm *sm; - int i; - - for (i = 0; i < BLE_LL_SYNC_CNT; i++) { - sm = &g_ble_ll_sync_sm[i]; - - if (!sm->flags) { - sm->flags |= BLE_LL_SYNC_SM_FLAG_RESERVED; - return sm; - } - } - - return NULL; -} - -int -ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_periodic_adv_create_sync_cp *cmd = (const void *) cmdbuf; - struct ble_ll_sync_sm *sm; - uint16_t timeout; - os_sr_t sr; - - if (g_ble_ll_sync_create_comp_ev) { - return BLE_ERR_CMD_DISALLOWED; - } - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - -#if MYNEWT_VAL(BLE_VERSION) >= 51 - if (cmd->options > BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DISABLED) { -#else - if (cmd->options > BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER) { -#endif - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (cmd->skip > 0x01f3) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - timeout = le16toh(cmd->sync_timeout); - if (timeout < 0x000a || timeout > 0x4000) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - -#if MYNEWT_VAL(BLE_VERSION) >= 51 - /* we don't support any CTE yet */ - if (cmd->sync_cte_type) { - if (cmd->sync_cte_type > 4) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - return BLE_ERR_UNSUPPORTED; - } -#endif - - if (cmd->options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER) { - if (ble_ll_sync_list_empty()) { - return BLE_ERR_CMD_DISALLOWED; - } - } else { - if (cmd->sid > 0x0f) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (cmd->peer_addr_type > BLE_HCI_ADV_PEER_ADDR_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - OS_ENTER_CRITICAL(sr); - sm = ble_ll_sync_find(cmd->peer_addr, cmd->peer_addr_type, cmd->sid); - OS_EXIT_CRITICAL(sr); - - if (sm) { - return BLE_ERR_ACL_CONN_EXISTS; - } - } - - /* reserve buffer for sync complete event */ - g_ble_ll_sync_create_comp_ev = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (!g_ble_ll_sync_create_comp_ev) { - return BLE_ERR_MEM_CAPACITY; - } - - OS_ENTER_CRITICAL(sr); - - /* reserve 1 SM for created sync */ - sm = ble_ll_sync_reserve(); - if (!sm) { - ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev); - g_ble_ll_sync_create_comp_ev = NULL; - OS_EXIT_CRITICAL(sr); - return BLE_ERR_MEM_CAPACITY; - } - - /* if we don't use list, store expected address in reserved SM */ - if (!(cmd->options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER)) { - sm->adv_sid = cmd->sid; - sm->adv_addr_type = cmd->peer_addr_type; - memcpy(&sm->adv_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); - } - - g_ble_ll_sync_create_params.timeout = timeout * 10000; /* 10ms units, store in us */; - g_ble_ll_sync_create_params.max_skip = cmd->skip; - g_ble_ll_sync_create_params.options = cmd->options; - - OS_EXIT_CRITICAL(sr); - return BLE_ERR_SUCCESS; -} - -static void -ble_ll_sync_cancel_complete_event(void) -{ - ble_ll_sync_est_event_failed(BLE_ERR_OPERATION_CANCELLED); -} - -int -ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) -{ - struct ble_ll_sync_sm *sm; - os_sr_t sr; - int i; - - if (!g_ble_ll_sync_create_comp_ev) { - return BLE_ERR_CMD_DISALLOWED; - } - - OS_ENTER_CRITICAL(sr); - - for (i = 0; i < BLE_LL_SYNC_CNT; i++) { - sm = &g_ble_ll_sync_sm[i]; - - /* cancelled before fist sync info packet */ - if (sm->flags & BLE_LL_SYNC_SM_FLAG_RESERVED) { - memset(sm, 0, sizeof(*sm)); - break; - } - - /* cancelled while pending sync */ - if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) { - ble_ll_sync_sm_clear(sm); - break; - } - } - - OS_EXIT_CRITICAL(sr); - - /* g_ble_ll_sync_create_comp_ev will be cleared by this callback */ - *post_cmd_cb = ble_ll_sync_cancel_complete_event; - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_sync_terminate(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_periodic_adv_term_sync_cp *cmd = (const void *) cmdbuf; - struct ble_ll_sync_sm *sm; - uint16_t handle; - os_sr_t sr; - - if (g_ble_ll_sync_create_comp_ev) { - return BLE_ERR_CMD_DISALLOWED; - } - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - handle = le16toh(cmd->sync_handle); - if (handle > 0xeff) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (handle >= BLE_LL_SYNC_CNT) { - return BLE_ERR_UNK_ADV_INDENT; - } - - sm = &g_ble_ll_sync_sm[handle]; - - OS_ENTER_CRITICAL(sr); - - if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED)) { - OS_EXIT_CRITICAL(sr); - return BLE_ERR_UNK_ADV_INDENT; - } - - ble_ll_sync_sm_clear(sm); - - OS_EXIT_CRITICAL(sr); - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_sync_list_add(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_add_dev_to_periodic_adv_list_cp *cmd = (const void *)cmdbuf; - int i; - - if (g_ble_ll_sync_create_comp_ev) { - return BLE_ERR_CMD_DISALLOWED; - } - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (cmd->peer_addr_type > BLE_HCI_ADV_PEER_ADDR_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - if (cmd->sid > 0x0f) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - i = ble_ll_sync_on_list(cmd->peer_addr, cmd->peer_addr_type, cmd->sid); - if (i >= 0) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - i = ble_ll_sync_list_get_free(); - if (i < 0) { - return BLE_ERR_MEM_CAPACITY; - } - - g_ble_ll_sync_adv_list[i].adv_sid = cmd->sid; - g_ble_ll_sync_adv_list[i].adv_addr_type = cmd->peer_addr_type; - memcpy(&g_ble_ll_sync_adv_list[i].adv_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_rem_dev_from_periodic_adv_list_cp *cmd = (const void *)cmdbuf; - int i; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (g_ble_ll_sync_create_comp_ev) { - return BLE_ERR_CMD_DISALLOWED; - } - - if (cmd->peer_addr_type > BLE_HCI_ADV_PEER_ADDR_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (cmd->sid > 0x0f) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - i = ble_ll_sync_on_list(cmd->peer_addr, cmd->peer_addr_type, cmd->sid); - if (i < 0) { - return BLE_ERR_UNK_ADV_INDENT; - } - - memset(&g_ble_ll_sync_adv_list[i], 0, sizeof(g_ble_ll_sync_adv_list[i])); - g_ble_ll_sync_adv_list[i].adv_sid = 0xff; - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_sync_list_clear(void) -{ - int i; - - if (g_ble_ll_sync_create_comp_ev) { - return BLE_ERR_CMD_DISALLOWED; - } - - for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { - memset(&g_ble_ll_sync_adv_list[i], 0, sizeof(g_ble_ll_sync_adv_list[i])); - g_ble_ll_sync_adv_list[i].adv_sid = 0xff; - } - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_sync_list_size(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_periodic_adv_list_size_rp *rsp = (void *) rspbuf; - - rsp->list_size = ARRAY_SIZE(g_ble_ll_sync_adv_list); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -#if MYNEWT_VAL(BLE_VERSION) >= 51 -int -ble_ll_sync_receive_enable(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_periodic_adv_receive_enable_cp *cmd = (const void *)cmdbuf; - struct ble_ll_sync_sm *sm; - uint16_t handle; - os_sr_t sr; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (cmd->enable > 0x01) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - handle = le16toh(cmd->sync_handle); - if (handle > 0xeff) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (handle >= BLE_LL_SYNC_CNT) { - return BLE_ERR_UNK_ADV_INDENT; - } - - sm = &g_ble_ll_sync_sm[handle]; - - OS_ENTER_CRITICAL(sr); - - if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED)) { - OS_EXIT_CRITICAL(sr); - return BLE_ERR_UNK_ADV_INDENT; - } - - if (cmd->enable) { - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_DISABLED; - } else { - sm->flags |= BLE_LL_SYNC_SM_FLAG_DISABLED; - } - - OS_EXIT_CRITICAL(sr); - return BLE_ERR_SUCCESS; -} -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -static struct ble_ll_sync_sm * -ble_ll_sync_transfer_get(const uint8_t *addr, uint8_t addr_type, uint8_t sid) -{ - struct ble_ll_sync_sm *sm; - int i; - - for (i = 0; i < BLE_LL_SYNC_CNT; i++) { - sm = &g_ble_ll_sync_sm[i]; - - if (!sm->flags) { - /* allocate event for transfer received event */ - sm->transfer_received_ev = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (!sm->transfer_received_ev) { - break; - } - - sm->adv_sid = sid; - sm->adv_addr_type = addr_type; - memcpy(&sm->adv_addr, addr, BLE_DEV_ADDR_LEN); - - sm->flags |= BLE_LL_SYNC_SM_FLAG_ESTABLISHING; - return sm; - } - } - - return NULL; -} - -void -ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, - const uint8_t *sync_ind, bool reports_disabled, - uint16_t max_skip, uint32_t sync_timeout) -{ - const uint8_t *syncinfo = sync_ind + 2; - uint16_t sync_conn_event_count; - uint16_t last_pa_event_count; - struct ble_ll_sync_sm *sm; - uint16_t conn_event_count; - uint8_t sync_anchor_usecs; - const uint8_t *rpa = NULL; - int last_pa_diff; - uint32_t sync_anchor; - const uint8_t *addr; - uint16_t event_cntr; - uint32_t itvl_usecs; - uint32_t ww_adjust; - uint8_t addr_type; - uint8_t phy_mode; - uint32_t offset; - uint32_t future; - uint16_t itvl; - int rpa_index; - uint8_t sid; - uint8_t sca; - os_sr_t sr; - - phy_mode = ble_ll_ctrl_phy_from_phy_mask(sync_ind[25]); - itvl = get_le16(syncinfo + 2); - /* ignore if sync params are not valid */ - if ((phy_mode == 0) || (itvl < 6)) { - return; - } - - last_pa_event_count = get_le16(sync_ind + 22); - event_cntr = get_le16(syncinfo + 16); - itvl_usecs = itvl * BLE_LL_SYNC_ITVL_USECS; - - last_pa_diff = abs((int16_t)(event_cntr - last_pa_event_count)); - /* check if not 5 seconds apart, if so ignore sync transfer */ - if ((last_pa_diff * itvl_usecs) > 5000000) { - return; - } - - sid = (sync_ind[24] & 0x0f); - addr_type = (sync_ind[24] & 0x10) ? BLE_ADDR_RANDOM : BLE_ADDR_PUBLIC; - addr = sync_ind + 26; - - rpa_index = -1; - - /* check if need to resolve */ - if (ble_ll_is_rpa(addr, addr_type)) { - rpa_index = ble_ll_resolv_peer_rpa_any(addr); - if (rpa_index >= 0) { - rpa = addr; - addr = g_ble_ll_resolv_list[rpa_index].rl_identity_addr; - addr_type = g_ble_ll_resolv_list[rpa_index].rl_addr_type; - } - } - - OS_ENTER_CRITICAL(sr); - /* check if already synchronized with this peer */ - sm = ble_ll_sync_find(addr, addr_type, sid); - if (sm) { - OS_EXIT_CRITICAL(sr); - return; - } - - /* ignore if no memory for new sync */ - sm = ble_ll_sync_transfer_get(addr, addr_type, sid); - if (!sm) { - OS_EXIT_CRITICAL(sr); - return; - } - - OS_EXIT_CRITICAL(sr); - - if (rpa_index >= 0) { - sm->flags |= BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED; - memcpy(sm->adv_addr_rpa, rpa, BLE_DEV_ADDR_LEN); - } - - /* set params from transfer */ - sm->timeout = os_cputime_usecs_to_ticks(sync_timeout); - sm->skip = max_skip; - sm->sync_pending_cnt = BLE_LL_SYNC_ESTABLISH_CNT; - sm->transfer_id = get_le16(sync_ind); /* first two bytes */ - sm->transfer_conn = connsm; - - /* Sync Packet Offset (13 bits), Offset Units (1 bit), Offset Adjust (1 bit), - * RFU (1 bit) - */ - offset = syncinfo[0]; - offset |= (uint16_t)(syncinfo[1] & 0x1f) << 8; - - if (syncinfo[1] & 0x20) { - if (syncinfo[1] & 0x40) { - offset += 0x2000; - } - - offset *= 300; - sm->flags |= BLE_LL_SYNC_SM_FLAG_OFFSET_300; - } else { - offset *= 30; - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_OFFSET_300; - } - - /* sync end event */ - ble_npl_event_init(&sm->sync_ev_end, ble_ll_sync_event_end, sm); - - sm->itvl = itvl; - - /* precalculate interval ticks and usecs */ - sm->itvl_ticks = os_cputime_usecs_to_ticks(itvl_usecs); - sm->itvl_usecs = (uint8_t)(itvl_usecs - - os_cputime_ticks_to_usecs(sm->itvl_ticks)); - if (sm->itvl_usecs == 31) { - sm->itvl_usecs = 0; - sm->itvl_ticks++; - } - - /* Channels Mask (37 bits) */ - sm->chanmap[0] = syncinfo[4]; - sm->chanmap[1] = syncinfo[5]; - sm->chanmap[2] = syncinfo[6]; - sm->chanmap[3] = syncinfo[7]; - sm->chanmap[4] = syncinfo[8] & 0x1f; - sm->num_used_chans = ble_ll_utils_calc_num_used_chans(sm->chanmap); - - /* SCA (3 bits) */ - sm->sca = syncinfo[8] >> 5; - - /* AA (4 bytes) */ - sm->access_addr = get_le32(syncinfo + 9); - sm->channel_id = ((sm->access_addr & 0xffff0000) >> 16) ^ - (sm->access_addr & 0x0000ffff); - - /* CRCInit (3 bytes) */ - sm->crcinit = syncinfo[13]; - sm->crcinit |= syncinfo[14] << 8; - sm->crcinit |= syncinfo[15] << 16; - - /* Event Counter (2 bytes) */ - sm->event_cntr = event_cntr; - - /* adjust skip if pass timeout */ - max_skip = get_max_skip(sm->itvl * BLE_LL_SYNC_ITVL_USECS, sync_timeout); - if (sm->skip > max_skip) { - sm->skip = max_skip; - } - - sm->phy_mode = phy_mode; - - /* Calculate channel index of first event */ - sm->chan_index = ble_ll_utils_calc_dci_csa2(sm->event_cntr, sm->channel_id, - sm->num_used_chans, sm->chanmap); - - sm->sch.sched_cb = ble_ll_sync_event_start_cb; - sm->sch.cb_arg = sm; - sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; - - /* get anchor for specified conn event */ - conn_event_count = get_le16(sync_ind + 20); - ble_ll_conn_get_anchor(connsm, conn_event_count, &sm->anchor_point, - &sm->anchor_point_usecs); - - /* Set last anchor point */ - sm->last_anchor_point = sm->anchor_point - (last_pa_diff * sm->itvl_ticks); - - /* calculate extra window widening */ - sync_conn_event_count = get_le16(sync_ind + 32); - sca = sync_ind[24] >> 5; - ble_ll_conn_get_anchor(connsm, sync_conn_event_count, &sync_anchor, - &sync_anchor_usecs); - ww_adjust = ble_ll_utils_calc_window_widening(connsm->anchor_point, - sync_anchor, sca); - - /* spin until we get anchor in future */ - future = os_cputime_get32() + g_ble_ll_sched_offset_ticks; - while (CPUTIME_LT(sm->anchor_point, future)) { - if (ble_ll_sync_next_event(sm, ww_adjust) < 0) { - /* release SM if this failed */ - ble_ll_sync_transfer_received(sm, BLE_ERR_CONN_ESTABLISHMENT); - memset(sm, 0, sizeof(*sm)); - return; - } - } - - if (ble_ll_sched_sync(&sm->sch, sm->anchor_point, sm->anchor_point_usecs, - offset, sm->phy_mode)) { - /* release SM if this failed */ - ble_ll_sync_transfer_received(sm, BLE_ERR_CONN_ESTABLISHMENT); - memset(sm, 0, sizeof(*sm)); - return; - } - - /* Set new anchor point */ - sm->anchor_point = sm->sch.start_time + g_ble_ll_sched_offset_ticks; - sm->anchor_point_usecs = sm->sch.remainder; - - if (reports_disabled) { - sm->flags |= BLE_LL_SYNC_SM_FLAG_DISABLED; - } -} - -static void -ble_ll_sync_put_syncinfo(struct ble_ll_sync_sm *syncsm, - struct ble_ll_conn_sm *connsm, uint8_t *conn_event_cnt, - uint8_t *dptr) -{ - uint8_t anchor_usecs; - uint16_t conn_cnt; - uint32_t offset; - uint32_t anchor; - uint8_t units; - - anchor = connsm->anchor_point; - anchor_usecs = connsm->anchor_point_usecs; - conn_cnt = connsm->event_cntr; - - /* get anchor for conn event that is before periodic_adv_event_start_time */ - while (CPUTIME_GT(anchor, syncsm->anchor_point)) { - ble_ll_conn_get_anchor(connsm, --conn_cnt, &anchor, &anchor_usecs); - } - - offset = os_cputime_ticks_to_usecs(syncsm->anchor_point - anchor); - offset -= anchor_usecs; - offset += syncsm->anchor_point_usecs; - - /* connEventCount */ - put_le16(conn_event_cnt, conn_cnt); - - /* Sync Packet Offset (13 bits), Offset Units (1 bit), Offset Adjust (1 bit), - * RFU (1 bit) - */ - if (offset > 245700) { - units = 0x20; - - if (offset >= 0x2000) { - offset -= 0x2000; - units |= 0x40; - } - - offset = offset / 300; - } else { - units = 0x00; - offset = offset / 30; - } - - dptr[0] = (offset & 0x000000ff); - dptr[1] = ((offset >> 8) & 0x0000001f) | units; - - /* Interval (2 bytes) */ - put_le16(&dptr[2], syncsm->itvl); - - /* Channels Mask (37 bits) */ - dptr[4] = syncsm->chanmap[0]; - dptr[5] = syncsm->chanmap[1]; - dptr[6] = syncsm->chanmap[2]; - dptr[7] = syncsm->chanmap[3]; - dptr[8] = syncsm->chanmap[4] & 0x1f; - - /* SCA (3 bits) */ - dptr[8] |= syncsm->sca << 5; - - /* AA (4 bytes) */ - put_le32(&dptr[9], syncsm->access_addr); - - /* CRCInit (3 bytes) */ - dptr[13] = (uint8_t)syncsm->crcinit; - dptr[14] = (uint8_t)(syncsm->crcinit >> 8); - dptr[15] = (uint8_t)(syncsm->crcinit >> 16); - - /* Event Counter (2 bytes) */ - put_le16(&dptr[16], syncsm->event_cntr); -} - -static int -ble_ll_sync_send_sync_ind(struct ble_ll_sync_sm *syncsm, - struct ble_ll_conn_sm *connsm, uint16_t service_data) -{ - struct os_mbuf *om; - uint8_t *sync_ind; - - om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN, - sizeof(struct ble_mbuf_hdr)); - if (!om) { - return BLE_ERR_MEM_CAPACITY; - } - - om->om_data[0] = BLE_LL_CTRL_PERIODIC_SYNC_IND; - - sync_ind = om->om_data + 1; - - /* ID (service_data), already in LE order */ - memcpy(sync_ind, &service_data, sizeof(service_data)); - - /* fill in syncinfo */ - ble_ll_sync_put_syncinfo(syncsm, connsm, sync_ind + 20, sync_ind + 2); - - /* lastPaEventCounter */ - put_le16(sync_ind + 22, syncsm->event_cntr_last_received); - - /* SID, AType, SCA */ - sync_ind[24] = syncsm->adv_sid; - - if (syncsm->flags & BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED) { - sync_ind[24] |= 1 << 4; - } else { - sync_ind[24] |= (syncsm->adv_addr_type == BLE_ADDR_RANDOM) << 4; - } - - sync_ind[24] |= BLE_LL_SCA_ENUM << 5; - - /* PHY */ - sync_ind[25] = (0x01 << (ble_ll_sync_phy_mode_to_hci(syncsm->phy_mode) - 1)); - - /* AdvA */ - if (syncsm->flags & BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED) { - memcpy(sync_ind + 26, syncsm->adv_addr_rpa, BLE_DEV_ADDR_LEN); - } else { - memcpy(sync_ind + 26, syncsm->adv_addr, BLE_DEV_ADDR_LEN); - } - - /* syncConnEventCount */ - put_le16(sync_ind + 32, connsm->event_cntr); - - ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, - BLE_LL_CTRL_PERIODIC_SYNC_IND_LEN + 1); - - return BLE_ERR_SUCCESS; -} - -int -ble_ll_sync_transfer(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - const struct ble_hci_le_periodic_adv_sync_transfer_cp *cmd = (const void *)cmdbuf; - struct ble_hci_le_periodic_adv_sync_transfer_rp *rsp = (void *) rspbuf; - struct ble_ll_conn_sm *connsm; - struct ble_ll_sync_sm *sm; - uint16_t handle; - os_sr_t sr; - int rc; - - if (len != sizeof(*cmd)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - handle = le16toh(cmd->sync_handle); - if (handle > 0xeff) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - - if (handle >= BLE_LL_SYNC_CNT) { - rc = BLE_ERR_UNK_ADV_INDENT; - goto done; - } - - sm = &g_ble_ll_sync_sm[handle]; - - OS_ENTER_CRITICAL(sr); - - if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED)) { - rc = BLE_ERR_UNK_ADV_INDENT; - OS_EXIT_CRITICAL(sr); - goto done; - } - - handle = le16toh(cmd->conn_handle); - if (handle > 0xeff) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - OS_EXIT_CRITICAL(sr); - goto done; - } - - connsm = ble_ll_conn_find_active_conn(handle); - if (!connsm) { - rc = BLE_ERR_UNK_CONN_ID; - OS_EXIT_CRITICAL(sr); - goto done; - } - - /* TODO should not need to shift - * byte 3 (0 byte is conn_feature) , bit 1 - * - * Allow initiate LL procedure only if remote supports it. - */ - if (!(connsm->remote_features[2] & (BLE_LL_FEAT_SYNC_TRANS_RECV >> (8 * 3)))) { - rc = BLE_ERR_UNSUPP_REM_FEATURE; - goto done; - } - - rc = ble_ll_sync_send_sync_ind(sm, connsm, cmd->service_data); - - OS_EXIT_CRITICAL(sr); -done: - rsp->conn_handle = cmd->conn_handle; - *rsplen = sizeof(*rsp); - return rc; -} -#endif - -/* - * Called when a sync scan event has been removed from the scheduler - * without being run. - */ -void -ble_ll_sync_rmvd_from_sched(struct ble_ll_sync_sm *sm) -{ - ble_ll_event_send(&sm->sync_ev_end); -} - -bool -ble_ll_sync_enabled(void) -{ - return g_ble_ll_sync_create_comp_ev != NULL; -} - -/** - * Called to reset the sync module. When this function is called the - * scheduler has been stopped and the phy has been disabled. The LL should - * be in the standby state. - */ -void -ble_ll_sync_reset(void) -{ - int i; - - for (i = 0; i < BLE_LL_SYNC_CNT; i++) { - ble_ll_sync_sm_clear(&g_ble_ll_sync_sm[i]); - } - - for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { - memset(&g_ble_ll_sync_adv_list[i], 0, sizeof(g_ble_ll_sync_adv_list[i])); - g_ble_ll_sync_adv_list[i].adv_sid = 0xff; - } - - g_ble_ll_sync_create_params.timeout = 0; - g_ble_ll_sync_create_params.max_skip = 0; - g_ble_ll_sync_create_params.options = 0; - - g_ble_ll_sync_sm_current = NULL; - - if (g_ble_ll_sync_create_comp_ev) { - ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev); - g_ble_ll_sync_create_comp_ev = NULL; - } -} - -void -ble_ll_sync_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { - g_ble_ll_sync_adv_list[i].adv_sid = 0xff; - } -} -#endif -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_trace.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_trace.c deleted file mode 100644 index c5d2b1d41..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_trace.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os_trace_api.h" - -#if MYNEWT_VAL(BLE_LL_SYSVIEW) - -static os_trace_module_t g_ble_ll_trace_mod; -uint32_t ble_ll_trace_off; - -static void -ble_ll_trace_module_send_desc(void) -{ - os_trace_module_desc(&g_ble_ll_trace_mod, "0 ll_sched lls=%u cputime=%u start_time=%u"); - os_trace_module_desc(&g_ble_ll_trace_mod, "1 ll_rx_start lls=%u pdu_type=%x"); - os_trace_module_desc(&g_ble_ll_trace_mod, "2 ll_rx_end pdu_type=%x len=%u flags=%x"); - os_trace_module_desc(&g_ble_ll_trace_mod, "3 ll_wfr_timer_exp lls=%u xcvr=%u rx_start=%u"); - os_trace_module_desc(&g_ble_ll_trace_mod, "4 ll_ctrl_rx opcode=%u len=%u"); - os_trace_module_desc(&g_ble_ll_trace_mod, "5 ll_conn_ev_start conn_handle=%u"); - os_trace_module_desc(&g_ble_ll_trace_mod, "6 ll_conn_ev_end conn_handle=%u event_cntr=%u"); - os_trace_module_desc(&g_ble_ll_trace_mod, "7 ll_conn_end conn_handle=%u event_cntr=%u err=%u"); - os_trace_module_desc(&g_ble_ll_trace_mod, "8 ll_conn_tx len=%u offset=%u"); - os_trace_module_desc(&g_ble_ll_trace_mod, "9 ll_conn_rx conn_sn=%u pdu_nesn=%u"); - os_trace_module_desc(&g_ble_ll_trace_mod, "10 ll_adv_txdone inst=%u chanset=%x"); - os_trace_module_desc(&g_ble_ll_trace_mod, "11 ll_adv_halt inst=%u"); - os_trace_module_desc(&g_ble_ll_trace_mod, "12 ll_aux_ref aux=%p ref=%u"); - os_trace_module_desc(&g_ble_ll_trace_mod, "13 ll_aux_unref aux=%p ref=%u"); -} - -void -ble_ll_trace_init(void) -{ - ble_ll_trace_off = - os_trace_module_register(&g_ble_ll_trace_mod, "ble_ll", 12, - ble_ll_trace_module_send_desc); -} -#endif -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_utils.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_utils.c deleted file mode 100644 index cdf6b60c6..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_utils.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include -#include "nimble/nimble/include/nimble/ble.h" -#include "../include/controller/ble_ll.h" -#include "../include/controller/ble_ll_utils.h" - -/* 37 bits require 5 bytes */ -#define BLE_LL_CHMAP_LEN (5) - -/* Sleep clock accuracy table (in ppm) */ -static const uint16_t g_ble_sca_ppm_tbl[8] = { - 500, 250, 150, 100, 75, 50, 30, 20 -}; - -uint32_t -ble_ll_utils_calc_access_addr(void) -{ - uint32_t aa; - uint16_t aa_low; - uint16_t aa_high; - uint32_t temp; - uint32_t mask; - uint32_t prev_bit; - uint8_t bits_diff; - uint8_t consecutive; - uint8_t transitions; - uint8_t ones; - int tmp; - - /* Calculate a random access address */ - aa = 0; - while (1) { - /* Get two, 16-bit random numbers */ - aa_low = ble_ll_rand() & 0xFFFF; - aa_high = ble_ll_rand() & 0xFFFF; - - /* All four bytes cannot be equal */ - if (aa_low == aa_high) { - continue; - } - - /* Upper 6 bits must have 2 transitions */ - tmp = (int16_t)aa_high >> 10; - if (__builtin_popcount(tmp ^ (tmp >> 1)) < 2) { - continue; - } - - /* Cannot be access address or be 1 bit different */ - aa = aa_high; - aa = (aa << 16) | aa_low; - bits_diff = 0; - temp = aa ^ BLE_ACCESS_ADDR_ADV; - for (mask = 0x00000001; mask != 0; mask <<= 1) { - if (mask & temp) { - ++bits_diff; - if (bits_diff > 1) { - break; - } - } - } - if (bits_diff <= 1) { - continue; - } - - /* Cannot have more than 24 transitions */ - transitions = 0; - consecutive = 1; - ones = 0; - mask = 0x00000001; - while (mask < 0x80000000) { - prev_bit = aa & mask; - mask <<= 1; - if (mask & aa) { - if (prev_bit == 0) { - ++transitions; - consecutive = 1; - } else { - ++consecutive; - } - } else { - if (prev_bit == 0) { - ++consecutive; - } else { - ++transitions; - consecutive = 1; - } - } - - if (prev_bit) { - ones++; - } - - /* 8 lsb should have at least three 1 */ - if (mask == 0x00000100 && ones < 3) { - break; - } - - /* 16 lsb should have no more than 11 transitions */ - if (mask == 0x00010000 && transitions > 11) { - break; - } - - /* This is invalid! */ - if (consecutive > 6) { - /* Make sure we always detect invalid sequence below */ - mask = 0; - break; - } - } - - /* Invalid sequence found */ - if (mask != 0x80000000) { - continue; - } - - /* Cannot be more than 24 transitions */ - if (transitions > 24) { - continue; - } - - /* We have a valid access address */ - break; - } - return aa; -} - -uint8_t -ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap) -{ - uint8_t cntr; - uint8_t mask; - uint8_t usable_chans; - uint8_t chan; - int i, j; - - /* NOTE: possible to build a map but this would use memory. For now, - * we just calculate - * Iterate through channel map to find this channel - */ - chan = 0; - cntr = 0; - for (i = 0; i < BLE_LL_CHMAP_LEN; i++) { - usable_chans = chanmap[i]; - if (usable_chans != 0) { - mask = 0x01; - for (j = 0; j < 8; j++) { - if (usable_chans & mask) { - if (cntr == remap_index) { - return (chan + j); - } - ++cntr; - } - mask <<= 1; - } - } - chan += 8; - } - - /* we should never reach here */ - BLE_LL_ASSERT(0); - return 0; -} - -uint8_t -ble_ll_utils_calc_num_used_chans(const uint8_t *chmap) -{ - int i; - int j; - uint8_t mask; - uint8_t chanbyte; - uint8_t used_channels; - - used_channels = 0; - for (i = 0; i < BLE_LL_CHMAP_LEN; ++i) { - chanbyte = chmap[i]; - if (chanbyte) { - if (chanbyte == 0xff) { - used_channels += 8; - } else { - mask = 0x01; - for (j = 0; j < 8; ++j) { - if (chanbyte & mask) { - ++used_channels; - } - mask <<= 1; - } - } - } - } - return used_channels; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) -static uint16_t -ble_ll_utils_csa2_perm(uint16_t in) -{ - uint16_t out = 0; - int i; - - for (i = 0; i < 8; i++) { - out |= ((in >> i) & 0x00000001) << (7 - i); - } - - for (i = 8; i < 16; i++) { - out |= ((in >> i) & 0x00000001) << (15 + 8 - i); - } - - return out; -} - -static uint16_t -ble_ll_utils_csa2_prng(uint16_t counter, uint16_t ch_id) -{ - uint16_t prn_e; - - prn_e = counter ^ ch_id; - - prn_e = ble_ll_utils_csa2_perm(prn_e); - prn_e = (prn_e * 17) + ch_id; - - prn_e = ble_ll_utils_csa2_perm(prn_e); - prn_e = (prn_e * 17) + ch_id; - - prn_e = ble_ll_utils_csa2_perm(prn_e); - prn_e = (prn_e * 17) + ch_id; - - prn_e = prn_e ^ ch_id; - - return prn_e; -} - -uint8_t -ble_ll_utils_calc_dci_csa2(uint16_t event_cntr, uint16_t channel_id, - uint8_t num_used_chans, const uint8_t *chanmap) -{ - uint16_t channel_unmapped; - uint8_t remap_index; - - uint16_t prn_e; - uint8_t bitpos; - - prn_e = ble_ll_utils_csa2_prng(event_cntr, channel_id); - - channel_unmapped = prn_e % 37; - - /* - * If unmapped channel is the channel index of a used channel it is used - * as channel index. - */ - bitpos = 1 << (channel_unmapped & 0x07); - if (chanmap[channel_unmapped >> 3] & bitpos) { - return channel_unmapped; - } - - remap_index = (num_used_chans * prn_e) / 0x10000; - - return ble_ll_utils_remapped_channel(remap_index, chanmap); -} -#endif - -uint32_t -ble_ll_utils_calc_window_widening(uint32_t anchor_point, - uint32_t last_anchor_point, - uint8_t master_sca) -{ - uint32_t total_sca_ppm; - uint32_t window_widening; - int32_t time_since_last_anchor; - uint32_t delta_msec; - - window_widening = 0; - - time_since_last_anchor = (int32_t)(anchor_point - last_anchor_point); - if (time_since_last_anchor > 0) { - delta_msec = os_cputime_ticks_to_usecs(time_since_last_anchor) / 1000; - total_sca_ppm = g_ble_sca_ppm_tbl[master_sca] + MYNEWT_VAL(BLE_LL_SCA); - window_widening = (total_sca_ppm * delta_msec) / 1000; - } - - return window_widening; -} -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_whitelist.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_whitelist.c deleted file mode 100644 index 8b9251117..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/controller/src/ble_ll_whitelist.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#ifndef ESP_PLATFORM - -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" - -#if defined(ARDUINO_ARCH_NRF5) && defined(NRF51) -#include "nimble/nimble/drivers/nrf51/include/ble/xcvr.h" -#elif defined(ARDUINO_ARCH_NRF5) && defined(NRF52_SERIES) -#include "nimble/nimble/drivers/nrf52/include/ble/xcvr.h" -#endif - -#include "../include/controller/ble_ll_whitelist.h" -#include "../include/controller/ble_ll_hci.h" -#include "../include/controller/ble_ll_adv.h" -#include "../include/controller/ble_ll_scan.h" -#include "../include/controller/ble_hw.h" - -#if (MYNEWT_VAL(BLE_LL_WHITELIST_SIZE) < BLE_HW_WHITE_LIST_SIZE) -#define BLE_LL_WHITELIST_SIZE MYNEWT_VAL(BLE_LL_WHITELIST_SIZE) -#else -#define BLE_LL_WHITELIST_SIZE BLE_HW_WHITE_LIST_SIZE -#endif - -struct ble_ll_whitelist_entry -{ - uint8_t wl_valid; - uint8_t wl_addr_type; - uint8_t wl_dev_addr[BLE_DEV_ADDR_LEN]; -}; - -struct ble_ll_whitelist_entry g_ble_ll_whitelist[BLE_LL_WHITELIST_SIZE]; - -static int -ble_ll_whitelist_chg_allowed(void) -{ - int rc; - - /* - * This command is not allowed if: - * -> advertising uses the whitelist and we are currently advertising. - * -> scanning uses the whitelist and is enabled. - * -> initiating uses whitelist and a LE create connection command is in - * progress - */ - rc = 1; - if (!ble_ll_adv_can_chg_whitelist() || !ble_ll_scan_can_chg_whitelist()) { - rc = 0; - } - return rc; -} - -/** - * Clear the whitelist. - * - * @return int 0: success, BLE error code otherwise - */ -int -ble_ll_whitelist_clear(void) -{ - int i; - struct ble_ll_whitelist_entry *wl; - - /* Check proper state */ - if (!ble_ll_whitelist_chg_allowed()) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* Set the number of entries to 0 */ - wl = &g_ble_ll_whitelist[0]; - for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) { - wl->wl_valid = 0; - ++wl; - } - -#if (BLE_USES_HW_WHITELIST == 1) - ble_hw_whitelist_clear(); -#endif - - return BLE_ERR_SUCCESS; -} - -/** - * Read the size of the whitelist. This is the total number of whitelist - * entries allowed by the controller. - * - * @param rspbuf Pointer to response buffer - * - * @return int 0: success. - */ -int -ble_ll_whitelist_read_size(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_le_rd_white_list_rp *rsp = (void *) rspbuf; - - rsp->size = BLE_LL_WHITELIST_SIZE; - - *rsplen = sizeof(*rsp); - - return BLE_ERR_SUCCESS; -} - -/** - * Searches the whitelist to determine if the address is present in the - * whitelist. This is an internal API that only searches the link layer - * whitelist and does not care about the hardware whitelist - * - * @param addr Device or identity address to check. - * @param addr_type Public address (0) or random address (1) - * - * @return int 0: device is not on whitelist; otherwise the return value - * is the 'position' of the device in the whitelist (the index of the element - * plus 1). - */ -static int -ble_ll_whitelist_search(const uint8_t *addr, uint8_t addr_type) -{ - int i; - struct ble_ll_whitelist_entry *wl; - - wl = &g_ble_ll_whitelist[0]; - for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) { - if ((wl->wl_valid) && (wl->wl_addr_type == addr_type) && - (!memcmp(&wl->wl_dev_addr[0], addr, BLE_DEV_ADDR_LEN))) { - return i + 1; - } - ++wl; - } - - return 0; -} - -/** - * Is there a match between the device and a device on the whitelist. - * - * NOTE: This API uses the HW, if present, to determine if there was a match - * between a received address and an address in the whitelist. If the HW does - * not support whitelisting this API is the same as the whitelist search API - * - * @param addr - * @param addr_type Public address (0) or random address (1) - * @param is_ident True if addr is an identity address; false otherwise - * - * @return int - */ -int -ble_ll_whitelist_match(uint8_t *addr, uint8_t addr_type, int is_ident) -{ - int rc; -#if (BLE_USES_HW_WHITELIST == 1) - /* - * XXX: This should be changed. This is HW specific: some HW may be able - * to both resolve a private address and perform a whitelist check. The - * current BLE hw cannot support this. - */ - if (is_ident) { - rc = ble_ll_whitelist_search(addr, addr_type); - } else { - rc = ble_hw_whitelist_match(); - } -#else - rc = ble_ll_whitelist_search(addr, addr_type); -#endif - return rc; -} - -/** - * Add a device to the whitelist - * - * @return int - */ -int -ble_ll_whitelist_add(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_add_whte_list_cp *cmd = (const void *) cmdbuf; - struct ble_ll_whitelist_entry *wl; - int rc; - int i; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Must be in proper state */ - if (!ble_ll_whitelist_chg_allowed()) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* Check if we have any open entries */ - rc = BLE_ERR_SUCCESS; - if (!ble_ll_whitelist_search(cmd->addr, cmd->addr_type)) { - wl = &g_ble_ll_whitelist[0]; - for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) { - if (wl->wl_valid == 0) { - memcpy(&wl->wl_dev_addr[0], cmd->addr, BLE_DEV_ADDR_LEN); - wl->wl_addr_type = cmd->addr_type; - wl->wl_valid = 1; - break; - } - ++wl; - } - - if (i == BLE_LL_WHITELIST_SIZE) { - rc = BLE_ERR_MEM_CAPACITY; - } else { -#if (BLE_USES_HW_WHITELIST == 1) - rc = ble_hw_whitelist_add(cmd->addr, cmd->addr_type); -#endif - } - } - - return rc; -} - -/** - * Remove a device from the whitelist - * - * @param cmdbuf - * - * @return int 0: success, BLE error code otherwise - */ -int -ble_ll_whitelist_rmv(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_rmv_white_list_cp *cmd = (const void *) cmdbuf; - int position; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Must be in proper state */ - if (!ble_ll_whitelist_chg_allowed()) { - return BLE_ERR_CMD_DISALLOWED; - } - - position = ble_ll_whitelist_search(cmd->addr, cmd->addr_type); - if (position) { - g_ble_ll_whitelist[position - 1].wl_valid = 0; - } - -#if (BLE_USES_HW_WHITELIST == 1) - ble_hw_whitelist_rmv(cmd->addr, cmd->addr_type); -#endif - - return BLE_ERR_SUCCESS; -} - -/** - * Enable whitelisting. - * - * Note: This function has no effect if we are not using HW whitelisting - */ -void -ble_ll_whitelist_enable(void) -{ -#if (BLE_USES_HW_WHITELIST == 1) - ble_hw_whitelist_enable(); -#endif -} - -/** - * Disable whitelisting. - * - * Note: This function has no effect if we are not using HW whitelisting - */ -void -ble_ll_whitelist_disable(void) -{ -#if (BLE_USES_HW_WHITELIST == 1) - ble_hw_whitelist_disable(); -#endif -} - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf51/include/ble/xcvr.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf51/include/ble/xcvr.h deleted file mode 100644 index 6c1fb7b24..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf51/include/ble/xcvr.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - #if defined(ARDUINO_ARCH_NRF5) && defined(NRF51) - -#ifndef H_BLE_XCVR_ -#define H_BLE_XCVR_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Transceiver specific defintions */ -/* NOTE: we have to account for the RTC output compare issue */ -#define XCVR_PROC_DELAY_USECS (230) - -#define XCVR_RX_START_DELAY_USECS (140) -#define XCVR_TX_START_DELAY_USECS (140) -#define XCVR_TX_SCHED_DELAY_USECS \ - (XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS) -#define XCVR_RX_SCHED_DELAY_USECS \ - (XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS) - -/* - * Define HW whitelist size. This is the total possible whitelist size; - * not necessarily the size that will be used (may be smaller) - */ -#define BLE_HW_WHITE_LIST_SIZE (8) - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_XCVR_ */ -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf51/src/ble_hw.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf51/src/ble_hw.c deleted file mode 100644 index 3d4966b2d..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf51/src/ble_hw.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#if defined(ARDUINO_ARCH_NRF5) && defined(NRF51) - -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os.h" -#include "../include/ble/xcvr.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "nrf.h" -#include "nimble/nimble/controller/include/controller/ble_hw.h" -#if MYNEWT -#include "mcu/cmsis_nvic.h" -#else -#include "core_cm0.h" -#include "nimble/porting/npl/freertos/include/nimble/nimble_npl_os.h" -#endif -#include "nimble/porting/nimble/include/os/os_trace_api.h" - -/* Total number of resolving list elements */ -#define BLE_HW_RESOLV_LIST_SIZE (16) - -/* We use this to keep track of which entries are set to valid addresses */ -static uint8_t g_ble_hw_whitelist_mask; - -/* Random number generator isr callback */ -ble_rng_isr_cb_t g_ble_rng_isr_cb; - -/* If LL privacy is enabled, allocate memory for AAR */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - -/* The NRF51 supports up to 16 IRK entries */ -#if (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE) < 16) -#define NRF_IRK_LIST_ENTRIES (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE)) -#else -#define NRF_IRK_LIST_ENTRIES (16) -#endif - -/* NOTE: each entry is 16 bytes long. */ -uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4]; - -/* Current number of IRK entries */ -uint8_t g_nrf_num_irks; - -#endif - -/* Returns public device address or -1 if not present */ -int -ble_hw_get_public_addr(ble_addr_t *addr) -{ - uint32_t addr_high; - uint32_t addr_low; - - /* Does FICR have a public address */ - if ((NRF_FICR->DEVICEADDRTYPE & 1) != 0) { - return -1; - } - - /* Copy into device address. We can do this because we know platform */ - addr_low = NRF_FICR->DEVICEADDR[0]; - addr_high = NRF_FICR->DEVICEADDR[1]; - memcpy(addr->val, &addr_low, 4); - memcpy(&addr->val[4], &addr_high, 2); - addr->type = BLE_ADDR_PUBLIC; - - return 0; -} - -/* Returns random static address or -1 if not present */ -int -ble_hw_get_static_addr(ble_addr_t *addr) -{ - int rc; - - if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) { - memcpy(addr->val, (void *)&NRF_FICR->DEVICEADDR[0], 4); - memcpy(&addr->val[4], (void *)&NRF_FICR->DEVICEADDR[1], 2); - addr->val[5] |= 0xc0; - addr->type = BLE_ADDR_RANDOM; - rc = 0; - } else { - rc = -1; - } - - return rc; -} - -/** - * Clear the whitelist - * - * @return int - */ -void -ble_hw_whitelist_clear(void) -{ - NRF_RADIO->DACNF = 0; - g_ble_hw_whitelist_mask = 0; -} - -/** - * Add a device to the hw whitelist - * - * @param addr - * @param addr_type - * - * @return int 0: success, BLE error code otherwise - */ -int -ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type) -{ - int i; - uint32_t mask; - - /* Find first ununsed device address match element */ - mask = 0x01; - for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) { - if ((mask & g_ble_hw_whitelist_mask) == 0) { - NRF_RADIO->DAB[i] = get_le32(addr); - NRF_RADIO->DAP[i] = get_le16(addr + 4); - if (addr_type == BLE_ADDR_RANDOM) { - NRF_RADIO->DACNF |= (mask << 8); - } - g_ble_hw_whitelist_mask |= mask; - return BLE_ERR_SUCCESS; - } - mask <<= 1; - } - - return BLE_ERR_MEM_CAPACITY; -} - -/** - * Remove a device from the hw whitelist - * - * @param addr - * @param addr_type - * - */ -void -ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type) -{ - int i; - uint8_t cfg_addr; - uint16_t dap; - uint16_t txadd; - uint32_t dab; - uint32_t mask; - - /* Find first ununsed device address match element */ - dab = get_le32(addr); - dap = get_le16(addr + 4); - txadd = NRF_RADIO->DACNF >> 8; - mask = 0x01; - for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) { - if (mask & g_ble_hw_whitelist_mask) { - if ((dab == NRF_RADIO->DAB[i]) && (dap == NRF_RADIO->DAP[i])) { - cfg_addr = txadd & mask; - if (addr_type == BLE_ADDR_RANDOM) { - if (cfg_addr != 0) { - break; - } - } else { - if (cfg_addr == 0) { - break; - } - } - } - } - mask <<= 1; - } - - if (i < BLE_HW_WHITE_LIST_SIZE) { - g_ble_hw_whitelist_mask &= ~mask; - NRF_RADIO->DACNF &= ~mask; - } -} - -/** - * Returns the size of the whitelist in HW - * - * @return int Number of devices allowed in whitelist - */ -uint8_t -ble_hw_whitelist_size(void) -{ - return BLE_HW_WHITE_LIST_SIZE; -} - -/** - * Enable the whitelisted devices - */ -void -ble_hw_whitelist_enable(void) -{ - /* Enable the configured device addresses */ - NRF_RADIO->DACNF |= g_ble_hw_whitelist_mask; -} - -/** - * Disables the whitelisted devices - */ -void -ble_hw_whitelist_disable(void) -{ - /* Disable all whitelist devices */ - NRF_RADIO->DACNF &= 0x0000ff00; -} - -/** - * Boolean function which returns true ('1') if there is a match on the - * whitelist. - * - * @return int - */ -int -ble_hw_whitelist_match(void) -{ - return (int)NRF_RADIO->EVENTS_DEVMATCH; -} - -/* Encrypt data */ -int -ble_hw_encrypt_block(struct ble_encryption_block *ecb) -{ - int rc; - uint32_t end; - uint32_t err; - - /* Stop ECB */ - NRF_ECB->TASKS_STOPECB = 1; - /* XXX: does task stop clear these counters? Anyway to do this quicker? */ - NRF_ECB->EVENTS_ENDECB = 0; - NRF_ECB->EVENTS_ERRORECB = 0; - NRF_ECB->ECBDATAPTR = (uint32_t)ecb; - - /* Start ECB */ - NRF_ECB->TASKS_STARTECB = 1; - - /* Wait till error or done */ - rc = 0; - while (1) { - end = NRF_ECB->EVENTS_ENDECB; - err = NRF_ECB->EVENTS_ERRORECB; - if (end || err) { - if (err) { - rc = -1; - } - break; - } - } - - return rc; -} - -/** - * Random number generator ISR. - */ -static void -ble_rng_isr(void) -{ - uint8_t rnum; - - os_trace_isr_enter(); - - /* No callback? Clear and disable interrupts */ - if (g_ble_rng_isr_cb == NULL) { - NRF_RNG->INTENCLR = 1; - NRF_RNG->EVENTS_VALRDY = 0; - (void)NRF_RNG->SHORTS; - os_trace_isr_exit(); - return; - } - - /* If there is a value ready grab it */ - if (NRF_RNG->EVENTS_VALRDY) { - NRF_RNG->EVENTS_VALRDY = 0; - rnum = (uint8_t)NRF_RNG->VALUE; - (*g_ble_rng_isr_cb)(rnum); - } - - os_trace_isr_exit(); -} - -/** - * Initialize the random number generator - * - * @param cb - * @param bias - * - * @return int - */ -int -ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias) -{ - /* Set bias */ - if (bias) { - NRF_RNG->CONFIG = 1; - } else { - NRF_RNG->CONFIG = 0; - } - - /* If we were passed a function pointer we need to enable the interrupt */ - if (cb != NULL) { -#ifndef RIOT_VERSION - NVIC_SetPriority(RNG_IRQn, (1 << __NVIC_PRIO_BITS) - 1); -#endif -#if MYNEWT - NVIC_SetVector(RNG_IRQn, (uint32_t)ble_rng_isr); -#else - ble_npl_hw_set_isr(RNG_IRQn, ble_rng_isr); -#endif - NVIC_EnableIRQ(RNG_IRQn); - g_ble_rng_isr_cb = cb; - } - - return 0; -} - -/** - * Start the random number generator - * - * @return int - */ -int -ble_hw_rng_start(void) -{ - os_sr_t sr; - - /* No need for interrupt if there is no callback */ - OS_ENTER_CRITICAL(sr); - NRF_RNG->EVENTS_VALRDY = 0; - if (g_ble_rng_isr_cb) { - NRF_RNG->INTENSET = 1; - } - NRF_RNG->TASKS_START = 1; - OS_EXIT_CRITICAL(sr); - - return 0; -} - -/** - * Stop the random generator - * - * @return int - */ -int -ble_hw_rng_stop(void) -{ - os_sr_t sr; - - /* No need for interrupt if there is no callback */ - OS_ENTER_CRITICAL(sr); - NRF_RNG->INTENCLR = 1; - NRF_RNG->TASKS_STOP = 1; - NRF_RNG->EVENTS_VALRDY = 0; - OS_EXIT_CRITICAL(sr); - - return 0; -} - -/** - * Read the random number generator. - * - * @return uint8_t - */ -uint8_t -ble_hw_rng_read(void) -{ - uint8_t rnum; - - /* Wait for a sample */ - while (NRF_RNG->EVENTS_VALRDY == 0) { - } - - NRF_RNG->EVENTS_VALRDY = 0; - rnum = (uint8_t)NRF_RNG->VALUE; - - return rnum; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -/** - * Clear the resolving list - * - * @return int - */ -void -ble_hw_resolv_list_clear(void) -{ - g_nrf_num_irks = 0; -} - -/** - * Add a device to the hw resolving list - * - * @param irk Pointer to IRK to add - * - * @return int 0: success, BLE error code otherwise - */ -int -ble_hw_resolv_list_add(uint8_t *irk) -{ - uint32_t *nrf_entry; - - /* Find first ununsed device address match element */ - if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) { - return BLE_ERR_MEM_CAPACITY; - } - - /* Copy into irk list */ - nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks]; - memcpy(nrf_entry, irk, 16); - - /* Add to total */ - ++g_nrf_num_irks; - return BLE_ERR_SUCCESS; -} - -/** - * Remove a device from the hw resolving list - * - * @param index Index of IRK to remove - */ -void -ble_hw_resolv_list_rmv(int index) -{ - uint32_t *irk_entry; - - if (index < g_nrf_num_irks) { - --g_nrf_num_irks; - irk_entry = &g_nrf_irk_list[index]; - if (g_nrf_num_irks > index) { - memmove(irk_entry, irk_entry + 4, 16 * (g_nrf_num_irks - index)); - } - } -} - -/** - * Returns the size of the resolving list. NOTE: this returns the maximum - * allowable entries in the HW. Configuration options may limit this. - * - * @return int Number of devices allowed in resolving list - */ -uint8_t -ble_hw_resolv_list_size(void) -{ - return BLE_HW_RESOLV_LIST_SIZE; -} - -/** - * Called to determine if the address received was resolved. - * - * @return int Negative values indicate unresolved address; positive values - * indicate index in resolving list of resolved address. - */ -int -ble_hw_resolv_list_match(void) -{ - uint32_t index; - - if (NRF_AAR->EVENTS_END) { - if (NRF_AAR->EVENTS_RESOLVED) { - index = NRF_AAR->STATUS; - return (int)index; - } - } - - return -1; -} -#endif -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf51/src/ble_phy.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf51/src/ble_phy.c deleted file mode 100644 index 908664a73..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf51/src/ble_phy.c +++ /dev/null @@ -1,1527 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - #if defined(ARDUINO_ARCH_NRF5) && defined(NRF51) - -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os.h" -#include "../include/ble/xcvr.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "nimble/nimble/controller/include/controller/ble_phy.h" -#include "nimble/nimble/controller/include/controller/ble_phy_trace.h" -#include "nimble/nimble/controller/include/controller/ble_ll.h" -#include "nrf.h" - -#if MYNEWT -#include "mcu/nrf51_clock.h" -#include "mcu/cmsis_nvic.h" -#else -#include "core_cm0.h" -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) -#error LE 2M PHY cannot be enabled on nRF51 -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) -#error LE Coded PHY cannot be enabled on nRF51 -#endif - -/* XXX: 4) Make sure RF is higher priority interrupt than schedule */ - -/* - * XXX: Maximum possible transmit time is 1 msec for a 60ppm crystal - * and 16ms for a 30ppm crystal! We need to limit PDU size based on - * crystal accuracy. Look at this in the spec. - */ - -/* XXX: private header file? */ -extern uint8_t g_nrf_num_irks; -extern uint32_t g_nrf_irk_list[]; - -/* To disable all radio interrupts */ -#define NRF_RADIO_IRQ_MASK_ALL (0x34FF) - -/* - * We configure the nrf with a 1 byte S0 field, 8 bit length field, and - * zero bit S1 field. The preamble is 8 bits long. - */ -#define NRF_LFLEN_BITS (8) -#define NRF_S0_LEN (1) - -/* Maximum length of frames */ -#define NRF_MAXLEN (255) -#define NRF_BALEN (3) /* For base address of 3 bytes */ - -/* Maximum tx power */ -#define NRF_TX_PWR_MAX_DBM (4) -#define NRF_TX_PWR_MIN_DBM (-40) - -/* Max. encrypted payload length */ -#define NRF_MAX_ENCRYPTED_PYLD_LEN (27) -#define NRF_ENC_HDR_SIZE (3) -#define NRF_ENC_BUF_SIZE \ - (NRF_MAX_ENCRYPTED_PYLD_LEN + NRF_ENC_HDR_SIZE + BLE_LL_DATA_MIC_LEN) - -/* BLE PHY data structure */ -struct ble_phy_obj -{ - uint8_t phy_stats_initialized; - int8_t phy_txpwr_dbm; - uint8_t phy_chan; - uint8_t phy_state; - uint8_t phy_transition; - uint8_t phy_rx_started; - uint8_t phy_encrypted; - uint8_t phy_privacy; - uint8_t phy_tx_pyld_len; - uint8_t *rxdptr; - int8_t rx_pwr_compensation; - uint32_t phy_aar_scratch; - uint32_t phy_access_address; - struct ble_mbuf_hdr rxhdr; - void *txend_arg; - ble_phy_tx_end_func txend_cb; - uint32_t phy_start_cputime; -}; -struct ble_phy_obj g_ble_phy_data; - -/* XXX: if 27 byte packets desired we can make this smaller */ -/* Global transmit/receive buffer */ -static uint32_t g_ble_phy_tx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; -static uint32_t g_ble_phy_rx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/* Make sure word-aligned for faster copies */ -static uint32_t g_ble_phy_enc_buf[(NRF_ENC_BUF_SIZE + 3) / 4]; -#endif - -/* RF center frequency for each channel index (offset from 2400 MHz) */ -static const uint8_t g_ble_phy_chan_freq[BLE_PHY_NUM_CHANS] = { - 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, /* 0-9 */ - 24, 28, 30, 32, 34, 36, 38, 40, 42, 44, /* 10-19 */ - 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, /* 20-29 */ - 66, 68, 70, 72, 74, 76, 78, 2, 26, 80, /* 30-39 */ -}; - -/* Statistics */ -STATS_SECT_START(ble_phy_stats) - STATS_SECT_ENTRY(phy_isrs) - STATS_SECT_ENTRY(tx_good) - STATS_SECT_ENTRY(tx_fail) - STATS_SECT_ENTRY(tx_late) - STATS_SECT_ENTRY(tx_bytes) - STATS_SECT_ENTRY(rx_starts) - STATS_SECT_ENTRY(rx_aborts) - STATS_SECT_ENTRY(rx_valid) - STATS_SECT_ENTRY(rx_crc_err) - STATS_SECT_ENTRY(rx_late) - STATS_SECT_ENTRY(radio_state_errs) - STATS_SECT_ENTRY(rx_hw_err) - STATS_SECT_ENTRY(tx_hw_err) -STATS_SECT_END -STATS_SECT_DECL(ble_phy_stats) ble_phy_stats; - -STATS_NAME_START(ble_phy_stats) - STATS_NAME(ble_phy_stats, phy_isrs) - STATS_NAME(ble_phy_stats, tx_good) - STATS_NAME(ble_phy_stats, tx_fail) - STATS_NAME(ble_phy_stats, tx_late) - STATS_NAME(ble_phy_stats, tx_bytes) - STATS_NAME(ble_phy_stats, rx_starts) - STATS_NAME(ble_phy_stats, rx_aborts) - STATS_NAME(ble_phy_stats, rx_valid) - STATS_NAME(ble_phy_stats, rx_crc_err) - STATS_NAME(ble_phy_stats, rx_late) - STATS_NAME(ble_phy_stats, radio_state_errs) - STATS_NAME(ble_phy_stats, rx_hw_err) - STATS_NAME(ble_phy_stats, tx_hw_err) -STATS_NAME_END(ble_phy_stats) - -/* - * NOTE: - * Tested the following to see what would happen: - * -> NVIC has radio irq enabled (interrupt # 1, mask 0x2). - * -> Set up nrf to receive. Clear ADDRESS event register. - * -> Enable ADDRESS interrupt on nrf5 by writing to INTENSET. - * -> Enable RX. - * -> Disable interrupts globally using OS_ENTER_CRITICAL(). - * -> Wait until a packet is received and the ADDRESS event occurs. - * -> Call ble_phy_disable(). - * - * At this point I wanted to see the state of the cortex NVIC. The IRQ - * pending bit was TRUE for the radio interrupt (as expected) as we never - * serviced the radio interrupt (interrupts were disabled). - * - * What was unexpected was this: without clearing the pending IRQ in the NVIC, - * when radio interrupts were re-enabled (address event bit in INTENSET set to - * 1) and the radio ADDRESS event register read 1 (it was never cleared after - * the first address event), the radio did not enter the ISR! I would have - * expected that if the following were true, an interrupt would occur: - * -> NVIC ISER bit set to TRUE - * -> NVIC ISPR bit reads TRUE, meaning interrupt is pending. - * -> Radio peripheral interrupts are enabled for some event (or events). - * -> Corresponding event register(s) in radio peripheral read 1. - * - * Not sure what the end result of all this is. We will clear the pending - * bit in the NVIC just to be sure when we disable the PHY. - */ - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/* Per nordic, the number of bytes needed for scratch is 16 + MAX_PKT_SIZE. */ -#define NRF_ENC_SCRATCH_WORDS (((NRF_MAX_ENCRYPTED_PYLD_LEN + 16) + 3) / 4) - -uint32_t g_nrf_encrypt_scratchpad[NRF_ENC_SCRATCH_WORDS]; - -struct nrf_ccm_data -{ - uint8_t key[16]; - uint64_t pkt_counter; - uint8_t dir_bit; - uint8_t iv[8]; -} __attribute__((packed)); - -struct nrf_ccm_data g_nrf_ccm_data; -#endif - -/** - * Copies the data from the phy receive buffer into a mbuf chain. - * - * @param dptr Pointer to receive buffer - * @param rxpdu Pointer to already allocated mbuf chain - * - * NOTE: the packet header already has the total mbuf length in it. The - * lengths of the individual mbufs are not set prior to calling. - * - */ -void -ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) -{ - uint32_t rem_len; - uint32_t copy_len; - uint32_t block_len; - uint32_t block_rem_len; - void *dst; - void *src; - struct os_mbuf * om; - - /* Better be aligned */ - assert(((uint32_t)dptr & 3) == 0); - - block_len = rxpdu->om_omp->omp_databuf_len; - rem_len = OS_MBUF_PKTHDR(rxpdu)->omp_len; - src = dptr; - - /* - * Setup for copying from first mbuf which is shorter due to packet header - * and extra leading space - */ - copy_len = block_len - rxpdu->om_pkthdr_len - 4; - om = rxpdu; - dst = om->om_data; - - while (true) { - /* - * Always copy blocks of length aligned to word size, only last mbuf - * will have remaining non-word size bytes appended. - */ - block_rem_len = copy_len; - copy_len = min(copy_len, rem_len); - copy_len &= ~3; - - dst = om->om_data; - om->om_len = copy_len; - rem_len -= copy_len; - block_rem_len -= copy_len; - - __asm__ volatile (".syntax unified \n" - " mov r4, %[len] \n" - " b 2f \n" - "1: ldr r3, [%[src], %[len]] \n" - " str r3, [%[dst], %[len]] \n" - "2: subs %[len], #4 \n" - " bpl 1b \n" - " adds %[src], %[src], r4 \n" - " adds %[dst], %[dst], r4 \n" - : [dst] "+l" (dst), [src] "+l" (src), - [len] "+l" (copy_len) - : - : "r3", "r4", "memory" - ); - - if ((rem_len < 4) && (block_rem_len >= rem_len)) { - break; - } - - /* Move to next mbuf */ - om = SLIST_NEXT(om, om_next); - copy_len = block_len; - } - - /* Copy remaining bytes, if any, to last mbuf */ - om->om_len += rem_len; - __asm__ volatile (".syntax unified \n" - " b 2f \n" - "1: ldrb r3, [%[src], %[len]] \n" - " strb r3, [%[dst], %[len]] \n" - "2: subs %[len], #1 \n" - " bpl 1b \n" - : [len] "+l" (rem_len) - : [dst] "l" (dst), [src] "l" (src) - : "r3", "memory" - ); - - /* Copy header */ - memcpy(BLE_MBUF_HDR_PTR(rxpdu), &g_ble_phy_data.rxhdr, - sizeof(struct ble_mbuf_hdr)); -} - -/** - * Called when we want to wait if the radio is in either the rx or tx - * disable states. We want to wait until that state is over before doing - * anything to the radio - */ -static void -nrf_wait_disabled(void) -{ - uint32_t state; - - /* - * RX and TX states have the same values except for 3rd bit (0=RX, 1=TX) so - * we use RX symbols only. - */ - state = NRF_RADIO->STATE & 0x07; - - if (state != RADIO_STATE_STATE_Disabled) { - /* If PHY is in idle state for whatever reason, disable it now */ - if (state == RADIO_STATE_STATE_RxIdle) { - NRF_RADIO->TASKS_DISABLE = 1; - STATS_INC(ble_phy_stats, radio_state_errs); - } - - if (state == RADIO_STATE_STATE_RxDisable) { - /* This will end within a short time (6 usecs). Just poll */ - while (NRF_RADIO->STATE == state) { - /* If this fails, something is really wrong. Should last - * no more than 6 usecs */ - } - } - } -} - -/** - * - * - */ -int -ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs) -{ - uint32_t next_cc; - uint32_t cur_cc; - uint32_t cntr; - uint32_t delta; - - /* - * XXX: The TXEN time is 140 usecs but there may be additional delays - * Need to look at this. - */ - - /* - * With the 32.768 kHz crystal, we may need to adjust the RTC compare - * value by 1 tick due to the time it takes for TXEN. The code uses a 5 RTC - * tick offset, which is 152.5 usecs. The TXEN time is 140 usecs. This - * means that with a remainder of 0, TIMER0 should be set to 12 or 13 (as - * TIMER0 counts at 1MHz). A remainder of 19 or more we will need to add - * 1 tick. We dont need to add 1 tick per se, but it does give us slightly - * more time and thus less of a chance to miss a tick. Another note: we - * cant set TIMER0 CC to 0 as the compare wont occur; it must be 1 or more. - * This is why we subtract 18 (as opposed to 19) as rem_uses will be >= 1. - */ - if (rem_usecs <= 18) { - cputime -= 5; - rem_usecs += 12; - } else { - cputime -= 4; - rem_usecs -= 18; - } - - /* - * Can we set the RTC compare to start TIMER0? We can do it if: - * a) Current compare value is not N+1 or N+2 ticks from current - * counter. - * b) The value we want to set is not at least N+2 from current - * counter. - * - * NOTE: since the counter can tick 1 while we do these calculations we - * need to account for it. - */ - next_cc = cputime & 0xffffff; - cur_cc = NRF_RTC0->CC[0]; - cntr = NRF_RTC0->COUNTER; - - delta = (cur_cc - cntr) & 0xffffff; - if ((delta <= 3) && (delta != 0)) { - return -1; - } - delta = (next_cc - cntr) & 0xffffff; - if ((delta & 0x800000) || (delta < 3)) { - return -1; - } - - /* Clear and set TIMER0 to fire off at proper time */ - NRF_TIMER0->TASKS_CLEAR = 1; - NRF_TIMER0->CC[0] = rem_usecs; - NRF_TIMER0->EVENTS_COMPARE[0] = 0; - - /* Set RTC compare to start TIMER0 */ - NRF_RTC0->EVENTS_COMPARE[0] = 0; - NRF_RTC0->CC[0] = next_cc; - NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; - - /* Enable PPI */ - NRF_PPI->CHENSET = PPI_CHEN_CH31_Msk; - - /* Store the cputime at which we set the RTC */ - g_ble_phy_data.phy_start_cputime = cputime; - - return 0; -} - -/** - * Function is used to set PPI so that we can time out waiting for a reception - * to occur. This happens for two reasons: we have sent a packet and we are - * waiting for a respons (txrx should be set to ENABLE_TXRX) or we are - * starting a connection event and we are a slave and we are waiting for the - * master to send us a packet (txrx should be set to ENABLE_RX). - * - * NOTE: when waiting for a txrx turn-around, wfr_usecs is not used as there - * is no additional time to wait; we know when we should receive the address of - * the received frame. - * - * @param txrx Flag denoting if this wfr is a txrx turn-around or not. - * @param tx_phy_mode phy mode for last TX (not used on nRF51) - * @param wfr_usecs Amount of usecs to wait. - */ -void -ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) -{ - uint32_t end_time; - - if (txrx == BLE_PHY_WFR_ENABLE_TXRX) { - /* - * Timeout occurs an IFS time plus time it takes to receive address - * from the transmit end. We add additional time to make sure the - * address event comes before the compare. Note that transmit end - * is captured in CC[2]. I just made up the 16 usecs I add here. - */ - end_time = NRF_TIMER0->CC[2] + BLE_LL_IFS + - ble_phy_mode_pdu_start_off(BLE_PHY_MODE_1M) + 16; - } else { - /* CC[0] is set to when RXEN occurs. */ - end_time = NRF_TIMER0->CC[0] + XCVR_RX_START_DELAY_USECS + wfr_usecs + - ble_phy_mode_pdu_start_off(BLE_PHY_MODE_1M) + BLE_LL_JITTER_USECS; - } - - /* wfr_secs is the time from rxen until timeout */ - NRF_TIMER0->CC[3] = end_time; - NRF_TIMER0->EVENTS_COMPARE[3] = 0; - - /* Enable wait for response PPI */ - NRF_PPI->CHENSET = (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk); - - /* Enable the disabled interrupt so we time out on events compare */ - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; -} - -/** - * Setup transceiver for receive. - */ -static void -ble_phy_rx_xcvr_setup(void) -{ - uint8_t *dptr; - - dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (g_ble_phy_data.phy_encrypted) { - dptr += 3; - NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM->OUTPTR = (uint32_t)dptr; - NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; - NRF_CCM->MODE = CCM_MODE_MODE_Decryption; - NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data; - NRF_CCM->SHORTS = 0; - NRF_CCM->EVENTS_ERROR = 0; - NRF_CCM->EVENTS_ENDCRYPT = 0; - NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk | PPI_CHEN_CH25_Msk; - } else { - NRF_RADIO->PACKETPTR = (uint32_t)dptr; - } -#else - NRF_RADIO->PACKETPTR = (uint32_t)dptr; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (g_ble_phy_data.phy_privacy) { - dptr += 3; - NRF_RADIO->PACKETPTR = (uint32_t)dptr; - NRF_RADIO->PCNF0 = (6 << RADIO_PCNF0_LFLEN_Pos) | - (2 << RADIO_PCNF0_S1LEN_Pos) | - (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos); - NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled; - NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; - NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch; - NRF_AAR->EVENTS_END = 0; - NRF_AAR->EVENTS_RESOLVED = 0; - NRF_AAR->EVENTS_NOTRESOLVED = 0; - } else { - if (g_ble_phy_data.phy_encrypted == 0) { - NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | - (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos); - /* XXX: do I only need to do this once? Figure out what I can do - once. */ - NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled; - } - } -#endif - - /* Turn off trigger TXEN on output compare match and AAR on bcmatch */ - NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk | PPI_CHEN_CH23_Msk; - - /* Reset the rx started flag. Used for the wait for response */ - g_ble_phy_data.phy_rx_started = 0; - g_ble_phy_data.phy_state = BLE_PHY_STATE_RX; - g_ble_phy_data.rxdptr = dptr; - - /* I want to know when 1st byte received (after address) */ - NRF_RADIO->BCC = 8; /* in bits */ - NRF_RADIO->EVENTS_ADDRESS = 0; - NRF_RADIO->EVENTS_DEVMATCH = 0; - NRF_RADIO->EVENTS_BCMATCH = 0; - NRF_RADIO->EVENTS_RSSIEND = 0; - NRF_RADIO->SHORTS = RADIO_SHORTS_END_DISABLE_Msk | - RADIO_SHORTS_READY_START_Msk | - RADIO_SHORTS_DISABLED_TXEN_Msk | - RADIO_SHORTS_ADDRESS_BCSTART_Msk | - RADIO_SHORTS_ADDRESS_RSSISTART_Msk | - RADIO_SHORTS_DISABLED_RSSISTOP_Msk; - - NRF_RADIO->INTENSET = RADIO_INTENSET_ADDRESS_Msk; -} - -/** - * Called from interrupt context when the transmit ends - * - */ -static void -ble_phy_tx_end_isr(void) -{ - uint8_t was_encrypted; - uint8_t transition; - uint8_t txlen; - uint32_t wfr_time; - - /* If this transmission was encrypted we need to remember it */ - was_encrypted = g_ble_phy_data.phy_encrypted; - (void)was_encrypted; - - /* Better be in TX state! */ - assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX); - - /* Clear events and clear interrupt on disabled event */ - NRF_RADIO->EVENTS_DISABLED = 0; - NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk; - NRF_RADIO->EVENTS_END = 0; - wfr_time = NRF_RADIO->SHORTS; - (void)wfr_time; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - /* - * XXX: not sure what to do. We had a HW error during transmission. - * For now I just count a stat but continue on like all is good. - */ - if (was_encrypted) { - if (NRF_CCM->EVENTS_ERROR) { - STATS_INC(ble_phy_stats, tx_hw_err); - NRF_CCM->EVENTS_ERROR = 0; - } - } -#endif - - /* Call transmit end callback */ - if (g_ble_phy_data.txend_cb) { - g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg); - } - - transition = g_ble_phy_data.phy_transition; - if (transition == BLE_PHY_TRANSITION_TX_RX) { - /* Packet pointer needs to be reset. */ - ble_phy_rx_xcvr_setup(); - - /* - * Enable the wait for response timer. Note that cc #1 on - * timer 0 contains the transmit start time - */ - txlen = g_ble_phy_data.phy_tx_pyld_len; - if (txlen && was_encrypted) { - txlen += BLE_LL_DATA_MIC_LEN; - } - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_TXRX, 0, 0); - } else { - /* - * XXX: not sure we need to stop the timer here all the time. Or that - * it should be stopped here. - */ - NRF_TIMER0->TASKS_STOP = 1; - NRF_TIMER0->TASKS_SHUTDOWN = 1; - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | - PPI_CHEN_CH20_Msk | PPI_CHEN_CH31_Msk; - assert(transition == BLE_PHY_TRANSITION_NONE); - } -} - -static void -ble_phy_rx_end_isr(void) -{ - int rc; - uint8_t *dptr; - uint8_t crcok; - struct ble_mbuf_hdr *ble_hdr; - - /* Clear events and clear interrupt */ - NRF_RADIO->EVENTS_END = 0; - NRF_RADIO->INTENCLR = RADIO_INTENCLR_END_Msk; - - /* Disable automatic RXEN */ - NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; - - /* Set RSSI and CRC status flag in header */ - ble_hdr = &g_ble_phy_data.rxhdr; - assert(NRF_RADIO->EVENTS_RSSIEND != 0); - ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO->RSSISAMPLE) + - g_ble_phy_data.rx_pwr_compensation; - - dptr = g_ble_phy_data.rxdptr; - - /* Count PHY crc errors and valid packets */ - crcok = (uint8_t)NRF_RADIO->CRCSTATUS; - if (!crcok) { - STATS_INC(ble_phy_stats, rx_crc_err); - } else { - STATS_INC(ble_phy_stats, rx_valid); - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (g_ble_phy_data.phy_encrypted) { - /* Only set MIC failure flag if frame is not zero length */ - if ((dptr[1] != 0) && (NRF_CCM->MICSTATUS == 0)) { - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE; - } - - /* - * XXX: not sure how to deal with this. This should not - * be a MIC failure but we should not hand it up. I guess - * this is just some form of rx error and that is how we - * handle it? For now, just set CRC error flags - */ - if (NRF_CCM->EVENTS_ERROR) { - STATS_INC(ble_phy_stats, rx_hw_err); - ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK; - } - - /* - * XXX: This is a total hack work-around for now but I dont - * know what else to do. If ENDCRYPT is not set and we are - * encrypted we need to not trust this frame and drop it. - */ - if (NRF_CCM->EVENTS_ENDCRYPT == 0) { - STATS_INC(ble_phy_stats, rx_hw_err); - ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK; - } - } -#endif - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (g_ble_phy_data.phy_encrypted || g_ble_phy_data.phy_privacy) { - /* - * XXX: This is a horrible ugly hack to deal with the RAM S1 byte. - * This should get fixed as we should not be handing up the header - * and length as part of the pdu. - */ - dptr[2] = dptr[1]; - dptr[1] = dptr[0]; - ++dptr; - } -#endif - rc = ble_ll_rx_end(dptr, ble_hdr); - if (rc < 0) { - ble_phy_disable(); - } -} - -static void -ble_phy_rx_start_isr(void) -{ - int rc; - uint32_t state; - uint32_t usecs; - uint32_t ticks; - struct ble_mbuf_hdr *ble_hdr; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - uint8_t *dptr; - - dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; -#endif - - /* Clear events and clear interrupt */ - NRF_RADIO->EVENTS_ADDRESS = 0; - - /* Clear wfr timer channels and DISABLED interrupt */ - NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk | RADIO_INTENCLR_ADDRESS_Msk; - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk; - - /* Initialize flags, channel and state in ble header at rx start */ - ble_hdr = &g_ble_phy_data.rxhdr; - ble_hdr->rxinfo.flags = ble_ll_state_get(); - ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan; - ble_hdr->rxinfo.handle = 0; - ble_hdr->rxinfo.phy = BLE_PHY_1M; - ble_hdr->rxinfo.phy_mode = BLE_PHY_MODE_1M; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_hdr->rxinfo.user_data = NULL; -#endif - - /* - * Calculate receive start time. - * - * XXX: possibly use other routine with remainder! - */ - usecs = NRF_TIMER0->CC[1] - ble_phy_mode_pdu_start_off(BLE_PHY_MODE_1M); - ticks = os_cputime_usecs_to_ticks(usecs); - ble_hdr->rem_usecs = usecs - os_cputime_ticks_to_usecs(ticks); - if (ble_hdr->rem_usecs == 31) { - ble_hdr->rem_usecs = 0; - ++ticks; - } - ble_hdr->beg_cputime = g_ble_phy_data.phy_start_cputime + ticks; - - /* Wait to get 1st byte of frame */ - while (1) { - state = NRF_RADIO->STATE; - if (NRF_RADIO->EVENTS_BCMATCH != 0) { - break; - } - - /* - * If state is disabled, we should have the BCMATCH. If not, - * something is wrong! - */ - if (state == RADIO_STATE_STATE_Disabled) { - NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - NRF_RADIO->SHORTS = 0; - return; - } - } - - /* Call Link Layer receive start function */ - rc = ble_ll_rx_start(g_ble_phy_data.rxdptr, g_ble_phy_data.phy_chan, - &g_ble_phy_data.rxhdr); - if (rc >= 0) { - /* Set rx started flag and enable rx end ISR */ - g_ble_phy_data.phy_rx_started = 1; - NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* Must start aar if we need to */ - if (g_ble_phy_data.phy_privacy) { - NRF_RADIO->EVENTS_BCMATCH = 0; - NRF_PPI->CHENSET = PPI_CHEN_CH23_Msk; - /* - * Setup AAR to resolve AdvA and trigger it after complete address - * is received, i.e. after PDU header and AdvA is received. - * - * AdvA starts at 4th octet in receive buffer, after S0, len and S1 - * fields. - * - * In case of extended advertising AdvA is located after extended - * header (+2 octets). - */ - if (BLE_MBUF_HDR_EXT_ADV(&g_ble_phy_data.rxhdr)) { - NRF_AAR->ADDRPTR = (uint32_t)(dptr + 5); - NRF_RADIO->BCC = (BLE_DEV_ADDR_LEN + BLE_LL_PDU_HDR_LEN + 2) * 8; - - } else { - NRF_AAR->ADDRPTR = (uint32_t)(dptr + 3); - NRF_RADIO->BCC = (BLE_DEV_ADDR_LEN + BLE_LL_PDU_HDR_LEN) * 8; - } - } -#endif - } else { - /* Disable PHY */ - ble_phy_disable(); - STATS_INC(ble_phy_stats, rx_aborts); - } - - /* Count rx starts */ - STATS_INC(ble_phy_stats, rx_starts); -} - -static void -ble_phy_isr(void) -{ - uint32_t irq_en; - - os_trace_isr_enter(); - - /* Read irq register to determine which interrupts are enabled */ - irq_en = NRF_RADIO->INTENCLR; - - /* - * NOTE: order of checking is important! Possible, if things get delayed, - * we have both an ADDRESS and DISABLED interrupt in rx state. If we get - * an address, we disable the DISABLED interrupt. - */ - - /* We get this if we have started to receive a frame */ - if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO->EVENTS_ADDRESS) { - irq_en &= ~RADIO_INTENCLR_DISABLED_Msk; - ble_phy_rx_start_isr(); - } - - /* Check for disabled event. This only happens for transmits now */ - if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) { - if (g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) { - NRF_RADIO->EVENTS_DISABLED = 0; - ble_ll_wfr_timer_exp(NULL); - } else { - ble_phy_tx_end_isr(); - } - } - - /* Receive packet end (we dont enable this for transmit) */ - if ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO->EVENTS_END) { - ble_phy_rx_end_isr(); - } - - /* Ensures IRQ is cleared */ - irq_en = NRF_RADIO->SHORTS; - - /* Count # of interrupts */ - STATS_INC(ble_phy_stats, phy_isrs); - - os_trace_isr_exit(); -} - -/** - * ble phy init - * - * Initialize the PHY. - * - * @return int 0: success; PHY error code otherwise - */ -int -ble_phy_init(void) -{ - int rc; - - /* Set phy channel to an invalid channel so first set channel works */ - g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS; - - g_ble_phy_data.rx_pwr_compensation = 0; - - /* Toggle peripheral power to reset (just in case) */ - NRF_RADIO->POWER = 0; - NRF_RADIO->POWER = 1; - - /* Disable all interrupts */ - NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - - /* Set configuration registers */ - NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit; - NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | - (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos); - /* XXX: should maxlen be 251 for encryption? */ - NRF_RADIO->PCNF1 = NRF_MAXLEN | - (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos) | - (NRF_BALEN << RADIO_PCNF1_BALEN_Pos) | - RADIO_PCNF1_WHITEEN_Msk; - - /* Set base0 with the advertising access address */ - NRF_RADIO->BASE0 = (BLE_ACCESS_ADDR_ADV << 8) & 0xFFFFFF00; - NRF_RADIO->PREFIX0 = (BLE_ACCESS_ADDR_ADV >> 24) & 0xFF; - - /* Configure the CRC registers */ - NRF_RADIO->CRCCNF = RADIO_CRCCNF_SKIPADDR_Msk | RADIO_CRCCNF_LEN_Three; - - /* Configure BLE poly */ - NRF_RADIO->CRCPOLY = 0x0100065B; - - /* Configure IFS */ - NRF_RADIO->TIFS = BLE_LL_IFS; - - /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */ - NRF_PPI->CHENSET = PPI_CHEN_CH26_Msk | PPI_CHEN_CH27_Msk; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - NRF_CCM->INTENCLR = 0xffffffff; - NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; - NRF_CCM->EVENTS_ERROR = 0; - memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad)); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - g_ble_phy_data.phy_aar_scratch = 0; - NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; - NRF_AAR->INTENCLR = 0xffffffff; - NRF_AAR->EVENTS_END = 0; - NRF_AAR->EVENTS_RESOLVED = 0; - NRF_AAR->EVENTS_NOTRESOLVED = 0; - NRF_AAR->NIRK = 0; -#endif - - /* TIMER0 setup for PHY when using RTC */ - NRF_TIMER0->TASKS_STOP = 1; - NRF_TIMER0->TASKS_SHUTDOWN = 1; - NRF_TIMER0->BITMODE = 3; /* 32-bit timer */ - NRF_TIMER0->MODE = 0; /* Timer mode */ - NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */ - - /* - * PPI setup. - * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used - * to cancel the wait for response timer. - * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait - * for response timer. - */ - NRF_PPI->CH[4].EEP = (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS); - NRF_PPI->CH[4].TEP = (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3]); - NRF_PPI->CH[5].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]); - NRF_PPI->CH[5].TEP = (uint32_t)&(NRF_RADIO->TASKS_DISABLE); - - /* Set isr in vector table and enable interrupt */ -#ifndef RIOT_VERSION - NVIC_SetPriority(RADIO_IRQn, 0); -#endif -#if MYNEWT - NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr); -#else - ble_npl_hw_set_isr(RADIO_IRQn, ble_phy_isr); -#endif - NVIC_EnableIRQ(RADIO_IRQn); - - /* Register phy statistics */ - if (!g_ble_phy_data.phy_stats_initialized) { - rc = stats_init_and_reg(STATS_HDR(ble_phy_stats), - STATS_SIZE_INIT_PARMS(ble_phy_stats, - STATS_SIZE_32), - STATS_NAME_INIT_PARMS(ble_phy_stats), - "ble_phy"); - assert(rc == 0); - - g_ble_phy_data.phy_stats_initialized = 1; - } - - return 0; -} - -/** - * Puts the phy into receive mode. - * - * @return int 0: success; BLE Phy error code otherwise - */ -int -ble_phy_rx(void) -{ - /* Check radio state */ - nrf_wait_disabled(); - if (NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) { - ble_phy_disable(); - STATS_INC(ble_phy_stats, radio_state_errs); - return BLE_PHY_ERR_RADIO_STATE; - } - - /* Make sure all interrupts are disabled */ - NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - - /* Clear events prior to enabling receive */ - NRF_RADIO->EVENTS_END = 0; - NRF_RADIO->EVENTS_DISABLED = 0; - - /* Setup for rx */ - ble_phy_rx_xcvr_setup(); - - /* Start the receive task in the radio if not automatically going to rx */ - if ((NRF_PPI->CHEN & PPI_CHEN_CH21_Msk) == 0) { - NRF_RADIO->TASKS_RXEN = 1; - } - - return 0; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/** - * Called to enable encryption at the PHY. Note that this state will persist - * in the PHY; in other words, if you call this function you have to call - * disable so that future PHY transmits/receives will not be encrypted. - * - * @param pkt_counter - * @param iv - * @param key - * @param is_master - */ -void -ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_master) -{ - memcpy(g_nrf_ccm_data.key, key, 16); - g_nrf_ccm_data.pkt_counter = pkt_counter; - memcpy(g_nrf_ccm_data.iv, iv, 8); - g_nrf_ccm_data.dir_bit = is_master; - g_ble_phy_data.phy_encrypted = 1; - - /* Encryption uses LFLEN=5, S1LEN = 3. */ - NRF_RADIO->PCNF0 = (5 << RADIO_PCNF0_LFLEN_Pos) | - (3 << RADIO_PCNF0_S1LEN_Pos) | - (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos); - - /* Enable the module (AAR cannot be on while CCM on) */ - NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled; - NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled; -} - -void -ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir) -{ - g_nrf_ccm_data.pkt_counter = pkt_counter; - g_nrf_ccm_data.dir_bit = dir; -} - -void -ble_phy_encrypt_disable(void) -{ - NRF_PPI->CHENCLR = (PPI_CHEN_CH24_Msk | PPI_CHEN_CH25_Msk); - NRF_CCM->TASKS_STOP = 1; - NRF_CCM->EVENTS_ERROR = 0; - NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Disabled; - - /* Switch back to normal length */ - NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | - (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos); - - g_ble_phy_data.phy_encrypted = 0; -} -#endif - -void -ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg) -{ - /* Set transmit end callback and arg */ - g_ble_phy_data.txend_cb = txend_cb; - g_ble_phy_data.txend_arg = arg; -} - -/** - * Called to set the start time of a transmission. - * - * This function is called to set the start time when we are not going from - * rx to tx automatically. - * - * NOTE: care must be taken when calling this function. The channel should - * already be set. - * - * @param cputime This is the tick at which the 1st bit of the preamble - * should be transmitted - * @param rem_usecs This is used only when the underlying timing uses a 32.768 - * kHz crystal. It is the # of usecs from the cputime tick - * at which the first bit of the preamble should be - * transmitted. - * @return int - */ -int -ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) -{ - int rc; - - ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_TX, cputime, rem_usecs); - - /* XXX: This should not be necessary, but paranoia is good! */ - /* Clear timer0 compare to RXEN since we are transmitting */ - NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; - - /* - * XXX: The TXEN time is 140 usecs but there may be additional delays - * Need to look at this. - */ - if (ble_phy_set_start_time(cputime, rem_usecs) != 0) { - STATS_INC(ble_phy_stats, tx_late); - ble_phy_disable(); - rc = BLE_PHY_ERR_TX_LATE; - } else { - /* Enable PPI to automatically start TXEN */ - NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk; - rc = 0; - } - return rc; -} -/** - * Called to set the start time of a reception - * - * This function acts a bit differently than transmit. If we are late getting - * here we will still attempt to receive. - * - * NOTE: care must be taken when calling this function. The channel should - * already be set. - * - * @param cputime - * - * @return int - */ -int -ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) -{ - int rc; - - ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_RX, cputime, rem_usecs); - - /* XXX: This should not be necessary, but paranoia is good! */ - /* Clear timer0 compare to TXEN since we are transmitting */ - NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk; - - /* - * XXX: The RXEN time is 138 usecs but there may be additional delays - * Need to look at this. - */ - if (ble_phy_set_start_time(cputime, rem_usecs) != 0) { - STATS_INC(ble_phy_stats, rx_late); - NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; - NRF_RADIO->TASKS_RXEN = 1; - rc = BLE_PHY_ERR_RX_LATE; - } else { - /* Enable PPI to automatically start RXEN */ - NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk; - - /* Start rx */ - rc = ble_phy_rx(); - } - return rc; -} - -int -ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) -{ - int rc; - uint8_t *dptr; - uint8_t payload_len; - uint8_t payload_off; - uint8_t hdr_byte; - uint32_t state; - uint32_t shortcuts; - - /* - * This check is to make sure that the radio is not in a state where - * it is moving to disabled state. If so, let it get there. - */ - nrf_wait_disabled(); - - /* - * XXX: Although we may not have to do this here, I clear all the PPI - * that should not be used when transmitting. Some of them are only enabled - * if encryption and/or privacy is on, but I dont care. Better to be - * paranoid, and if you are going to clear one, might as well clear them - * all. - */ - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH23_Msk | - PPI_CHEN_CH25_Msk; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (g_ble_phy_data.phy_encrypted) { - /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */ - dptr = (uint8_t *)&g_ble_phy_enc_buf[0]; - payload_off = 3; - - NRF_CCM->SHORTS = 1; - NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM->OUTPTR = (uint32_t)&g_ble_phy_tx_buf[0]; - NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; - NRF_CCM->EVENTS_ERROR = 0; - NRF_CCM->MODE = CCM_MODE_MODE_Encryption; - NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data; - NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk; - } else { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* Reconfigure PCNF0 */ - NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | - (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos); - NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; -#endif - /* RAM representation has S0 and LENGTH fields (2 bytes) */ - dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; - payload_off = 2; - } -#else - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* Reconfigure PCNF0 */ - NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | - (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos); -#endif - - /* RAM representation has S0 and LENGTH fields (2 bytes) */ - dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; - payload_off = 2; -#endif - - NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_tx_buf[0]; - - /* Clear the ready, end and disabled events */ - NRF_RADIO->EVENTS_READY = 0; - NRF_RADIO->EVENTS_END = 0; - NRF_RADIO->EVENTS_DISABLED = 0; - - /* Enable shortcuts for transmit start/end. */ - shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk; - if (end_trans == BLE_PHY_TRANSITION_TX_RX) { - shortcuts |= RADIO_SHORTS_DISABLED_RXEN_Msk; - } - NRF_RADIO->SHORTS = shortcuts; - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; - - /* Set PDU payload */ - payload_len = pducb(&dptr[payload_off], pducb_arg, &hdr_byte); - - /* Set PDU header */ - dptr[0] = hdr_byte; - dptr[1] = payload_len; - if (payload_off > 2) { - dptr[2] = 0; - } - - /* Set the PHY transition */ - g_ble_phy_data.phy_transition = end_trans; - - /* Set transmitted payload length */ - g_ble_phy_data.phy_tx_pyld_len = payload_len; - - /* If we already started transmitting, abort it! */ - state = NRF_RADIO->STATE; - if (state != RADIO_STATE_STATE_Tx) { - - /* Set phy state to transmitting and count packet statistics */ - g_ble_phy_data.phy_state = BLE_PHY_STATE_TX; - STATS_INC(ble_phy_stats, tx_good); - STATS_INCN(ble_phy_stats, tx_bytes, payload_len + BLE_LL_PDU_HDR_LEN); - rc = BLE_ERR_SUCCESS; - } else { - ble_phy_disable(); - STATS_INC(ble_phy_stats, tx_late); - rc = BLE_PHY_ERR_RADIO_STATE; - } - - return rc; -} - -/** - * ble phy txpwr set - * - * Set the transmit output power (in dBm). - * - * NOTE: If the output power specified is within the BLE limits but outside - * the chip limits, we "rail" the power level so we dont exceed the min/max - * chip values. - * - * @param dbm Power output in dBm. - * - * @return int 0: success; anything else is an error - */ -int -ble_phy_txpwr_set(int dbm) -{ - /* Check valid range */ - assert(dbm <= BLE_PHY_MAX_PWR_DBM); - - /* "Rail" power level if outside supported range */ - if (dbm > NRF_TX_PWR_MAX_DBM) { - dbm = NRF_TX_PWR_MAX_DBM; - } else { - if (dbm < NRF_TX_PWR_MIN_DBM) { - dbm = NRF_TX_PWR_MIN_DBM; - } - } - - NRF_RADIO->TXPOWER = dbm; - g_ble_phy_data.phy_txpwr_dbm = dbm; - - return 0; -} - -/** - * ble phy txpwr round - * - * Get the rounded transmit output power (in dBm). - * - * @param dbm Power output in dBm. - * - * @return int Rounded power in dBm - */ -int ble_phy_txpower_round(int dbm) -{ - /* "Rail" power level if outside supported range */ - if (dbm > NRF_TX_PWR_MAX_DBM) { - dbm = NRF_TX_PWR_MAX_DBM; - } else { - if (dbm < NRF_TX_PWR_MIN_DBM) { - dbm = NRF_TX_PWR_MIN_DBM; - } - } - - return dbm; -} - -/** - * ble phy txpwr get - * - * Get the transmit power. - * - * @return int The current PHY transmit power, in dBm - */ -int -ble_phy_txpwr_get(void) -{ - return g_ble_phy_data.phy_txpwr_dbm; -} - -void -ble_phy_set_rx_pwr_compensation(int8_t compensation) -{ - g_ble_phy_data.rx_pwr_compensation = compensation; -} - -/** - * ble phy setchan - * - * Sets the logical frequency of the transceiver. The input parameter is the - * BLE channel index (0 to 39, inclusive). The NRF frequency register works like - * this: logical frequency = 2400 + FREQ (MHz). - * - * Thus, to get a logical frequency of 2402 MHz, you would program the - * FREQUENCY register to 2. - * - * @param chan This is the Data Channel Index or Advertising Channel index - * - * @return int 0: success; PHY error code otherwise - */ -int -ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) -{ - uint32_t prefix; - - assert(chan < BLE_PHY_NUM_CHANS); - - /* Check for valid channel range */ - if (chan >= BLE_PHY_NUM_CHANS) { - return BLE_PHY_ERR_INV_PARAM; - } - - /* Get correct frequency */ - if (chan < BLE_PHY_NUM_DATA_CHANS) { - /* Set current access address */ - g_ble_phy_data.phy_access_address = access_addr; - - /* Configure logical address 1 and crcinit */ - prefix = NRF_RADIO->PREFIX0; - prefix &= 0xffff00ff; - prefix |= ((access_addr >> 24) & 0xFF) << 8; - NRF_RADIO->BASE1 = (access_addr << 8) & 0xFFFFFF00; - NRF_RADIO->PREFIX0 = prefix; - NRF_RADIO->TXADDRESS = 1; - NRF_RADIO->RXADDRESSES = (1 << 1); - NRF_RADIO->CRCINIT = crcinit; - } else { - /* Logical adddress 0 preconfigured */ - NRF_RADIO->TXADDRESS = 0; - NRF_RADIO->RXADDRESSES = (1 << 0); - NRF_RADIO->CRCINIT = BLE_LL_CRCINIT_ADV; - - /* Set current access address */ - g_ble_phy_data.phy_access_address = BLE_ACCESS_ADDR_ADV; - } - - /* Set the frequency and the data whitening initial value */ - g_ble_phy_data.phy_chan = chan; - NRF_RADIO->FREQUENCY = g_ble_phy_chan_freq[chan]; - NRF_RADIO->DATAWHITEIV = chan; - - return 0; -} - -/** - * Stop the timer used to count microseconds when using RTC for cputime - */ -static void -ble_phy_stop_usec_timer(void) -{ - NRF_TIMER0->TASKS_STOP = 1; - NRF_TIMER0->TASKS_SHUTDOWN = 1; - NRF_RTC0->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk; -} - -/** - * ble phy disable irq and ppi - * - * This routine is to be called when reception was stopped due to either a - * wait for response timeout or a packet being received and the phy is to be - * restarted in receive mode. Generally, the disable routine is called to stop - * the phy. - */ -static void -ble_phy_disable_irq_and_ppi(void) -{ - NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - NRF_RADIO->SHORTS = 0; - NRF_RADIO->TASKS_DISABLE = 1; - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH20_Msk | - PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk | PPI_CHEN_CH24_Msk | - PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk; - NVIC_ClearPendingIRQ(RADIO_IRQn); - g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE; -} - -void -ble_phy_restart_rx(void) -{ - ble_phy_stop_usec_timer(); - ble_phy_disable_irq_and_ppi(); - ble_phy_rx(); -} - -/** - * ble phy disable - * - * Disables the PHY. This should be called when an event is over. It stops - * the usec timer (if used), disables interrupts, disables the RADIO, disables - * PPI and sets state to idle. - */ -void -ble_phy_disable(void) -{ - ble_phy_trace_void(BLE_PHY_TRACE_ID_DISABLE); - - ble_phy_stop_usec_timer(); - ble_phy_disable_irq_and_ppi(); -} - -/* Gets the current access address */ -uint32_t ble_phy_access_addr_get(void) -{ - return g_ble_phy_data.phy_access_address; -} - -/** - * Return the phy state - * - * @return int The current PHY state. - */ -int -ble_phy_state_get(void) -{ - return g_ble_phy_data.phy_state; -} - -/** - * Called to see if a reception has started - * - * @return int - */ -int -ble_phy_rx_started(void) -{ - return g_ble_phy_data.phy_rx_started; -} - -/** - * Return the transceiver state - * - * @return int transceiver state. - */ -uint8_t -ble_phy_xcvr_state_get(void) -{ - uint32_t state; - state = NRF_RADIO->STATE; - return (uint8_t)state; -} - -/** - * Called to return the maximum data pdu payload length supported by the - * phy. For this chip, if encryption is enabled, the maximum payload is 27 - * bytes. - * - * @return uint8_t Maximum data channel PDU payload size supported - */ -uint8_t -ble_phy_max_data_pdu_pyld(void) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - return NRF_MAX_ENCRYPTED_PYLD_LEN; -#else - return BLE_LL_DATA_PDU_MAX_PYLD; -#endif -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -void -ble_phy_resolv_list_enable(void) -{ - NRF_AAR->NIRK = (uint32_t)g_nrf_num_irks; - g_ble_phy_data.phy_privacy = 1; -} - -void -ble_phy_resolv_list_disable(void) -{ - g_ble_phy_data.phy_privacy = 0; -} -#endif - -void -ble_phy_rfclk_enable(void) -{ -#if MYNEWT || ARDUINO - nrf51_clock_hfxo_request(); -#else - NRF_CLOCK->TASKS_HFCLKSTART = 1; -#endif -} - -void -ble_phy_rfclk_disable(void) -{ -#if MYNEWT || ARDUINO - nrf51_clock_hfxo_release(); -#else - NRF_CLOCK->TASKS_HFCLKSTOP = 1; -#endif -} -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf52/include/ble/xcvr.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf52/include/ble/xcvr.h deleted file mode 100644 index fd8e1e898..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf52/include/ble/xcvr.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#if defined(ARDUINO_ARCH_NRF5) && defined(NRF52_SERIES) - -#ifndef H_BLE_XCVR_ -#define H_BLE_XCVR_ - -#ifdef __cplusplus -extern "C" { -#endif - -#define XCVR_RX_RADIO_RAMPUP_USECS (40) -#define XCVR_TX_RADIO_RAMPUP_USECS (40) - -/* - * NOTE: we have to account for the RTC output compare issue. We want it to be - * 5 ticks. - */ -#define XCVR_PROC_DELAY_USECS (153) -#define XCVR_RX_START_DELAY_USECS (XCVR_RX_RADIO_RAMPUP_USECS) -#define XCVR_TX_START_DELAY_USECS (XCVR_TX_RADIO_RAMPUP_USECS) -#define XCVR_TX_SCHED_DELAY_USECS \ - (XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS) -#define XCVR_RX_SCHED_DELAY_USECS \ - (XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS) - -/* - * Define HW whitelist size. This is the total possible whitelist size; - * not necessarily the size that will be used (may be smaller) - */ -#define BLE_HW_WHITE_LIST_SIZE (8) - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_XCVR_ */ -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf52/src/ble_hw.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf52/src/ble_hw.c deleted file mode 100644 index 400fddf6f..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf52/src/ble_hw.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#if defined(ARDUINO_ARCH_NRF5) && defined(NRF52_SERIES) - -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os.h" -#include "../include/ble/xcvr.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "nrf.h" -#include "nimble/nimble/controller/include/controller/ble_hw.h" -#if MYNEWT -#include "mcu/cmsis_nvic.h" -#else -#include "core_cm4.h" -#include "nimble/porting/npl/freertos/include/nimble/nimble_npl_os.h" -#endif -#include "nimble/porting/nimble/include/os/os_trace_api.h" - -/* Total number of resolving list elements */ -#define BLE_HW_RESOLV_LIST_SIZE (16) - -/* We use this to keep track of which entries are set to valid addresses */ -static uint8_t g_ble_hw_whitelist_mask; - -/* Random number generator isr callback */ -ble_rng_isr_cb_t g_ble_rng_isr_cb; - -/* If LL privacy is enabled, allocate memory for AAR */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - -/* The NRF51 supports up to 16 IRK entries */ -#if (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE) < 16) -#define NRF_IRK_LIST_ENTRIES (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE)) -#else -#define NRF_IRK_LIST_ENTRIES (16) -#endif - -/* NOTE: each entry is 16 bytes long. */ -uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4]; - -/* Current number of IRK entries */ -uint8_t g_nrf_num_irks; - -#endif - -/* Returns public device address or -1 if not present */ -int -ble_hw_get_public_addr(ble_addr_t *addr) -{ - uint32_t addr_high; - uint32_t addr_low; - - /* Does FICR have a public address */ - if ((NRF_FICR->DEVICEADDRTYPE & 1) != 0) { - return -1; - } - - /* Copy into device address. We can do this because we know platform */ - addr_low = NRF_FICR->DEVICEADDR[0]; - addr_high = NRF_FICR->DEVICEADDR[1]; - memcpy(addr->val, &addr_low, 4); - memcpy(&addr->val[4], &addr_high, 2); - addr->type = BLE_ADDR_PUBLIC; - - return 0; -} - -/* Returns random static address or -1 if not present */ -int -ble_hw_get_static_addr(ble_addr_t *addr) -{ - int rc; - - if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) { - memcpy(addr->val, (void *)&NRF_FICR->DEVICEADDR[0], 4); - memcpy(&addr->val[4], (void *)&NRF_FICR->DEVICEADDR[1], 2); - addr->val[5] |= 0xc0; - addr->type = BLE_ADDR_RANDOM; - rc = 0; - } else { - rc = -1; - } - - return rc; -} - -/** - * Clear the whitelist - * - * @return int - */ -void -ble_hw_whitelist_clear(void) -{ - NRF_RADIO->DACNF = 0; - g_ble_hw_whitelist_mask = 0; -} - -/** - * Add a device to the hw whitelist - * - * @param addr - * @param addr_type - * - * @return int 0: success, BLE error code otherwise - */ -int -ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type) -{ - int i; - uint32_t mask; - - /* Find first ununsed device address match element */ - mask = 0x01; - for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) { - if ((mask & g_ble_hw_whitelist_mask) == 0) { - NRF_RADIO->DAB[i] = get_le32(addr); - NRF_RADIO->DAP[i] = get_le16(addr + 4); - if (addr_type == BLE_ADDR_RANDOM) { - NRF_RADIO->DACNF |= (mask << 8); - } - g_ble_hw_whitelist_mask |= mask; - return BLE_ERR_SUCCESS; - } - mask <<= 1; - } - - return BLE_ERR_MEM_CAPACITY; -} - -/** - * Remove a device from the hw whitelist - * - * @param addr - * @param addr_type - * - */ -void -ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type) -{ - int i; - uint8_t cfg_addr; - uint16_t dap; - uint16_t txadd; - uint32_t dab; - uint32_t mask; - - /* Find first ununsed device address match element */ - dab = get_le32(addr); - dap = get_le16(addr + 4); - txadd = NRF_RADIO->DACNF >> 8; - mask = 0x01; - for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) { - if (mask & g_ble_hw_whitelist_mask) { - if ((dab == NRF_RADIO->DAB[i]) && (dap == NRF_RADIO->DAP[i])) { - cfg_addr = txadd & mask; - if (addr_type == BLE_ADDR_RANDOM) { - if (cfg_addr != 0) { - break; - } - } else { - if (cfg_addr == 0) { - break; - } - } - } - } - mask <<= 1; - } - - if (i < BLE_HW_WHITE_LIST_SIZE) { - g_ble_hw_whitelist_mask &= ~mask; - NRF_RADIO->DACNF &= ~mask; - } -} - -/** - * Returns the size of the whitelist in HW - * - * @return int Number of devices allowed in whitelist - */ -uint8_t -ble_hw_whitelist_size(void) -{ - return BLE_HW_WHITE_LIST_SIZE; -} - -/** - * Enable the whitelisted devices - */ -void -ble_hw_whitelist_enable(void) -{ - /* Enable the configured device addresses */ - NRF_RADIO->DACNF |= g_ble_hw_whitelist_mask; -} - -/** - * Disables the whitelisted devices - */ -void -ble_hw_whitelist_disable(void) -{ - /* Disable all whitelist devices */ - NRF_RADIO->DACNF &= 0x0000ff00; -} - -/** - * Boolean function which returns true ('1') if there is a match on the - * whitelist. - * - * @return int - */ -int -ble_hw_whitelist_match(void) -{ - return (int)NRF_RADIO->EVENTS_DEVMATCH; -} - -/* Encrypt data */ -int -ble_hw_encrypt_block(struct ble_encryption_block *ecb) -{ - int rc; - uint32_t end; - uint32_t err; - - /* Stop ECB */ - NRF_ECB->TASKS_STOPECB = 1; - /* XXX: does task stop clear these counters? Anyway to do this quicker? */ - NRF_ECB->EVENTS_ENDECB = 0; - NRF_ECB->EVENTS_ERRORECB = 0; - NRF_ECB->ECBDATAPTR = (uint32_t)ecb; - - /* Start ECB */ - NRF_ECB->TASKS_STARTECB = 1; - - /* Wait till error or done */ - rc = 0; - while (1) { - end = NRF_ECB->EVENTS_ENDECB; - err = NRF_ECB->EVENTS_ERRORECB; - if (end || err) { - if (err) { - rc = -1; - } - break; - } - } - - return rc; -} - -/** - * Random number generator ISR. - */ -static void -ble_rng_isr(void) -{ - uint8_t rnum; - - os_trace_isr_enter(); - - /* No callback? Clear and disable interrupts */ - if (g_ble_rng_isr_cb == NULL) { - NRF_RNG->INTENCLR = 1; - NRF_RNG->EVENTS_VALRDY = 0; - (void)NRF_RNG->SHORTS; - os_trace_isr_exit(); - return; - } - - /* If there is a value ready grab it */ - if (NRF_RNG->EVENTS_VALRDY) { - NRF_RNG->EVENTS_VALRDY = 0; - rnum = (uint8_t)NRF_RNG->VALUE; - (*g_ble_rng_isr_cb)(rnum); - } - - os_trace_isr_exit(); -} - -/** - * Initialize the random number generator - * - * @param cb - * @param bias - * - * @return int - */ -int -ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias) -{ - /* Set bias */ - if (bias) { - NRF_RNG->CONFIG = 1; - } else { - NRF_RNG->CONFIG = 0; - } - - /* If we were passed a function pointer we need to enable the interrupt */ - if (cb != NULL) { -#ifndef RIOT_VERSION - NVIC_SetPriority(RNG_IRQn, (1 << __NVIC_PRIO_BITS) - 1); -#endif -#if MYNEWT - NVIC_SetVector(RNG_IRQn, (uint32_t)ble_rng_isr); -#else - ble_npl_hw_set_isr(RNG_IRQn, ble_rng_isr); -#endif - NVIC_EnableIRQ(RNG_IRQn); - g_ble_rng_isr_cb = cb; - } - - return 0; -} - -/** - * Start the random number generator - * - * @return int - */ -int -ble_hw_rng_start(void) -{ - os_sr_t sr; - - /* No need for interrupt if there is no callback */ - OS_ENTER_CRITICAL(sr); - NRF_RNG->EVENTS_VALRDY = 0; - if (g_ble_rng_isr_cb) { - NRF_RNG->INTENSET = 1; - } - NRF_RNG->TASKS_START = 1; - OS_EXIT_CRITICAL(sr); - - return 0; -} - -/** - * Stop the random generator - * - * @return int - */ -int -ble_hw_rng_stop(void) -{ - os_sr_t sr; - - /* No need for interrupt if there is no callback */ - OS_ENTER_CRITICAL(sr); - NRF_RNG->INTENCLR = 1; - NRF_RNG->TASKS_STOP = 1; - NRF_RNG->EVENTS_VALRDY = 0; - OS_EXIT_CRITICAL(sr); - - return 0; -} - -/** - * Read the random number generator. - * - * @return uint8_t - */ -uint8_t -ble_hw_rng_read(void) -{ - uint8_t rnum; - - /* Wait for a sample */ - while (NRF_RNG->EVENTS_VALRDY == 0) { - } - - NRF_RNG->EVENTS_VALRDY = 0; - rnum = (uint8_t)NRF_RNG->VALUE; - - return rnum; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -/** - * Clear the resolving list - * - * @return int - */ -void -ble_hw_resolv_list_clear(void) -{ - g_nrf_num_irks = 0; -} - -/** - * Add a device to the hw resolving list - * - * @param irk Pointer to IRK to add - * - * @return int 0: success, BLE error code otherwise - */ -int -ble_hw_resolv_list_add(uint8_t *irk) -{ - uint32_t *nrf_entry; - - /* Find first ununsed device address match element */ - if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) { - return BLE_ERR_MEM_CAPACITY; - } - - /* Copy into irk list */ - nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks]; - memcpy(nrf_entry, irk, 16); - - /* Add to total */ - ++g_nrf_num_irks; - return BLE_ERR_SUCCESS; -} - -/** - * Remove a device from the hw resolving list - * - * @param index Index of IRK to remove - */ -void -ble_hw_resolv_list_rmv(int index) -{ - uint32_t *irk_entry; - - if (index < g_nrf_num_irks) { - --g_nrf_num_irks; - irk_entry = &g_nrf_irk_list[index]; - if (g_nrf_num_irks > index) { - memmove(irk_entry, irk_entry + 4, 16 * (g_nrf_num_irks - index)); - } - } -} - -/** - * Returns the size of the resolving list. NOTE: this returns the maximum - * allowable entries in the HW. Configuration options may limit this. - * - * @return int Number of devices allowed in resolving list - */ -uint8_t -ble_hw_resolv_list_size(void) -{ - return BLE_HW_RESOLV_LIST_SIZE; -} - -/** - * Called to determine if the address received was resolved. - * - * @return int Negative values indicate unresolved address; positive values - * indicate index in resolving list of resolved address. - */ -int -ble_hw_resolv_list_match(void) -{ - uint32_t index; - - if (NRF_AAR->EVENTS_END) { - if (NRF_AAR->EVENTS_RESOLVED) { - index = NRF_AAR->STATUS; - return (int)index; - } - } - - return -1; -} -#endif -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf52/src/ble_phy.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf52/src/ble_phy.c deleted file mode 100644 index 08511c340..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf52/src/ble_phy.c +++ /dev/null @@ -1,2120 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - #if defined(ARDUINO_ARCH_NRF5) && defined(NRF52_SERIES) - -#include -#include -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os.h" -#include "../include/ble/xcvr.h" -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/include/nimble/nimble_opt.h" -#include "nimble/nimble/include/nimble/nimble_npl.h" -#include "nimble/nimble/controller/include/controller/ble_phy.h" -#include "nimble/nimble/controller/include/controller/ble_phy_trace.h" -#include "nimble/nimble/controller/include/controller/ble_ll.h" -#include "nrf.h" -#if MYNEWT -#include "mcu/nrf52_clock.h" -#include "mcu/cmsis_nvic.h" -#include "hal/hal_gpio.h" -#else -#include "core_cm4.h" -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) -#if !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52840) && !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52811) -#error LE Coded PHY can only be enabled on nRF52811 or nRF52840 -#endif -#endif - -/* - * NOTE: This code uses a couple of PPI channels so care should be taken when - * using PPI somewhere else. - * - * Pre-programmed channels: CH20, CH21, CH23, CH25, CH31 - * Regular channels: CH4, CH5 and optionally CH17, CH18, CH19 - * - CH4 = cancel wfr timer on address match - * - CH5 = disable radio on wfr timer expiry - * - CH17 = (optional) gpio debug for radio ramp-up - * - CH18 = (optional) gpio debug for wfr timer RX enabled - * - CH19 = (optional) gpio debug for wfr timer radio disabled - * - */ - -/* XXX: 4) Make sure RF is higher priority interrupt than schedule */ - -/* - * XXX: Maximum possible transmit time is 1 msec for a 60ppm crystal - * and 16ms for a 30ppm crystal! We need to limit PDU size based on - * crystal accuracy. Look at this in the spec. - */ - -/* XXX: private header file? */ -extern uint8_t g_nrf_num_irks; -extern uint32_t g_nrf_irk_list[]; - -/* To disable all radio interrupts */ -#define NRF_RADIO_IRQ_MASK_ALL (0x34FF) - -/* - * We configure the nrf with a 1 byte S0 field, 8 bit length field, and - * zero bit S1 field. The preamble is 8 bits long. - */ -#define NRF_LFLEN_BITS (8) -#define NRF_S0LEN (1) -#define NRF_S1LEN_BITS (0) -#define NRF_CILEN_BITS (2) -#define NRF_TERMLEN_BITS (3) - -/* Maximum length of frames */ -#define NRF_MAXLEN (255) -#define NRF_BALEN (3) /* For base address of 3 bytes */ - -/* NRF_RADIO->PCNF0 configuration values */ -#define NRF_PCNF0 (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | \ - (RADIO_PCNF0_S1INCL_Msk) | \ - (NRF_S0LEN << RADIO_PCNF0_S0LEN_Pos) | \ - (NRF_S1LEN_BITS << RADIO_PCNF0_S1LEN_Pos) -#define NRF_PCNF0_1M (NRF_PCNF0) | \ - (RADIO_PCNF0_PLEN_8bit << RADIO_PCNF0_PLEN_Pos) -#define NRF_PCNF0_2M (NRF_PCNF0) | \ - (RADIO_PCNF0_PLEN_16bit << RADIO_PCNF0_PLEN_Pos) -#define NRF_PCNF0_CODED (NRF_PCNF0) | \ - (RADIO_PCNF0_PLEN_LongRange << RADIO_PCNF0_PLEN_Pos) | \ - (NRF_CILEN_BITS << RADIO_PCNF0_CILEN_Pos) | \ - (NRF_TERMLEN_BITS << RADIO_PCNF0_TERMLEN_Pos) - -/* BLE PHY data structure */ -struct ble_phy_obj -{ - uint8_t phy_stats_initialized; - int8_t phy_txpwr_dbm; - uint8_t phy_chan; - uint8_t phy_state; - uint8_t phy_transition; - uint8_t phy_transition_late; - uint8_t phy_rx_started; - uint8_t phy_encrypted; - uint8_t phy_privacy; - uint8_t phy_tx_pyld_len; - uint8_t phy_cur_phy_mode; - uint8_t phy_tx_phy_mode; - uint8_t phy_rx_phy_mode; - uint8_t phy_bcc_offset; - int8_t rx_pwr_compensation; - uint32_t phy_aar_scratch; - uint32_t phy_access_address; - struct ble_mbuf_hdr rxhdr; - void *txend_arg; - ble_phy_tx_end_func txend_cb; - uint32_t phy_start_cputime; -}; -struct ble_phy_obj g_ble_phy_data; - -/* XXX: if 27 byte packets desired we can make this smaller */ -/* Global transmit/receive buffer */ -static uint32_t g_ble_phy_tx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; -static uint32_t g_ble_phy_rx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/* Make sure word-aligned for faster copies */ -static uint32_t g_ble_phy_enc_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; -#endif - -/* RF center frequency for each channel index (offset from 2400 MHz) */ -static const uint8_t g_ble_phy_chan_freq[BLE_PHY_NUM_CHANS] = { - 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, /* 0-9 */ - 24, 28, 30, 32, 34, 36, 38, 40, 42, 44, /* 10-19 */ - 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, /* 20-29 */ - 66, 68, 70, 72, 74, 76, 78, 2, 26, 80, /* 30-39 */ -}; - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) -/* packet start offsets (in usecs) */ -static const uint16_t g_ble_phy_mode_pkt_start_off[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 40, - [BLE_PHY_MODE_2M] = 24, - [BLE_PHY_MODE_CODED_125KBPS] = 376, - [BLE_PHY_MODE_CODED_500KBPS] = 376 -}; -#endif - -/* Various radio timings */ -/* Radio ramp-up times in usecs (fast mode) */ -#define BLE_PHY_T_TXENFAST (XCVR_TX_RADIO_RAMPUP_USECS) -#define BLE_PHY_T_RXENFAST (XCVR_RX_RADIO_RAMPUP_USECS) -/* delay between EVENTS_READY and start of tx */ -static const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 4, - [BLE_PHY_MODE_2M] = 3, - [BLE_PHY_MODE_CODED_125KBPS] = 5, - [BLE_PHY_MODE_CODED_500KBPS] = 5 -}; -/* delay between EVENTS_END and end of txd packet */ -static const uint8_t g_ble_phy_t_txenddelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 4, - [BLE_PHY_MODE_2M] = 3, - [BLE_PHY_MODE_CODED_125KBPS] = 9, - [BLE_PHY_MODE_CODED_500KBPS] = 3 -}; -/* delay between rxd access address (w/ TERM1 for coded) and EVENTS_ADDRESS */ -static const uint8_t g_ble_phy_t_rxaddrdelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 6, - [BLE_PHY_MODE_2M] = 2, - [BLE_PHY_MODE_CODED_125KBPS] = 17, - [BLE_PHY_MODE_CODED_500KBPS] = 17 -}; -/* delay between end of rxd packet and EVENTS_END */ -static const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 6, - [BLE_PHY_MODE_2M] = 2, - [BLE_PHY_MODE_CODED_125KBPS] = 27, - [BLE_PHY_MODE_CODED_500KBPS] = 22 -}; - -/* Statistics */ -STATS_SECT_START(ble_phy_stats) - STATS_SECT_ENTRY(phy_isrs) - STATS_SECT_ENTRY(tx_good) - STATS_SECT_ENTRY(tx_fail) - STATS_SECT_ENTRY(tx_late) - STATS_SECT_ENTRY(tx_bytes) - STATS_SECT_ENTRY(rx_starts) - STATS_SECT_ENTRY(rx_aborts) - STATS_SECT_ENTRY(rx_valid) - STATS_SECT_ENTRY(rx_crc_err) - STATS_SECT_ENTRY(rx_late) - STATS_SECT_ENTRY(radio_state_errs) - STATS_SECT_ENTRY(rx_hw_err) - STATS_SECT_ENTRY(tx_hw_err) -STATS_SECT_END -STATS_SECT_DECL(ble_phy_stats) ble_phy_stats; - -STATS_NAME_START(ble_phy_stats) - STATS_NAME(ble_phy_stats, phy_isrs) - STATS_NAME(ble_phy_stats, tx_good) - STATS_NAME(ble_phy_stats, tx_fail) - STATS_NAME(ble_phy_stats, tx_late) - STATS_NAME(ble_phy_stats, tx_bytes) - STATS_NAME(ble_phy_stats, rx_starts) - STATS_NAME(ble_phy_stats, rx_aborts) - STATS_NAME(ble_phy_stats, rx_valid) - STATS_NAME(ble_phy_stats, rx_crc_err) - STATS_NAME(ble_phy_stats, rx_late) - STATS_NAME(ble_phy_stats, radio_state_errs) - STATS_NAME(ble_phy_stats, rx_hw_err) - STATS_NAME(ble_phy_stats, tx_hw_err) -STATS_NAME_END(ble_phy_stats) - -/* - * NOTE: - * Tested the following to see what would happen: - * -> NVIC has radio irq enabled (interrupt # 1, mask 0x2). - * -> Set up nrf to receive. Clear ADDRESS event register. - * -> Enable ADDRESS interrupt on nrf5 by writing to INTENSET. - * -> Enable RX. - * -> Disable interrupts globally using OS_ENTER_CRITICAL(). - * -> Wait until a packet is received and the ADDRESS event occurs. - * -> Call ble_phy_disable(). - * - * At this point I wanted to see the state of the cortex NVIC. The IRQ - * pending bit was TRUE for the radio interrupt (as expected) as we never - * serviced the radio interrupt (interrupts were disabled). - * - * What was unexpected was this: without clearing the pending IRQ in the NVIC, - * when radio interrupts were re-enabled (address event bit in INTENSET set to - * 1) and the radio ADDRESS event register read 1 (it was never cleared after - * the first address event), the radio did not enter the ISR! I would have - * expected that if the following were true, an interrupt would occur: - * -> NVIC ISER bit set to TRUE - * -> NVIC ISPR bit reads TRUE, meaning interrupt is pending. - * -> Radio peripheral interrupts are enabled for some event (or events). - * -> Corresponding event register(s) in radio peripheral read 1. - * - * Not sure what the end result of all this is. We will clear the pending - * bit in the NVIC just to be sure when we disable the PHY. - */ - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - -/* - * Per nordic, the number of bytes needed for scratch is 16 + MAX_PKT_SIZE. - * However, when I used a smaller size it still overwrote the scratchpad. Until - * I figure this out I am just going to allocate 67 words so we have enough - * space for 267 bytes of scratch. I used 268 bytes since not sure if this - * needs to be aligned and burning a byte is no big deal. - */ -//#define NRF_ENC_SCRATCH_WORDS (((MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE) + 16) + 3) / 4) -#define NRF_ENC_SCRATCH_WORDS (67) - -uint32_t g_nrf_encrypt_scratchpad[NRF_ENC_SCRATCH_WORDS]; - -struct nrf_ccm_data -{ - uint8_t key[16]; - uint64_t pkt_counter; - uint8_t dir_bit; - uint8_t iv[8]; -} __attribute__((packed)); - -struct nrf_ccm_data g_nrf_ccm_data; -#endif - -static void -ble_phy_apply_errata_102_106_107(void) -{ - /* [102] RADIO: PAYLOAD/END events delayed or not triggered after ADDRESS - * [106] RADIO: Higher CRC error rates for some access addresses - * [107] RADIO: Immediate address match for access addresses containing MSBs 0x00 - */ - *(volatile uint32_t *)0x40001774 = ((*(volatile uint32_t *)0x40001774) & - 0xfffffffe) | 0x01000000; -} - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - -/* Packet start offset (in usecs). This is the preamble plus access address. - * For LE Coded PHY this also includes CI and TERM1. */ -uint32_t -ble_phy_mode_pdu_start_off(int phy_mode) -{ - return g_ble_phy_mode_pkt_start_off[phy_mode]; -} - -#if NRF52840_XXAA -static inline bool -ble_phy_mode_is_coded(uint8_t phy_mode) -{ - return (phy_mode == BLE_PHY_MODE_CODED_125KBPS) || - (phy_mode == BLE_PHY_MODE_CODED_500KBPS); -} - -static void -ble_phy_apply_nrf52840_errata(uint8_t new_phy_mode) -{ - bool new_coded = ble_phy_mode_is_coded(new_phy_mode); - bool cur_coded = ble_phy_mode_is_coded(g_ble_phy_data.phy_cur_phy_mode); - - /* - * Workarounds should be applied only when switching to/from LE Coded PHY - * so no need to apply them every time. - * - * nRF52840 Engineering A Errata v1.2 - * [164] RADIO: Low sensitivity in long range mode - * - * nRF52840 Rev 1 Errata - * [191] RADIO: High packet error rate in BLE Long Range mode - */ - if (new_coded == cur_coded) { - return; - } - - if (new_coded) { -#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164) - /* [164] */ - *(volatile uint32_t *)0x4000173C |= 0x80000000; - *(volatile uint32_t *)0x4000173C = - ((*(volatile uint32_t *)0x4000173C & 0xFFFFFF00) | 0x5C); -#endif -#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191) - /* [191] */ - *(volatile uint32_t *) 0x40001740 = - ((*((volatile uint32_t *) 0x40001740)) & 0x7FFF00FF) | - 0x80000000 | (((uint32_t)(196)) << 8); -#endif - } else { -#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164) - /* [164] */ - *(volatile uint32_t *)0x4000173C &= ~0x80000000; -#endif -#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191) - /* [191] */ - *(volatile uint32_t *) 0x40001740 = - ((*((volatile uint32_t *) 0x40001740)) & 0x7FFFFFFF); -#endif - } -} -#endif - -static void -ble_phy_mode_apply(uint8_t phy_mode) -{ - if (phy_mode == g_ble_phy_data.phy_cur_phy_mode) { - return; - } - -#if NRF52840_XXAA - ble_phy_apply_nrf52840_errata(phy_mode); -#endif - - switch (phy_mode) { - case BLE_PHY_MODE_1M: - NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit; - NRF_RADIO->PCNF0 = NRF_PCNF0_1M; - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - case BLE_PHY_MODE_2M: - NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_2Mbit; - NRF_RADIO->PCNF0 = NRF_PCNF0_2M; - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case BLE_PHY_MODE_CODED_125KBPS: - NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR125Kbit; - NRF_RADIO->PCNF0 = NRF_PCNF0_CODED; - break; - case BLE_PHY_MODE_CODED_500KBPS: - NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR500Kbit; - NRF_RADIO->PCNF0 = NRF_PCNF0_CODED; - break; -#endif - default: - assert(0); - } - - g_ble_phy_data.phy_cur_phy_mode = phy_mode; -} - -void -ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode) -{ - g_ble_phy_data.phy_tx_phy_mode = tx_phy_mode; - g_ble_phy_data.phy_rx_phy_mode = rx_phy_mode; -} -#endif - -int -ble_phy_get_cur_phy(void) -{ -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - switch (g_ble_phy_data.phy_cur_phy_mode) { - case BLE_PHY_MODE_1M: - return BLE_PHY_1M; - case BLE_PHY_MODE_2M: - return BLE_PHY_2M; - case BLE_PHY_MODE_CODED_125KBPS: - case BLE_PHY_MODE_CODED_500KBPS: - return BLE_PHY_CODED; - default: - assert(0); - return -1; - } -#else - return BLE_PHY_1M; -#endif -} - -/** - * Copies the data from the phy receive buffer into a mbuf chain. - * - * @param dptr Pointer to receive buffer - * @param rxpdu Pointer to already allocated mbuf chain - * - * NOTE: the packet header already has the total mbuf length in it. The - * lengths of the individual mbufs are not set prior to calling. - * - */ -void -ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) -{ - uint32_t rem_len; - uint32_t copy_len; - uint32_t block_len; - uint32_t block_rem_len; - void *dst; - void *src; - struct os_mbuf * om; - - /* Better be aligned */ - assert(((uint32_t)dptr & 3) == 0); - - block_len = rxpdu->om_omp->omp_databuf_len; - rem_len = OS_MBUF_PKTHDR(rxpdu)->omp_len; - src = dptr; - - /* - * Setup for copying from first mbuf which is shorter due to packet header - * and extra leading space - */ - copy_len = block_len - rxpdu->om_pkthdr_len - 4; - om = rxpdu; - dst = om->om_data; - - while (true) { - /* - * Always copy blocks of length aligned to word size, only last mbuf - * will have remaining non-word size bytes appended. - */ - block_rem_len = copy_len; - copy_len = min(copy_len, rem_len); - copy_len &= ~3; - - dst = om->om_data; - om->om_len = copy_len; - rem_len -= copy_len; - block_rem_len -= copy_len; - - __asm__ volatile (".syntax unified \n" - " mov r4, %[len] \n" - " b 2f \n" - "1: ldr r3, [%[src], %[len]] \n" - " str r3, [%[dst], %[len]] \n" - "2: subs %[len], #4 \n" - " bpl 1b \n" - " adds %[src], %[src], r4 \n" - " adds %[dst], %[dst], r4 \n" - : [dst] "+r" (dst), [src] "+r" (src), - [len] "+r" (copy_len) - : - : "r3", "r4", "memory" - ); - - if ((rem_len < 4) && (block_rem_len >= rem_len)) { - break; - } - - /* Move to next mbuf */ - om = SLIST_NEXT(om, om_next); - copy_len = block_len; - } - - /* Copy remaining bytes, if any, to last mbuf */ - om->om_len += rem_len; - __asm__ volatile (".syntax unified \n" - " b 2f \n" - "1: ldrb r3, [%[src], %[len]] \n" - " strb r3, [%[dst], %[len]] \n" - "2: subs %[len], #1 \n" - " bpl 1b \n" - : [len] "+r" (rem_len) - : [dst] "r" (dst), [src] "r" (src) - : "r3", "memory" - ); - - /* Copy header */ - memcpy(BLE_MBUF_HDR_PTR(rxpdu), &g_ble_phy_data.rxhdr, - sizeof(struct ble_mbuf_hdr)); -} - -/** - * Called when we want to wait if the radio is in either the rx or tx - * disable states. We want to wait until that state is over before doing - * anything to the radio - */ -static void -nrf_wait_disabled(void) -{ - uint32_t state; - - state = NRF_RADIO->STATE; - if (state != RADIO_STATE_STATE_Disabled) { - if ((state == RADIO_STATE_STATE_RxDisable) || - (state == RADIO_STATE_STATE_TxDisable)) { - /* This will end within a short time (6 usecs). Just poll */ - while (NRF_RADIO->STATE == state) { - /* If this fails, something is really wrong. Should last - * no more than 6 usecs */ - } - } - } -} - -/** - * - * - */ -static int -ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx) -{ - uint32_t next_cc; - uint32_t cur_cc; - uint32_t cntr; - uint32_t delta; - - /* - * We need to adjust start time to include radio ramp-up and TX pipeline - * delay (the latter only if applicable, so only for TX). - * - * Radio ramp-up time is 40 usecs and TX delay is 3 or 5 usecs depending on - * phy, thus we'll offset RTC by 2 full ticks (61 usecs) and then compensate - * using TIMER0 with 1 usec precision. - */ - - cputime -= 2; - rem_usecs += 61; - if (tx) { - rem_usecs -= BLE_PHY_T_TXENFAST; - rem_usecs -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; - } else { - rem_usecs -= BLE_PHY_T_RXENFAST; - } - - /* - * rem_usecs will be no more than 2 ticks, but if it is more than single - * tick then we should better count one more low-power tick rather than - * 30 high-power usecs. Also make sure we don't set TIMER0 CC to 0 as the - * compare won't occur. - */ - - if (rem_usecs > 30) { - cputime++; - rem_usecs -= 30; - } - - /* - * Can we set the RTC compare to start TIMER0? We can do it if: - * a) Current compare value is not N+1 or N+2 ticks from current - * counter. - * b) The value we want to set is not at least N+2 from current - * counter. - * - * NOTE: since the counter can tick 1 while we do these calculations we - * need to account for it. - */ - next_cc = cputime & 0xffffff; - cur_cc = NRF_RTC0->CC[0]; - cntr = NRF_RTC0->COUNTER; - - delta = (cur_cc - cntr) & 0xffffff; - if ((delta <= 3) && (delta != 0)) { - return -1; - } - delta = (next_cc - cntr) & 0xffffff; - if ((delta & 0x800000) || (delta < 3)) { - return -1; - } - - /* Clear and set TIMER0 to fire off at proper time */ - NRF_TIMER0->TASKS_CLEAR = 1; - NRF_TIMER0->CC[0] = rem_usecs; - NRF_TIMER0->EVENTS_COMPARE[0] = 0; - - /* Set RTC compare to start TIMER0 */ - NRF_RTC0->EVENTS_COMPARE[0] = 0; - NRF_RTC0->CC[0] = next_cc; - NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; - - /* Enable PPI */ - NRF_PPI->CHENSET = PPI_CHEN_CH31_Msk; - - /* Store the cputime at which we set the RTC */ - g_ble_phy_data.phy_start_cputime = cputime; - - return 0; -} - -static int -ble_phy_set_start_now(void) -{ - os_sr_t sr; - uint32_t now; - - OS_ENTER_CRITICAL(sr); - - /* - * Set TIMER0 to fire immediately. We can't set CC to 0 as compare will not - * occur in such case. - */ - NRF_TIMER0->TASKS_CLEAR = 1; - NRF_TIMER0->CC[0] = 1; - NRF_TIMER0->EVENTS_COMPARE[0] = 0; - - /* - * Set RTC compare to start TIMER0. We need to set it to at least N+2 ticks - * from current value to guarantee triggering compare event, but let's set - * it to N+3 to account for possible extra tick on RTC0 during these - * operations. - */ - now = os_cputime_get32(); - NRF_RTC0->EVENTS_COMPARE[0] = 0; - NRF_RTC0->CC[0] = now + 3; - NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; - - /* Enable PPI */ - NRF_PPI->CHENSET = PPI_CHEN_CH31_Msk; - - /* - * Store the cputime at which we set the RTC - * - * XXX Compare event may be triggered on previous CC value (if it was set to - * less than N+2) so in rare cases actual start time may be 2 ticks earlier - * than what we expect. Since this is only used on RX, it may cause AUX scan - * to be scheduled 1 or 2 ticks too late so we'll miss it - it's acceptable - * for now. - */ - g_ble_phy_data.phy_start_cputime = now + 3; - - OS_EXIT_CRITICAL(sr); - - return 0; -} - -/** - * Function is used to set PPI so that we can time out waiting for a reception - * to occur. This happens for two reasons: we have sent a packet and we are - * waiting for a respons (txrx should be set to ENABLE_TXRX) or we are - * starting a connection event and we are a slave and we are waiting for the - * master to send us a packet (txrx should be set to ENABLE_RX). - * - * NOTE: when waiting for a txrx turn-around, wfr_usecs is not used as there - * is no additional time to wait; we know when we should receive the address of - * the received frame. - * - * @param txrx Flag denoting if this wfr is a txrx turn-around or not. - * @param tx_phy_mode phy mode for last TX (only valid for TX->RX) - * @param wfr_usecs Amount of usecs to wait. - */ -void -ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) -{ - uint32_t end_time; - uint8_t phy; - - phy = g_ble_phy_data.phy_cur_phy_mode; - - if (txrx == BLE_PHY_WFR_ENABLE_TXRX) { - /* RX shall start exactly T_IFS after TX end captured in CC[2] */ - end_time = NRF_TIMER0->CC[2] + BLE_LL_IFS; - /* Adjust for delay between EVENT_END and actual TX end time */ - end_time += g_ble_phy_t_txenddelay[tx_phy_mode]; - /* Wait a bit longer due to allowed active clock accuracy */ - end_time += 2; - /* - * It's possible that we'll capture PDU start time at the end of timer - * cycle and since wfr expires at the beginning of calculated timer - * cycle it can be almost 1 usec too early. Let's compensate for this - * by waiting 1 usec more. - */ - end_time += 1; -#if MYNEWT_VAL(BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN) > 0 - if ((phy == BLE_PHY_MODE_CODED_125KBPS) || - (phy == BLE_PHY_MODE_CODED_500KBPS)) { - /* - * Some controllers exceed T_IFS when transmitting on coded phy - * so let's wait a bit longer to be able to talk to them if this - * workaround is enabled. - */ - end_time += MYNEWT_VAL(BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN); - } -#endif - } else { - /* - * RX shall start no later than wfr_usecs after RX enabled. - * CC[0] is the time of RXEN so adjust for radio ram-up. - * Do not add jitter since this is already covered by LL. - */ - end_time = NRF_TIMER0->CC[0] + BLE_PHY_T_RXENFAST + wfr_usecs; - } - - /* - * Note: on LE Coded EVENT_ADDRESS is fired after TERM1 is received, so - * we are actually calculating relative to start of packet payload - * which is fine. - */ - - /* Adjust for receiving access address since this triggers EVENT_ADDRESS */ - end_time += ble_phy_mode_pdu_start_off(phy); - /* Adjust for delay between actual access address RX and EVENT_ADDRESS */ - end_time += g_ble_phy_t_rxaddrdelay[phy]; - - /* wfr_secs is the time from rxen until timeout */ - NRF_TIMER0->CC[3] = end_time; - NRF_TIMER0->EVENTS_COMPARE[3] = 0; - - /* Enable wait for response PPI */ - NRF_PPI->CHENSET = (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk); - - /* Enable the disabled interrupt so we time out on events compare */ - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; - - /* - * It may happen that if CPU is halted for a brief moment (e.g. during flash - * erase or write), TIMER0 already counted past CC[3] and thus wfr will not - * fire as expected. In case this happened, let's just disable PPIs for wfr - * and trigger wfr manually (i.e. disable radio). - * - * Note that the same applies to RX start time set in CC[0] but since it - * should fire earlier than wfr, fixing wfr is enough. - * - * CC[1] is only used as a reference on RX start, we do not need it here so - * it can be used to read TIMER0 counter. - */ - NRF_TIMER0->TASKS_CAPTURE[1] = 1; - if (NRF_TIMER0->CC[1] > NRF_TIMER0->CC[3]) { - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk; - NRF_RADIO->TASKS_DISABLE = 1; - } -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -static uint32_t -ble_phy_get_ccm_datarate(void) -{ -#if BLE_LL_BT5_PHY_SUPPORTED - switch (g_ble_phy_data.phy_cur_phy_mode) { - case BLE_PHY_MODE_1M: - return CCM_MODE_DATARATE_1Mbit << CCM_MODE_DATARATE_Pos; - case BLE_PHY_MODE_2M: - return CCM_MODE_DATARATE_2Mbit << CCM_MODE_DATARATE_Pos; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case BLE_PHY_MODE_CODED_125KBPS: - return CCM_MODE_DATARATE_125Kbps << CCM_MODE_DATARATE_Pos; - case BLE_PHY_MODE_CODED_500KBPS: - return CCM_MODE_DATARATE_500Kbps << CCM_MODE_DATARATE_Pos; -#endif - } - - assert(0); - return 0; -#else - return CCM_MODE_DATARATE_1Mbit << CCM_MODE_DATARATE_Pos; -#endif -} -#endif - -/** - * Setup transceiver for receive. - */ -static void -ble_phy_rx_xcvr_setup(void) -{ - uint8_t *dptr; - - dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; - dptr += 3; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (g_ble_phy_data.phy_encrypted) { - NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM->OUTPTR = (uint32_t)dptr; - NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; - NRF_CCM->MODE = CCM_MODE_LENGTH_Msk | CCM_MODE_MODE_Decryption | - ble_phy_get_ccm_datarate(); - NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data; - NRF_CCM->SHORTS = 0; - NRF_CCM->EVENTS_ERROR = 0; - NRF_CCM->EVENTS_ENDCRYPT = 0; - NRF_CCM->TASKS_KSGEN = 1; - NRF_PPI->CHENSET = PPI_CHEN_CH25_Msk; - } else { - NRF_RADIO->PACKETPTR = (uint32_t)dptr; - } -#else - NRF_RADIO->PACKETPTR = (uint32_t)dptr; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (g_ble_phy_data.phy_privacy) { - NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled; - NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; - NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch; - NRF_AAR->EVENTS_END = 0; - NRF_AAR->EVENTS_RESOLVED = 0; - NRF_AAR->EVENTS_NOTRESOLVED = 0; - } else { - if (g_ble_phy_data.phy_encrypted == 0) { - NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled; - } - } -#endif - - /* Turn off trigger TXEN on output compare match and AAR on bcmatch */ - NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk | PPI_CHEN_CH23_Msk; - - /* Reset the rx started flag. Used for the wait for response */ - g_ble_phy_data.phy_rx_started = 0; - g_ble_phy_data.phy_state = BLE_PHY_STATE_RX; - -#if BLE_LL_BT5_PHY_SUPPORTED - /* - * On Coded PHY there are CI and TERM1 fields before PDU starts so we need - * to take this into account when setting up BCC. - */ - if (g_ble_phy_data.phy_cur_phy_mode == BLE_PHY_MODE_CODED_125KBPS || - g_ble_phy_data.phy_cur_phy_mode == BLE_PHY_MODE_CODED_500KBPS) { - g_ble_phy_data.phy_bcc_offset = 5; - } else { - g_ble_phy_data.phy_bcc_offset = 0; - } -#else - g_ble_phy_data.phy_bcc_offset = 0; -#endif - - /* I want to know when 1st byte received (after address) */ - NRF_RADIO->BCC = 8 + g_ble_phy_data.phy_bcc_offset; /* in bits */ - NRF_RADIO->EVENTS_ADDRESS = 0; - NRF_RADIO->EVENTS_DEVMATCH = 0; - NRF_RADIO->EVENTS_BCMATCH = 0; - NRF_RADIO->EVENTS_RSSIEND = 0; - NRF_RADIO->EVENTS_CRCOK = 0; - NRF_RADIO->SHORTS = RADIO_SHORTS_END_DISABLE_Msk | - RADIO_SHORTS_READY_START_Msk | - RADIO_SHORTS_ADDRESS_BCSTART_Msk | - RADIO_SHORTS_ADDRESS_RSSISTART_Msk | - RADIO_SHORTS_DISABLED_RSSISTOP_Msk; - - NRF_RADIO->INTENSET = RADIO_INTENSET_ADDRESS_Msk; -} - -/** - * Called from interrupt context when the transmit ends - * - */ -static void -ble_phy_tx_end_isr(void) -{ - uint8_t tx_phy_mode; - uint8_t was_encrypted; - uint8_t transition; - uint32_t rx_time; - uint32_t wfr_time; - - /* Store PHY on which we've just transmitted smth */ - tx_phy_mode = g_ble_phy_data.phy_cur_phy_mode; - - /* If this transmission was encrypted we need to remember it */ - was_encrypted = g_ble_phy_data.phy_encrypted; - (void)was_encrypted; - - /* Better be in TX state! */ - assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX); - - /* Clear events and clear interrupt on disabled event */ - NRF_RADIO->EVENTS_DISABLED = 0; - NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk; - NRF_RADIO->EVENTS_END = 0; - wfr_time = NRF_RADIO->SHORTS; - (void)wfr_time; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - /* - * XXX: not sure what to do. We had a HW error during transmission. - * For now I just count a stat but continue on like all is good. - */ - if (was_encrypted) { - if (NRF_CCM->EVENTS_ERROR) { - STATS_INC(ble_phy_stats, tx_hw_err); - NRF_CCM->EVENTS_ERROR = 0; - } - } -#endif - - /* Call transmit end callback */ - if (g_ble_phy_data.txend_cb) { - g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg); - } - - transition = g_ble_phy_data.phy_transition; - if (transition == BLE_PHY_TRANSITION_TX_RX) { - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_apply(g_ble_phy_data.phy_rx_phy_mode); -#endif - - /* Packet pointer needs to be reset. */ - ble_phy_rx_xcvr_setup(); - - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_TXRX, tx_phy_mode, 0); - - /* Schedule RX exactly T_IFS after TX end captured in CC[2] */ - rx_time = NRF_TIMER0->CC[2] + BLE_LL_IFS; - /* Adjust for delay between EVENT_END and actual TX end time */ - rx_time += g_ble_phy_t_txenddelay[tx_phy_mode]; - /* Adjust for radio ramp-up */ - rx_time -= BLE_PHY_T_RXENFAST; - /* Start listening a bit earlier due to allowed active clock accuracy */ - rx_time -= 2; - - NRF_TIMER0->CC[0] = rx_time; - NRF_TIMER0->EVENTS_COMPARE[0] = 0; - NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk; - } else { - /* - * XXX: not sure we need to stop the timer here all the time. Or that - * it should be stopped here. - */ - NRF_TIMER0->TASKS_STOP = 1; - NRF_TIMER0->TASKS_SHUTDOWN = 1; - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | - PPI_CHEN_CH20_Msk | PPI_CHEN_CH31_Msk; - assert(transition == BLE_PHY_TRANSITION_NONE); - } -} - -static inline uint8_t -ble_phy_get_cur_rx_phy_mode(void) -{ - uint8_t phy; - - phy = g_ble_phy_data.phy_cur_phy_mode; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - /* - * For Coded PHY mode can be set to either codings since actual coding is - * set in packet header. However, here we need actual coding of received - * packet as this determines pipeline delays so need to figure this out - * using CI field. - */ - if ((phy == BLE_PHY_MODE_CODED_125KBPS) || - (phy == BLE_PHY_MODE_CODED_500KBPS)) { - phy = NRF_RADIO->PDUSTAT & RADIO_PDUSTAT_CISTAT_Msk ? - BLE_PHY_MODE_CODED_500KBPS : - BLE_PHY_MODE_CODED_125KBPS; - } -#endif - - return phy; -} - -static void -ble_phy_rx_end_isr(void) -{ - int rc; - uint8_t *dptr; - uint8_t crcok; - uint32_t tx_time; - struct ble_mbuf_hdr *ble_hdr; - - /* Clear events and clear interrupt */ - NRF_RADIO->EVENTS_END = 0; - NRF_RADIO->INTENCLR = RADIO_INTENCLR_END_Msk; - - /* Disable automatic RXEN */ - NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; - - /* Set RSSI and CRC status flag in header */ - ble_hdr = &g_ble_phy_data.rxhdr; - assert(NRF_RADIO->EVENTS_RSSIEND != 0); - ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO->RSSISAMPLE) + - g_ble_phy_data.rx_pwr_compensation; - - dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; - dptr += 3; - - /* Count PHY crc errors and valid packets */ - crcok = NRF_RADIO->EVENTS_CRCOK; - if (!crcok) { - STATS_INC(ble_phy_stats, rx_crc_err); - } else { - STATS_INC(ble_phy_stats, rx_valid); - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (g_ble_phy_data.phy_encrypted) { - /* Only set MIC failure flag if frame is not zero length */ - if ((dptr[1] != 0) && (NRF_CCM->MICSTATUS == 0)) { - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE; - } - - /* - * XXX: not sure how to deal with this. This should not - * be a MIC failure but we should not hand it up. I guess - * this is just some form of rx error and that is how we - * handle it? For now, just set CRC error flags - */ - if (NRF_CCM->EVENTS_ERROR) { - STATS_INC(ble_phy_stats, rx_hw_err); - ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK; - } - - /* - * XXX: This is a total hack work-around for now but I dont - * know what else to do. If ENDCRYPT is not set and we are - * encrypted we need to not trust this frame and drop it. - */ - if (NRF_CCM->EVENTS_ENDCRYPT == 0) { - STATS_INC(ble_phy_stats, rx_hw_err); - ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK; - } - } -#endif - } - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_apply(g_ble_phy_data.phy_tx_phy_mode); -#endif - - /* - * Let's schedule TX now and we will just cancel it after processing RXed - * packet if we don't need TX. - * - * We need this to initiate connection in case AUX_CONNECT_REQ was sent on - * LE Coded S8. In this case the time we process RXed packet is roughly the - * same as the limit when we need to have TX scheduled (i.e. TIMER0 and PPI - * armed) so we may simply miss the slot and set the timer in the past. - * - * When TX is scheduled in advance, we may event process packet a bit longer - * during radio ramp-up - this gives us extra 40 usecs which is more than - * enough. - */ - - /* Schedule TX exactly T_IFS after RX end captured in CC[2] */ - tx_time = NRF_TIMER0->CC[2] + BLE_LL_IFS; - /* Adjust for delay between actual RX end time and EVENT_END */ - tx_time -= g_ble_phy_t_rxenddelay[ble_hdr->rxinfo.phy_mode]; - /* Adjust for radio ramp-up */ - tx_time -= BLE_PHY_T_TXENFAST; - /* Adjust for delay between EVENT_READY and actual TX start time */ - tx_time -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; - - NRF_TIMER0->CC[0] = tx_time; - NRF_TIMER0->EVENTS_COMPARE[0] = 0; - NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk; - - /* - * XXX: Hack warning! - * - * It may happen (during flash erase) that CPU is stopped for a moment and - * TIMER0 already counted past CC[0]. In such case we will be stuck waiting - * for TX to start since EVENTS_COMPARE[0] will not happen any time soon. - * For now let's set a flag denoting that we are late in RX-TX transition so - * ble_phy_tx() will fail - this allows everything to cleanup nicely without - * the need for extra handling in many places. - * - * Note: CC[3] is used only for wfr which we do not need here. - */ - NRF_TIMER0->TASKS_CAPTURE[3] = 1; - if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) { - NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk; - g_ble_phy_data.phy_transition_late = 1; - } - - /* - * XXX: This is a horrible ugly hack to deal with the RAM S1 byte - * that is not sent over the air but is present here. Simply move the - * data pointer to deal with it. Fix this later. - */ - dptr[2] = dptr[1]; - dptr[1] = dptr[0]; - rc = ble_ll_rx_end(dptr + 1, ble_hdr); - if (rc < 0) { - ble_phy_disable(); - } -} - -static bool -ble_phy_rx_start_isr(void) -{ - int rc; - uint32_t state; - uint32_t usecs; - uint32_t pdu_usecs; - uint32_t ticks; - struct ble_mbuf_hdr *ble_hdr; - uint8_t *dptr; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - int adva_offset; -#endif - - dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; - - /* Clear events and clear interrupt */ - NRF_RADIO->EVENTS_ADDRESS = 0; - - /* Clear wfr timer channels and DISABLED interrupt */ - NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk | RADIO_INTENCLR_ADDRESS_Msk; - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk; - - /* Initialize the ble mbuf header */ - ble_hdr = &g_ble_phy_data.rxhdr; - ble_hdr->rxinfo.flags = ble_ll_state_get(); - ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan; - ble_hdr->rxinfo.handle = 0; - ble_hdr->rxinfo.phy = ble_phy_get_cur_phy(); - ble_hdr->rxinfo.phy_mode = ble_phy_get_cur_rx_phy_mode(); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_hdr->rxinfo.user_data = NULL; -#endif - - /* - * Calculate accurate packets start time (with remainder) - * - * We may start receiving packet somewhere during preamble in which case - * it is possible that actual transmission started before TIMER0 was - * running - need to take this into account. - */ - ble_hdr->beg_cputime = g_ble_phy_data.phy_start_cputime; - - usecs = NRF_TIMER0->CC[1]; - pdu_usecs = ble_phy_mode_pdu_start_off(ble_hdr->rxinfo.phy_mode) + - g_ble_phy_t_rxaddrdelay[ble_hdr->rxinfo.phy_mode]; - if (usecs < pdu_usecs) { - g_ble_phy_data.phy_start_cputime--; - usecs += 30; - } - usecs -= pdu_usecs; - - ticks = os_cputime_usecs_to_ticks(usecs); - usecs -= os_cputime_ticks_to_usecs(ticks); - if (usecs == 31) { - usecs = 0; - ++ticks; - } - - ble_hdr->beg_cputime += ticks; - ble_hdr->rem_usecs = usecs; - - /* XXX: I wonder if we always have the 1st byte. If we need to wait for - * rx chain delay, it could be 18 usecs from address interrupt. The - nrf52 may be able to get here early. */ - /* Wait to get 1st byte of frame */ - while (1) { - state = NRF_RADIO->STATE; - if (NRF_RADIO->EVENTS_BCMATCH != 0) { - break; - } - - /* - * If state is disabled, we should have the BCMATCH. If not, - * something is wrong! - */ - if (state == RADIO_STATE_STATE_Disabled) { - NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - NRF_RADIO->SHORTS = 0; - return false; - } - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* - * If privacy is enabled and received PDU has TxAdd bit set (i.e. random - * address) we try to resolve address using AAR. - */ - if (g_ble_phy_data.phy_privacy && (dptr[3] & 0x40)) { - /* - * AdvA is located at 4th octet in RX buffer (after S0, length an S1 - * fields). In case of extended advertising PDU we need to add 2 more - * octets for extended header. - */ - adva_offset = (dptr[3] & 0x0f) == 0x07 ? 2 : 0; - NRF_AAR->ADDRPTR = (uint32_t)(dptr + 3 + adva_offset); - - /* Trigger AAR after last bit of AdvA is received */ - NRF_RADIO->EVENTS_BCMATCH = 0; - NRF_PPI->CHENSET = PPI_CHEN_CH23_Msk; - NRF_RADIO->BCC = (BLE_LL_PDU_HDR_LEN + adva_offset + BLE_DEV_ADDR_LEN) * 8 + - g_ble_phy_data.phy_bcc_offset; - } -#endif - - /* Call Link Layer receive start function */ - rc = ble_ll_rx_start(dptr + 3, - g_ble_phy_data.phy_chan, - &g_ble_phy_data.rxhdr); - if (rc >= 0) { - /* Set rx started flag and enable rx end ISR */ - g_ble_phy_data.phy_rx_started = 1; - NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk; - } else { - /* Disable PHY */ - ble_phy_disable(); - STATS_INC(ble_phy_stats, rx_aborts); - } - - /* Count rx starts */ - STATS_INC(ble_phy_stats, rx_starts); - - return true; -} - -static void -ble_phy_isr(void) -{ - uint32_t irq_en; - - os_trace_isr_enter(); - - /* Read irq register to determine which interrupts are enabled */ - irq_en = NRF_RADIO->INTENCLR; - - /* - * NOTE: order of checking is important! Possible, if things get delayed, - * we have both an ADDRESS and DISABLED interrupt in rx state. If we get - * an address, we disable the DISABLED interrupt. - */ - - /* We get this if we have started to receive a frame */ - if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO->EVENTS_ADDRESS) { - /* - * wfr timer is calculated to expire at the exact time we should start - * receiving a packet (with 1 usec precision) so it is possible it will - * fire at the same time as EVENT_ADDRESS. If this happens, radio will - * be disabled while we are waiting for EVENT_BCCMATCH after 1st byte - * of payload is received and ble_phy_rx_start_isr() will fail. In this - * case we should not clear DISABLED irq mask so it will be handled as - * regular radio disabled event below. In other case radio was disabled - * on purpose and there's nothing more to handle so we can clear mask. - */ - if (ble_phy_rx_start_isr()) { - irq_en &= ~RADIO_INTENCLR_DISABLED_Msk; - } - } - - /* Check for disabled event. This only happens for transmits now */ - if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) { - if (g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) { - NRF_RADIO->EVENTS_DISABLED = 0; - ble_ll_wfr_timer_exp(NULL); - } else if (g_ble_phy_data.phy_state == BLE_PHY_STATE_IDLE) { - assert(0); - } else { - ble_phy_tx_end_isr(); - } - } - - /* Receive packet end (we dont enable this for transmit) */ - if ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO->EVENTS_END) { - ble_phy_rx_end_isr(); - } - - g_ble_phy_data.phy_transition_late = 0; - - /* Ensures IRQ is cleared */ - irq_en = NRF_RADIO->SHORTS; - - /* Count # of interrupts */ - STATS_INC(ble_phy_stats, phy_isrs); - - os_trace_isr_exit(); -} - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 || \ - MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \ - MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 -static inline void -ble_phy_dbg_time_setup_gpiote(int index, int pin) -{ - NRF_GPIO_Type *port; - -#if NRF52840_XXAA - port = pin > 31 ? NRF_P1 : NRF_P0; - pin &= 0x1f; -#else - port = NRF_P0; -#endif - - /* Configure GPIO directly to avoid dependency to hal_gpio (for porting) */ - port->DIRSET = (1 << pin); - port->OUTCLR = (1 << pin); - - NRF_GPIOTE->CONFIG[index] = - (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | - ((pin & 0x1F) << GPIOTE_CONFIG_PSEL_Pos) | -#if NRF52840_XXAA - ((port == NRF_P1) << GPIOTE_CONFIG_PORT_Pos); -#else - 0; -#endif -} -#endif - -static void -ble_phy_dbg_time_setup(void) -{ - int gpiote_idx __attribute__((unused)) = 8; - - /* - * We setup GPIOTE starting from last configuration index to minimize risk - * of conflict with GPIO setup via hal. It's not great solution, but since - * this is just debugging code we can live with this. - */ - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 - ble_phy_dbg_time_setup_gpiote(--gpiote_idx, - MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); - - NRF_PPI->CH[17].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY); - NRF_PPI->CH[17].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); - NRF_PPI->CHENSET = PPI_CHEN_CH17_Msk; - - /* CH[20] and PPI CH[21] are on to trigger TASKS_TXEN or TASKS_RXEN */ - NRF_PPI->FORK[20].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]); - NRF_PPI->FORK[21].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]); -#endif - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 - ble_phy_dbg_time_setup_gpiote(--gpiote_idx, - MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); - - /* CH[26] and CH[27] are always on for EVENT_ADDRESS and EVENT_END */ - NRF_PPI->FORK[26].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]); - NRF_PPI->FORK[27].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); -#endif - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 - ble_phy_dbg_time_setup_gpiote(--gpiote_idx, - MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); - -#if NRF52840_XXAA - NRF_PPI->CH[18].EEP = (uint32_t)&(NRF_RADIO->EVENTS_RXREADY); -#else - NRF_PPI->CH[18].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY); -#endif - NRF_PPI->CH[18].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]); - NRF_PPI->CH[19].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED); - NRF_PPI->CH[19].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); - NRF_PPI->CHENSET = PPI_CHEN_CH18_Msk | PPI_CHEN_CH19_Msk; - - /* CH[4] and CH[5] are always on for wfr */ - NRF_PPI->FORK[4].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); - NRF_PPI->FORK[5].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); -#endif -} - -/** - * ble phy init - * - * Initialize the PHY. - * - * @return int 0: success; PHY error code otherwise - */ -int -ble_phy_init(void) -{ - int rc; - - /* Default phy to use is 1M */ - g_ble_phy_data.phy_cur_phy_mode = BLE_PHY_MODE_1M; - g_ble_phy_data.phy_tx_phy_mode = BLE_PHY_MODE_1M; - g_ble_phy_data.phy_rx_phy_mode = BLE_PHY_MODE_1M; - - g_ble_phy_data.rx_pwr_compensation = 0; - - /* Set phy channel to an invalid channel so first set channel works */ - g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS; - - /* Toggle peripheral power to reset (just in case) */ - NRF_RADIO->POWER = 0; - NRF_RADIO->POWER = 1; - - /* Disable all interrupts */ - NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - - /* Set configuration registers */ - NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit; - NRF_RADIO->PCNF0 = NRF_PCNF0; - - /* XXX: should maxlen be 251 for encryption? */ - NRF_RADIO->PCNF1 = NRF_MAXLEN | - (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos) | - (NRF_BALEN << RADIO_PCNF1_BALEN_Pos) | - RADIO_PCNF1_WHITEEN_Msk; - - /* Enable radio fast ramp-up */ - NRF_RADIO->MODECNF0 |= (RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos) & - RADIO_MODECNF0_RU_Msk; - - /* Set logical address 1 for TX and RX */ - NRF_RADIO->TXADDRESS = 0; - NRF_RADIO->RXADDRESSES = (1 << 0); - - /* Configure the CRC registers */ - NRF_RADIO->CRCCNF = (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos) | RADIO_CRCCNF_LEN_Three; - - /* Configure BLE poly */ - NRF_RADIO->CRCPOLY = 0x0000065B; - - /* Configure IFS */ - NRF_RADIO->TIFS = BLE_LL_IFS; - - /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */ - NRF_PPI->CHENSET = PPI_CHEN_CH26_Msk | PPI_CHEN_CH27_Msk; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - NRF_CCM->INTENCLR = 0xffffffff; - NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; - NRF_CCM->EVENTS_ERROR = 0; - memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad)); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - g_ble_phy_data.phy_aar_scratch = 0; - NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; - NRF_AAR->INTENCLR = 0xffffffff; - NRF_AAR->EVENTS_END = 0; - NRF_AAR->EVENTS_RESOLVED = 0; - NRF_AAR->EVENTS_NOTRESOLVED = 0; - NRF_AAR->NIRK = 0; -#endif - - /* TIMER0 setup for PHY when using RTC */ - NRF_TIMER0->TASKS_STOP = 1; - NRF_TIMER0->TASKS_SHUTDOWN = 1; - NRF_TIMER0->BITMODE = 3; /* 32-bit timer */ - NRF_TIMER0->MODE = 0; /* Timer mode */ - NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */ - - /* - * PPI setup. - * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used - * to cancel the wait for response timer. - * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait - * for response timer. - */ - NRF_PPI->CH[4].EEP = (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS); - NRF_PPI->CH[4].TEP = (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3]); - NRF_PPI->CH[5].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]); - NRF_PPI->CH[5].TEP = (uint32_t)&(NRF_RADIO->TASKS_DISABLE); - - /* Set isr in vector table and enable interrupt */ -#ifndef RIOT_VERSION - NVIC_SetPriority(RADIO_IRQn, 0); -#endif -#if MYNEWT - NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr); -#else - ble_npl_hw_set_isr(RADIO_IRQn, ble_phy_isr); -#endif - NVIC_EnableIRQ(RADIO_IRQn); - - /* Register phy statistics */ - if (!g_ble_phy_data.phy_stats_initialized) { - rc = stats_init_and_reg(STATS_HDR(ble_phy_stats), - STATS_SIZE_INIT_PARMS(ble_phy_stats, - STATS_SIZE_32), - STATS_NAME_INIT_PARMS(ble_phy_stats), - "ble_phy"); - assert(rc == 0); - - g_ble_phy_data.phy_stats_initialized = 1; - } - - ble_phy_dbg_time_setup(); - - return 0; -} - -/** - * Puts the phy into receive mode. - * - * @return int 0: success; BLE Phy error code otherwise - */ -int -ble_phy_rx(void) -{ - /* - * Check radio state. - * - * In case radio is now disabling we'll wait for it to finish, but if for - * any reason it's just in idle state we proceed with RX as usual since - * nRF52 radio can ramp-up from idle state as well. - * - * Note that TX and RX states values are the same except for 3rd bit so we - * can make a shortcut here when checking for idle state. - */ - nrf_wait_disabled(); - if ((NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) && - ((NRF_RADIO->STATE & 0x07) != RADIO_STATE_STATE_RxIdle)) { - ble_phy_disable(); - STATS_INC(ble_phy_stats, radio_state_errs); - return BLE_PHY_ERR_RADIO_STATE; - } - - /* Make sure all interrupts are disabled */ - NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - - /* Clear events prior to enabling receive */ - NRF_RADIO->EVENTS_END = 0; - NRF_RADIO->EVENTS_DISABLED = 0; - - /* Setup for rx */ - ble_phy_rx_xcvr_setup(); - - /* PPI to start radio automatically shall be set here */ - assert(NRF_PPI->CHEN & PPI_CHEN_CH21_Msk); - - return 0; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/** - * Called to enable encryption at the PHY. Note that this state will persist - * in the PHY; in other words, if you call this function you have to call - * disable so that future PHY transmits/receives will not be encrypted. - * - * @param pkt_counter - * @param iv - * @param key - * @param is_master - */ -void -ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_master) -{ - memcpy(g_nrf_ccm_data.key, key, 16); - g_nrf_ccm_data.pkt_counter = pkt_counter; - memcpy(g_nrf_ccm_data.iv, iv, 8); - g_nrf_ccm_data.dir_bit = is_master; - g_ble_phy_data.phy_encrypted = 1; - /* Enable the module (AAR cannot be on while CCM on) */ - NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled; - NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled; -} - -void -ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir) -{ - g_nrf_ccm_data.pkt_counter = pkt_counter; - g_nrf_ccm_data.dir_bit = dir; -} - -void -ble_phy_encrypt_disable(void) -{ - NRF_PPI->CHENCLR = PPI_CHEN_CH25_Msk; - NRF_CCM->TASKS_STOP = 1; - NRF_CCM->EVENTS_ERROR = 0; - NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Disabled; - - g_ble_phy_data.phy_encrypted = 0; -} -#endif - -void -ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg) -{ - /* Set transmit end callback and arg */ - g_ble_phy_data.txend_cb = txend_cb; - g_ble_phy_data.txend_arg = arg; -} - -/** - * Called to set the start time of a transmission. - * - * This function is called to set the start time when we are not going from - * rx to tx automatically. - * - * NOTE: care must be taken when calling this function. The channel should - * already be set. - * - * @param cputime This is the tick at which the 1st bit of the preamble - * should be transmitted - * @param rem_usecs This is used only when the underlying timing uses a 32.768 - * kHz crystal. It is the # of usecs from the cputime tick - * at which the first bit of the preamble should be - * transmitted. - * @return int - */ -int -ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) -{ - int rc; - - ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_TX, cputime, rem_usecs); - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_apply(g_ble_phy_data.phy_tx_phy_mode); -#endif - - /* XXX: This should not be necessary, but paranoia is good! */ - /* Clear timer0 compare to RXEN since we are transmitting */ - NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; - - if (ble_phy_set_start_time(cputime, rem_usecs, true) != 0) { - STATS_INC(ble_phy_stats, tx_late); - ble_phy_disable(); - rc = BLE_PHY_ERR_TX_LATE; - } else { - /* Enable PPI to automatically start TXEN */ - NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk; - rc = 0; - } - return rc; -} - -/** - * Called to set the start time of a reception - * - * This function acts a bit differently than transmit. If we are late getting - * here we will still attempt to receive. - * - * NOTE: care must be taken when calling this function. The channel should - * already be set. - * - * @param cputime - * - * @return int - */ -int -ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) -{ - bool late = false; - int rc = 0; - - ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_RX, cputime, rem_usecs); - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_apply(g_ble_phy_data.phy_rx_phy_mode); -#endif - - /* XXX: This should not be necessary, but paranoia is good! */ - /* Clear timer0 compare to TXEN since we are transmitting */ - NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk; - - if (ble_phy_set_start_time(cputime, rem_usecs, false) != 0) { - STATS_INC(ble_phy_stats, rx_late); - - /* We're late so let's just try to start RX as soon as possible */ - ble_phy_set_start_now(); - - late = true; - } - - /* Enable PPI to automatically start RXEN */ - NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk; - - /* Start rx */ - rc = ble_phy_rx(); - - /* - * If we enabled receiver but were late, let's return proper error code so - * caller can handle this. - */ - if (!rc && late) { - rc = BLE_PHY_ERR_RX_LATE; - } - - return rc; -} - -int -ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) -{ - int rc; - uint8_t *dptr; - uint8_t *pktptr; - uint8_t payload_len; - uint8_t hdr_byte; - uint32_t state; - uint32_t shortcuts; - - if (g_ble_phy_data.phy_transition_late) { - ble_phy_disable(); - STATS_INC(ble_phy_stats, tx_late); - return BLE_PHY_ERR_TX_LATE; - } - - /* - * This check is to make sure that the radio is not in a state where - * it is moving to disabled state. If so, let it get there. - */ - nrf_wait_disabled(); - - /* - * XXX: Although we may not have to do this here, I clear all the PPI - * that should not be used when transmitting. Some of them are only enabled - * if encryption and/or privacy is on, but I dont care. Better to be - * paranoid, and if you are going to clear one, might as well clear them - * all. - */ - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH23_Msk | - PPI_CHEN_CH25_Msk; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (g_ble_phy_data.phy_encrypted) { - dptr = (uint8_t *)&g_ble_phy_enc_buf[0]; - pktptr = (uint8_t *)&g_ble_phy_tx_buf[0]; - NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; - NRF_CCM->INPTR = (uint32_t)dptr; - NRF_CCM->OUTPTR = (uint32_t)pktptr; - NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; - NRF_CCM->EVENTS_ERROR = 0; - NRF_CCM->MODE = CCM_MODE_LENGTH_Msk | ble_phy_get_ccm_datarate(); - NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data; - } else { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; -#endif - dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; - pktptr = dptr; - } -#else - dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; - pktptr = dptr; -#endif - - /* Set PDU payload */ - payload_len = pducb(&dptr[3], pducb_arg, &hdr_byte); - - /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */ - dptr[0] = hdr_byte; - dptr[1] = payload_len; - dptr[2] = 0; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - /* Start key-stream generation and encryption (via short) */ - if (g_ble_phy_data.phy_encrypted) { - NRF_CCM->TASKS_KSGEN = 1; - } -#endif - - NRF_RADIO->PACKETPTR = (uint32_t)pktptr; - - /* Clear the ready, end and disabled events */ - NRF_RADIO->EVENTS_READY = 0; - NRF_RADIO->EVENTS_END = 0; - NRF_RADIO->EVENTS_DISABLED = 0; - - /* Enable shortcuts for transmit start/end. */ - shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk; - NRF_RADIO->SHORTS = shortcuts; - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; - - /* Set the PHY transition */ - g_ble_phy_data.phy_transition = end_trans; - - /* Set transmitted payload length */ - g_ble_phy_data.phy_tx_pyld_len = payload_len; - - /* If we already started transmitting, abort it! */ - state = NRF_RADIO->STATE; - if (state != RADIO_STATE_STATE_Tx) { - /* Set phy state to transmitting and count packet statistics */ - g_ble_phy_data.phy_state = BLE_PHY_STATE_TX; - STATS_INC(ble_phy_stats, tx_good); - STATS_INCN(ble_phy_stats, tx_bytes, payload_len + BLE_LL_PDU_HDR_LEN); - rc = BLE_ERR_SUCCESS; - } else { - ble_phy_disable(); - STATS_INC(ble_phy_stats, tx_late); - rc = BLE_PHY_ERR_RADIO_STATE; - } - - return rc; -} - -/** - * ble phy txpwr set - * - * Set the transmit output power (in dBm). - * - * NOTE: If the output power specified is within the BLE limits but outside - * the chip limits, we "rail" the power level so we dont exceed the min/max - * chip values. - * - * @param dbm Power output in dBm. - * - * @return int 0: success; anything else is an error - */ -int -ble_phy_txpwr_set(int dbm) -{ - /* "Rail" power level if outside supported range */ - dbm = ble_phy_txpower_round(dbm); - - NRF_RADIO->TXPOWER = dbm; - g_ble_phy_data.phy_txpwr_dbm = dbm; - - return 0; -} - -/** - * ble phy txpwr round - * - * Get the rounded transmit output power (in dBm). - * - * @param dbm Power output in dBm. - * - * @return int Rounded power in dBm - */ -int ble_phy_txpower_round(int dbm) -{ - /* TODO this should be per nRF52XXX */ - - /* "Rail" power level if outside supported range */ - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm; - } - - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; -} - -/** - * ble phy set access addr - * - * Set access address. - * - * @param access_addr Access address - * - * @return int 0: success; PHY error code otherwise - */ -static int -ble_phy_set_access_addr(uint32_t access_addr) -{ - NRF_RADIO->BASE0 = (access_addr << 8); - NRF_RADIO->PREFIX0 = (NRF_RADIO->PREFIX0 & 0xFFFFFF00) | (access_addr >> 24); - - g_ble_phy_data.phy_access_address = access_addr; - - ble_phy_apply_errata_102_106_107(); - - return 0; -} - -/** - * ble phy txpwr get - * - * Get the transmit power. - * - * @return int The current PHY transmit power, in dBm - */ -int -ble_phy_txpwr_get(void) -{ - return g_ble_phy_data.phy_txpwr_dbm; -} - -void -ble_phy_set_rx_pwr_compensation(int8_t compensation) -{ - g_ble_phy_data.rx_pwr_compensation = compensation; -} - -/** - * ble phy setchan - * - * Sets the logical frequency of the transceiver. The input parameter is the - * BLE channel index (0 to 39, inclusive). The NRF frequency register works like - * this: logical frequency = 2400 + FREQ (MHz). - * - * Thus, to get a logical frequency of 2402 MHz, you would program the - * FREQUENCY register to 2. - * - * @param chan This is the Data Channel Index or Advertising Channel index - * - * @return int 0: success; PHY error code otherwise - */ -int -ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) -{ - assert(chan < BLE_PHY_NUM_CHANS); - - /* Check for valid channel range */ - if (chan >= BLE_PHY_NUM_CHANS) { - return BLE_PHY_ERR_INV_PARAM; - } - - /* Set current access address */ - ble_phy_set_access_addr(access_addr); - - /* Configure crcinit */ - NRF_RADIO->CRCINIT = crcinit; - - /* Set the frequency and the data whitening initial value */ - g_ble_phy_data.phy_chan = chan; - NRF_RADIO->FREQUENCY = g_ble_phy_chan_freq[chan]; - NRF_RADIO->DATAWHITEIV = chan; - - return 0; -} - -/** - * Stop the timer used to count microseconds when using RTC for cputime - */ -static void -ble_phy_stop_usec_timer(void) -{ - NRF_TIMER0->TASKS_STOP = 1; - NRF_TIMER0->TASKS_SHUTDOWN = 1; - NRF_RTC0->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk; -} - -/** - * ble phy disable irq and ppi - * - * This routine is to be called when reception was stopped due to either a - * wait for response timeout or a packet being received and the phy is to be - * restarted in receive mode. Generally, the disable routine is called to stop - * the phy. - */ -static void -ble_phy_disable_irq_and_ppi(void) -{ - NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - NRF_RADIO->SHORTS = 0; - NRF_RADIO->TASKS_DISABLE = 1; - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH20_Msk | - PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk | - PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk; - NVIC_ClearPendingIRQ(RADIO_IRQn); - g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE; -} - -void -ble_phy_restart_rx(void) -{ - ble_phy_stop_usec_timer(); - ble_phy_disable_irq_and_ppi(); - - ble_phy_set_start_now(); - /* Enable PPI to automatically start RXEN */ - NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk; - - ble_phy_rx(); -} - -/** - * ble phy disable - * - * Disables the PHY. This should be called when an event is over. It stops - * the usec timer (if used), disables interrupts, disables the RADIO, disables - * PPI and sets state to idle. - */ -void -ble_phy_disable(void) -{ - ble_phy_trace_void(BLE_PHY_TRACE_ID_DISABLE); - - ble_phy_stop_usec_timer(); - ble_phy_disable_irq_and_ppi(); -} - -/* Gets the current access address */ -uint32_t ble_phy_access_addr_get(void) -{ - return g_ble_phy_data.phy_access_address; -} - -/** - * Return the phy state - * - * @return int The current PHY state. - */ -int -ble_phy_state_get(void) -{ - return g_ble_phy_data.phy_state; -} - -/** - * Called to see if a reception has started - * - * @return int - */ -int -ble_phy_rx_started(void) -{ - return g_ble_phy_data.phy_rx_started; -} - -/** - * Return the transceiver state - * - * @return int transceiver state. - */ -uint8_t -ble_phy_xcvr_state_get(void) -{ - uint32_t state; - state = NRF_RADIO->STATE; - return (uint8_t)state; -} - -/** - * Called to return the maximum data pdu payload length supported by the - * phy. For this chip, if encryption is enabled, the maximum payload is 27 - * bytes. - * - * @return uint8_t Maximum data channel PDU payload size supported - */ -uint8_t -ble_phy_max_data_pdu_pyld(void) -{ - return BLE_LL_DATA_PDU_MAX_PYLD; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -void -ble_phy_resolv_list_enable(void) -{ - NRF_AAR->NIRK = (uint32_t)g_nrf_num_irks; - g_ble_phy_data.phy_privacy = 1; -} - -void -ble_phy_resolv_list_disable(void) -{ - g_ble_phy_data.phy_privacy = 0; -} -#endif - -#if MYNEWT_VAL(BLE_LL_DTM) -void ble_phy_enable_dtm(void) -{ - /* When DTM is enabled we need to disable whitening as per - * Bluetooth v5.0 Vol 6. Part F. 4.1.1 - */ - NRF_RADIO->PCNF1 &= ~RADIO_PCNF1_WHITEEN_Msk; -} - -void ble_phy_disable_dtm(void) -{ - /* Enable whitening */ - NRF_RADIO->PCNF1 |= RADIO_PCNF1_WHITEEN_Msk; -} -#endif - -void -ble_phy_rfclk_enable(void) -{ -#if MYNEWT || ARDUINO - nrf52_clock_hfxo_request(); -#else - NRF_CLOCK->TASKS_HFCLKSTART = 1; -#endif -} - -void -ble_phy_rfclk_disable(void) -{ -#if MYNEWT || ARDUINO - nrf52_clock_hfxo_release(); -#else - NRF_CLOCK->TASKS_HFCLKSTOP = 1; -#endif -} - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf52/src/ble_phy_trace.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf52/src/ble_phy_trace.c deleted file mode 100644 index 84dbf4def..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/drivers/nrf52/src/ble_phy_trace.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#if defined(ARDUINO_ARCH_NRF5) && defined(NRF52_SERIES) - -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os_trace_api.h" - -#if MYNEWT_VAL(BLE_PHY_SYSVIEW) - -static os_trace_module_t g_ble_phy_trace_mod; -uint32_t ble_phy_trace_off; - -static void -ble_phy_trace_module_send_desc(void) -{ - os_trace_module_desc(&g_ble_phy_trace_mod, "0 phy_set_tx cputime=%u usecs=%u"); - os_trace_module_desc(&g_ble_phy_trace_mod, "1 phy_set_rx cputime=%u usecs=%u"); - os_trace_module_desc(&g_ble_phy_trace_mod, "2 phy_disable"); -} - -void -ble_phy_trace_init(void) -{ - ble_phy_trace_off = - os_trace_module_register(&g_ble_phy_trace_mod, "ble_phy", 3, - ble_phy_trace_module_send_desc); -} -#endif -#endif \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_att.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_att.h deleted file mode 100644 index ceca35179..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_att.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_ATT_ -#define H_BLE_ATT_ - -/** - * @brief Bluetooth Attribute Protocol (ATT) - * @defgroup bt_att Bluetooth Attribute Protocol (ATT) - * @ingroup bt_host - * @{ - */ - -#include "nimble/porting/nimble/include/os/queue.h" -#ifdef __cplusplus -extern "C" { -#endif - -struct os_mbuf; - -#define BLE_ATT_UUID_PRIMARY_SERVICE 0x2800 -#define BLE_ATT_UUID_SECONDARY_SERVICE 0x2801 -#define BLE_ATT_UUID_INCLUDE 0x2802 -#define BLE_ATT_UUID_CHARACTERISTIC 0x2803 - -#define BLE_ATT_ERR_INVALID_HANDLE 0x01 -#define BLE_ATT_ERR_READ_NOT_PERMITTED 0x02 -#define BLE_ATT_ERR_WRITE_NOT_PERMITTED 0x03 -#define BLE_ATT_ERR_INVALID_PDU 0x04 -#define BLE_ATT_ERR_INSUFFICIENT_AUTHEN 0x05 -#define BLE_ATT_ERR_REQ_NOT_SUPPORTED 0x06 -#define BLE_ATT_ERR_INVALID_OFFSET 0x07 -#define BLE_ATT_ERR_INSUFFICIENT_AUTHOR 0x08 -#define BLE_ATT_ERR_PREPARE_QUEUE_FULL 0x09 -#define BLE_ATT_ERR_ATTR_NOT_FOUND 0x0a -#define BLE_ATT_ERR_ATTR_NOT_LONG 0x0b -#define BLE_ATT_ERR_INSUFFICIENT_KEY_SZ 0x0c -#define BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN 0x0d -#define BLE_ATT_ERR_UNLIKELY 0x0e -#define BLE_ATT_ERR_INSUFFICIENT_ENC 0x0f -#define BLE_ATT_ERR_UNSUPPORTED_GROUP 0x10 -#define BLE_ATT_ERR_INSUFFICIENT_RES 0x11 - -#define BLE_ATT_OP_ERROR_RSP 0x01 -#define BLE_ATT_OP_MTU_REQ 0x02 -#define BLE_ATT_OP_MTU_RSP 0x03 -#define BLE_ATT_OP_FIND_INFO_REQ 0x04 -#define BLE_ATT_OP_FIND_INFO_RSP 0x05 -#define BLE_ATT_OP_FIND_TYPE_VALUE_REQ 0x06 -#define BLE_ATT_OP_FIND_TYPE_VALUE_RSP 0x07 -#define BLE_ATT_OP_READ_TYPE_REQ 0x08 -#define BLE_ATT_OP_READ_TYPE_RSP 0x09 -#define BLE_ATT_OP_READ_REQ 0x0a -#define BLE_ATT_OP_READ_RSP 0x0b -#define BLE_ATT_OP_READ_BLOB_REQ 0x0c -#define BLE_ATT_OP_READ_BLOB_RSP 0x0d -#define BLE_ATT_OP_READ_MULT_REQ 0x0e -#define BLE_ATT_OP_READ_MULT_RSP 0x0f -#define BLE_ATT_OP_READ_GROUP_TYPE_REQ 0x10 -#define BLE_ATT_OP_READ_GROUP_TYPE_RSP 0x11 -#define BLE_ATT_OP_WRITE_REQ 0x12 -#define BLE_ATT_OP_WRITE_RSP 0x13 -#define BLE_ATT_OP_PREP_WRITE_REQ 0x16 -#define BLE_ATT_OP_PREP_WRITE_RSP 0x17 -#define BLE_ATT_OP_EXEC_WRITE_REQ 0x18 -#define BLE_ATT_OP_EXEC_WRITE_RSP 0x19 -#define BLE_ATT_OP_NOTIFY_REQ 0x1b -#define BLE_ATT_OP_INDICATE_REQ 0x1d -#define BLE_ATT_OP_INDICATE_RSP 0x1e -#define BLE_ATT_OP_WRITE_CMD 0x52 - -#define BLE_ATT_ATTR_MAX_LEN 512 - -#define BLE_ATT_F_READ 0x01 -#define BLE_ATT_F_WRITE 0x02 -#define BLE_ATT_F_READ_ENC 0x04 -#define BLE_ATT_F_READ_AUTHEN 0x08 -#define BLE_ATT_F_READ_AUTHOR 0x10 -#define BLE_ATT_F_WRITE_ENC 0x20 -#define BLE_ATT_F_WRITE_AUTHEN 0x40 -#define BLE_ATT_F_WRITE_AUTHOR 0x80 - -#define HA_FLAG_PERM_RW (BLE_ATT_F_READ | BLE_ATT_F_WRITE) - -#define BLE_ATT_ACCESS_OP_READ 1 -#define BLE_ATT_ACCESS_OP_WRITE 2 - -/** Default ATT MTU. Also the minimum. */ -#define BLE_ATT_MTU_DFLT 23 - -/** - * An ATT MTU of 527 allows the largest ATT command (signed write) to contain a - * 512-byte attribute value. - */ -#define BLE_ATT_MTU_MAX 527 - -/** - * Reads a locally registered attribute. If the specified attribute handle - * corresponds to a GATT characteristic value or descriptor, the read is - * performed by calling the registered GATT access callback. - * - * @param attr_handle The 16-bit handle of the attribute to read. - * @param out_om On success, this is made to point to a - * newly-allocated mbuf containing the - * attribute data read. - * - * @return 0 on success; - * NimBLE host ATT return code if the attribute - * access callback reports failure; - * NimBLE host core return code on unexpected - * error. - */ -int ble_att_svr_read_local(uint16_t attr_handle, struct os_mbuf **out_om); - -/** - * Writes a locally registered attribute. This function consumes the supplied - * mbuf regardless of the outcome. If the specified attribute handle - * corresponds to a GATT characteristic value or descriptor, the write is - * performed by calling the registered GATT access callback. - * - * @param attr_handle The 16-bit handle of the attribute to write. - * @param om The value to write to the attribute. - * - * @return 0 on success; - * NimBLE host ATT return code if the attribute - * access callback reports failure; - * NimBLE host core return code on unexpected - * error. - */ -int ble_att_svr_write_local(uint16_t attr_handle, struct os_mbuf *om); - -/** - * Retrieves the ATT MTU of the specified connection. If an MTU exchange for - * this connection has occurred, the MTU is the lower of the two peers' - * preferred values. Otherwise, the MTU is the default value of 23. - * - * @param conn_handle The handle of the connection to query. - * - * @return The specified connection's ATT MTU, or 0 if - * there is no such connection. - */ -uint16_t ble_att_mtu(uint16_t conn_handle); - -/** - * Retrieves the preferred ATT MTU. This is the value indicated by the device - * during an ATT MTU exchange. - * - * @return The preferred ATT MTU. - */ -uint16_t ble_att_preferred_mtu(void); - -/** - * Sets the preferred ATT MTU; the device will indicate this value in all - * subsequent ATT MTU exchanges. The ATT MTU of a connection is equal to the - * lower of the two peers' preferred MTU values. The ATT MTU is what dictates - * the maximum size of any message sent during a GATT procedure. - * - * The specified MTU must be within the following range: [23, BLE_ATT_MTU_MAX]. - * 23 is a minimum imposed by the Bluetooth specification; BLE_ATT_MTU_MAX is a - * NimBLE compile-time setting. - * - * @param mtu The preferred ATT MTU. - * - * @return 0 on success; - * BLE_HS_EINVAL if the specified value is not - * within the allowed range. - */ -int ble_att_set_preferred_mtu(uint16_t mtu); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_eddystone.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_eddystone.h deleted file mode 100644 index 76b7e2b01..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_eddystone.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_EDDYSTONE_ -#define H_BLE_EDDYSTONE_ - -/** - * @brief Eddystone - BLE beacon from Google - * @defgroup bt_eddystone Eddystone - BLE beacon from Google - * @ingroup bt_host - * @{ - */ - -#include -#ifdef __cplusplus -extern "C" { -#endif - -struct ble_hs_adv_fields; - -#define BLE_EDDYSTONE_MAX_UUIDS16 3 -#define BLE_EDDYSTONE_URL_MAX_LEN 17 - -#define BLE_EDDYSTONE_URL_SCHEME_HTTP_WWW 0 -#define BLE_EDDYSTONE_URL_SCHEME_HTTPS_WWW 1 -#define BLE_EDDYSTONE_URL_SCHEME_HTTP 2 -#define BLE_EDDYSTONE_URL_SCHEME_HTTPS 3 - -#define BLE_EDDYSTONE_URL_SUFFIX_COM_SLASH 0x00 -#define BLE_EDDYSTONE_URL_SUFFIX_ORG_SLASH 0x01 -#define BLE_EDDYSTONE_URL_SUFFIX_EDU_SLASH 0x02 -#define BLE_EDDYSTONE_URL_SUFFIX_NET_SLASH 0x03 -#define BLE_EDDYSTONE_URL_SUFFIX_INFO_SLASH 0x04 -#define BLE_EDDYSTONE_URL_SUFFIX_BIZ_SLASH 0x05 -#define BLE_EDDYSTONE_URL_SUFFIX_GOV_SLASH 0x06 -#define BLE_EDDYSTONE_URL_SUFFIX_COM 0x07 -#define BLE_EDDYSTONE_URL_SUFFIX_ORG 0x08 -#define BLE_EDDYSTONE_URL_SUFFIX_EDU 0x09 -#define BLE_EDDYSTONE_URL_SUFFIX_NET 0x0a -#define BLE_EDDYSTONE_URL_SUFFIX_INFO 0x0b -#define BLE_EDDYSTONE_URL_SUFFIX_BIZ 0x0c -#define BLE_EDDYSTONE_URL_SUFFIX_GOV 0x0d -#define BLE_EDDYSTONE_URL_SUFFIX_NONE 0xff - -/** - * Configures the device to advertise Eddystone UID beacons. - * - * @param adv_fields The base advertisement fields to transform into - * an eddystone beacon. All configured fields - * are preserved; you probably want to clear - * this struct before calling this function. - * @param uid The 16-byte UID to advertise. - * @param measured_power The Measured Power (RSSI value at 0 Meter). - * - * @return 0 on success; - * BLE_HS_EBUSY if advertising is in progress; - * BLE_HS_EMSGSIZE if the specified data is too - * large to fit in an advertisement; - * Other nonzero on failure. - */ -int ble_eddystone_set_adv_data_uid(struct ble_hs_adv_fields *adv_fields, - void *uid, int8_t measured_power); - -/** - * Configures the device to advertise Eddystone URL beacons. - * - * @param adv_fields The base advertisement fields to transform into - * an eddystone beacon. All configured fields - * are preserved; you probably want to clear - * this struct before calling this function. - * @param url_scheme The prefix of the URL; one of the - * BLE_EDDYSTONE_URL_SCHEME values. - * @param url_body The middle of the URL. Don't include the - * suffix if there is a suitable suffix code. - * @param url_body_len The string length of the url_body argument. - * @param url_suffix The suffix of the URL; one of the - * BLE_EDDYSTONE_URL_SUFFIX values; use - * BLE_EDDYSTONE_URL_SUFFIX_NONE if the suffix - * is embedded in the body argument. - * @param measured_power The Measured Power (RSSI value at 0 Meter). - * - * @return 0 on success; - * BLE_HS_EBUSY if advertising is in progress; - * BLE_HS_EMSGSIZE if the specified data is too - * large to fit in an advertisement; - * Other nonzero on failure. - */ -int ble_eddystone_set_adv_data_url(struct ble_hs_adv_fields *adv_fields, - uint8_t url_scheme, char *url_body, - uint8_t url_body_len, uint8_t suffix, - int8_t measured_power); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_gap.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_gap.h deleted file mode 100644 index 7f77d7fb6..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_gap.h +++ /dev/null @@ -1,2163 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_GAP_ -#define H_BLE_GAP_ - -/** - * @brief Bluetooth Host Generic Access Profile (GAP) - * @defgroup bt_host_gap Bluetooth Host Generic Access Profile (GAP) - * @ingroup bt_host - * @{ - */ - -#include -#include "ble_hs.h" -#include "ble_hs_adv.h" -#include "nimble/porting/nimble/include/syscfg/syscfg.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct hci_le_conn_complete; -struct hci_conn_update; - -#define BLE_GAP_ADV_ITVL_MS(t) ((t) * 1000 / BLE_HCI_ADV_ITVL) -#define BLE_GAP_SCAN_ITVL_MS(t) ((t) * 1000 / BLE_HCI_SCAN_ITVL) -#define BLE_GAP_SCAN_WIN_MS(t) ((t) * 1000 / BLE_HCI_SCAN_ITVL) -#define BLE_GAP_CONN_ITVL_MS(t) ((t) * 1000 / BLE_HCI_CONN_ITVL) -#define BLE_GAP_SUPERVISION_TIMEOUT_MS(t) ((t) / 10) - -/** 30 ms. */ -#define BLE_GAP_ADV_FAST_INTERVAL1_MIN BLE_GAP_ADV_ITVL_MS(30) - -/** 60 ms. */ -#define BLE_GAP_ADV_FAST_INTERVAL1_MAX BLE_GAP_ADV_ITVL_MS(60) - -/** 100 ms. */ -#define BLE_GAP_ADV_FAST_INTERVAL2_MIN BLE_GAP_ADV_ITVL_MS(100) - -/** 150 ms. */ -#define BLE_GAP_ADV_FAST_INTERVAL2_MAX BLE_GAP_ADV_ITVL_MS(150) - -/** 30 ms; active scanning. */ -#define BLE_GAP_SCAN_FAST_INTERVAL_MIN BLE_GAP_SCAN_ITVL_MS(30) - -/** 60 ms; active scanning. */ -#define BLE_GAP_SCAN_FAST_INTERVAL_MAX BLE_GAP_SCAN_ITVL_MS(60) - -/** 11.25 ms; limited discovery interval. */ -#define BLE_GAP_LIM_DISC_SCAN_INT BLE_GAP_SCAN_ITVL_MS(11.25) - -/** 11.25 ms; limited discovery window (not from the spec). */ -#define BLE_GAP_LIM_DISC_SCAN_WINDOW BLE_GAP_SCAN_WIN_MS(11.25) - -/** 30 ms; active scanning. */ -#define BLE_GAP_SCAN_FAST_WINDOW BLE_GAP_SCAN_WIN_MS(30) - -/* 30.72 seconds; active scanning. */ -#define BLE_GAP_SCAN_FAST_PERIOD BLE_GAP_SCAN_ITVL_MS(30.72) - -/** 1.28 seconds; background scanning. */ -#define BLE_GAP_SCAN_SLOW_INTERVAL1 BLE_GAP_SCAN_ITVL_MS(1280) - -/** 11.25 ms; background scanning. */ -#define BLE_GAP_SCAN_SLOW_WINDOW1 BLE_GAP_SCAN_WIN_MS(11.25) - -/** 10.24 seconds. */ -#define BLE_GAP_DISC_DUR_DFLT (10.24 * 1000) - -/** 30 seconds (not from the spec). */ -#define BLE_GAP_CONN_DUR_DFLT (30 * 1000) - -/** 1 second. */ -#define BLE_GAP_CONN_PAUSE_CENTRAL (1 * 1000) - -/** 5 seconds. */ -#define BLE_GAP_CONN_PAUSE_PERIPHERAL (5 * 1000) - -/* 30 ms. */ -#define BLE_GAP_INITIAL_CONN_ITVL_MIN BLE_GAP_CONN_ITVL_MS(30) - -/* 50 ms. */ -#define BLE_GAP_INITIAL_CONN_ITVL_MAX BLE_GAP_CONN_ITVL_MS(50) - -/** Default channels mask: all three channels are used. */ -#define BLE_GAP_ADV_DFLT_CHANNEL_MAP 0x07 - -#define BLE_GAP_INITIAL_CONN_LATENCY 0 -#define BLE_GAP_INITIAL_SUPERVISION_TIMEOUT 0x0100 -#define BLE_GAP_INITIAL_CONN_MIN_CE_LEN 0x0000 -#define BLE_GAP_INITIAL_CONN_MAX_CE_LEN 0x0000 - -#define BLE_GAP_ROLE_MASTER 0 -#define BLE_GAP_ROLE_SLAVE 1 - -#define BLE_GAP_EVENT_CONNECT 0 -#define BLE_GAP_EVENT_DISCONNECT 1 -/* Reserved 2 */ -#define BLE_GAP_EVENT_CONN_UPDATE 3 -#define BLE_GAP_EVENT_CONN_UPDATE_REQ 4 -#define BLE_GAP_EVENT_L2CAP_UPDATE_REQ 5 -#define BLE_GAP_EVENT_TERM_FAILURE 6 -#define BLE_GAP_EVENT_DISC 7 -#define BLE_GAP_EVENT_DISC_COMPLETE 8 -#define BLE_GAP_EVENT_ADV_COMPLETE 9 -#define BLE_GAP_EVENT_ENC_CHANGE 10 -#define BLE_GAP_EVENT_PASSKEY_ACTION 11 -#define BLE_GAP_EVENT_NOTIFY_RX 12 -#define BLE_GAP_EVENT_NOTIFY_TX 13 -#define BLE_GAP_EVENT_SUBSCRIBE 14 -#define BLE_GAP_EVENT_MTU 15 -#define BLE_GAP_EVENT_IDENTITY_RESOLVED 16 -#define BLE_GAP_EVENT_REPEAT_PAIRING 17 -#define BLE_GAP_EVENT_PHY_UPDATE_COMPLETE 18 -#define BLE_GAP_EVENT_EXT_DISC 19 -#define BLE_GAP_EVENT_PERIODIC_SYNC 20 -#define BLE_GAP_EVENT_PERIODIC_REPORT 21 -#define BLE_GAP_EVENT_PERIODIC_SYNC_LOST 22 -#define BLE_GAP_EVENT_SCAN_REQ_RCVD 23 -#define BLE_GAP_EVENT_PERIODIC_TRANSFER 24 - -/*** Reason codes for the subscribe GAP event. */ - -/** Peer's CCCD subscription state changed due to a descriptor write. */ -#define BLE_GAP_SUBSCRIBE_REASON_WRITE 1 - -/** Peer's CCCD subscription state cleared due to connection termination. */ -#define BLE_GAP_SUBSCRIBE_REASON_TERM 2 - -/** - * Peer's CCCD subscription state changed due to restore from persistence - * (bonding restored). - */ -#define BLE_GAP_SUBSCRIBE_REASON_RESTORE 3 - -#define BLE_GAP_REPEAT_PAIRING_RETRY 1 -#define BLE_GAP_REPEAT_PAIRING_IGNORE 2 - -/** Connection security state */ -struct ble_gap_sec_state { - /** If connection is encrypted */ - unsigned encrypted:1; - - /** If connection is authenticated */ - unsigned authenticated:1; - - /** If connection is bonded (security information is stored) */ - unsigned bonded:1; - - /** Size of a key used for encryption */ - unsigned key_size:5; -}; - -/** Advertising parameters */ -struct ble_gap_adv_params { - /** Advertising mode. Can be one of following constants: - * - BLE_GAP_CONN_MODE_NON (non-connectable; 3.C.9.3.2). - * - BLE_GAP_CONN_MODE_DIR (directed-connectable; 3.C.9.3.3). - * - BLE_GAP_CONN_MODE_UND (undirected-connectable; 3.C.9.3.4). - */ - uint8_t conn_mode; - /** Discoverable mode. Can be one of following constants: - * - BLE_GAP_DISC_MODE_NON (non-discoverable; 3.C.9.2.2). - * - BLE_GAP_DISC_MODE_LTD (limited-discoverable; 3.C.9.2.3). - * - BLE_GAP_DISC_MODE_GEN (general-discoverable; 3.C.9.2.4). - */ - uint8_t disc_mode; - - /** Minimum advertising interval, if 0 stack use sane defaults */ - uint16_t itvl_min; - /** Maximum advertising interval, if 0 stack use sane defaults */ - uint16_t itvl_max; - /** Advertising channel map , if 0 stack use sane defaults */ - uint8_t channel_map; - - /** Advertising Filter policy */ - uint8_t filter_policy; - - /** If do High Duty cycle for Directed Advertising */ - uint8_t high_duty_cycle:1; -}; - -/** @brief Connection descriptor */ -struct ble_gap_conn_desc { - /** Connection security state */ - struct ble_gap_sec_state sec_state; - - /** Local identity address */ - ble_addr_t our_id_addr; - - /** Peer identity address */ - ble_addr_t peer_id_addr; - - /** Local over-the-air address */ - ble_addr_t our_ota_addr; - - /** Peer over-the-air address */ - ble_addr_t peer_ota_addr; - - /** Connection handle */ - uint16_t conn_handle; - - /** Connection interval */ - uint16_t conn_itvl; - - /** Connection latency */ - uint16_t conn_latency; - - /** Connection supervision timeout */ - uint16_t supervision_timeout; - - /** Connection Role - * Possible values BLE_GAP_ROLE_SLAVE or BLE_GAP_ROLE_MASTER - */ - uint8_t role; - - /** Master clock accuracy */ - uint8_t master_clock_accuracy; -}; - -/** @brief Connection parameters */ -struct ble_gap_conn_params { - /** Scan interval in 0.625ms units */ - uint16_t scan_itvl; - - /** Scan window in 0.625ms units */ - uint16_t scan_window; - - /** Minimum value for connection interval in 1.25ms units */ - uint16_t itvl_min; - - /** Maximum value for connection interval in 1.25ms units */ - uint16_t itvl_max; - - /** Connection latency */ - uint16_t latency; - - /** Supervision timeout in 10ms units */ - uint16_t supervision_timeout; - - /** Minimum length of connection event in 0.625ms units */ - uint16_t min_ce_len; - - /** Maximum length of connection event in 0.625ms units */ - uint16_t max_ce_len; -}; - -/** @brief Extended discovery parameters */ -struct ble_gap_ext_disc_params { - /** Scan interval in 0.625ms units */ - uint16_t itvl; - - /** Scan window in 0.625ms units */ - uint16_t window; - - /** If passive scan should be used */ - uint8_t passive:1; -}; - -/** @brief Discovery parameters */ -struct ble_gap_disc_params { - /** Scan interval in 0.625ms units */ - uint16_t itvl; - - /** Scan window in 0.625ms units */ - uint16_t window; - - /** Scan filter policy */ - uint8_t filter_policy; - - /** If limited discovery procedure should be used */ - uint8_t limited:1; - - /** If passive scan should be used */ - uint8_t passive:1; - - /** If enable duplicates filtering */ - uint8_t filter_duplicates:1; -}; - -/** @brief Connection parameters update parameters */ -struct ble_gap_upd_params { - /** Minimum value for connection interval in 1.25ms units */ - uint16_t itvl_min; - - /** Maximum value for connection interval in 1.25ms units */ - uint16_t itvl_max; - - /** Connection latency */ - uint16_t latency; - - /** Supervision timeout in 10ms units */ - uint16_t supervision_timeout; - - /** Minimum length of connection event in 0.625ms units */ - uint16_t min_ce_len; - - /** Maximum length of connection event in 0.625ms units */ - uint16_t max_ce_len; -}; - -/** @brief Passkey query */ -struct ble_gap_passkey_params { - /** Passkey action, can be one of following constants: - * - BLE_SM_IOACT_NONE - * - BLE_SM_IOACT_OOB - * - BLE_SM_IOACT_INPUT - * - BLE_SM_IOACT_DISP - * - BLE_SM_IOACT_NUMCMP - */ - uint8_t action; - - /** Passkey to compare, valid for BLE_SM_IOACT_NUMCMP action */ - uint32_t numcmp; -}; - -#if MYNEWT_VAL(BLE_EXT_ADV) - -#define BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE 0x00 -#define BLE_GAP_EXT_ADV_DATA_STATUS_INCOMPLETE 0x01 -#define BLE_GAP_EXT_ADV_DATA_STATUS_TRUNCATED 0x02 - -/** @brief Extended advertising report */ -struct ble_gap_ext_disc_desc { - /** Report properties bitmask - * - BLE_HCI_ADV_CONN_MASK - * - BLE_HCI_ADV_SCAN_MASK - * - BLE_HCI_ADV_DIRECT_MASK - * - BLE_HCI_ADV_SCAN_RSP_MASK - * - BLE_HCI_ADV_LEGACY_MASK - * */ - uint8_t props; - - /** Advertising data status, can be one of following constants: - * - BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE - * - BLE_GAP_EXT_ADV_DATA_STATUS_INCOMPLETE - * - BLE_GAP_EXT_ADV_DATA_STATUS_TRUNCATED - */ - uint8_t data_status; - - /** Legacy advertising PDU type. Valid if BLE_HCI_ADV_LEGACY_MASK props is - * set. Can be one of following constants: - * - BLE_HCI_ADV_RPT_EVTYPE_ADV_IND - * - BLE_HCI_ADV_RPT_EVTYPE_DIR_IND - * - BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND - * - BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND - * - BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP - */ - uint8_t legacy_event_type; - - /** Advertiser address */ - ble_addr_t addr; - - /** Received signal strength indication in dBm (127 if unavailable) */ - int8_t rssi; - - /** Advertiser transmit power in dBm (127 if unavailable) */ - int8_t tx_power; - - /** Advertising Set ID */ - uint8_t sid; - - /** Primary advertising PHY, can be one of following constants: - * - BLE_HCI_LE_PHY_1M - * - BLE_HCI_LE_PHY_CODED - */ - uint8_t prim_phy; - - /** Secondary advertising PHY, can be one of following constants: - * - BLE_HCI_LE_PHY_1M - * - LE_HCI_LE_PHY_2M - * - BLE_HCI_LE_PHY_CODED - */ - uint8_t sec_phy; - - /** Periodic advertising interval. 0 if no periodic advertising. */ - uint16_t periodic_adv_itvl; - - /** Advertising Data length */ - uint8_t length_data; - - /** Advertising data */ - const uint8_t *data; - - /** Directed advertising address. Valid if BLE_HCI_ADV_DIRECT_MASK props is - * set (BLE_ADDR_ANY otherwise). - */ - ble_addr_t direct_addr; -}; -#endif - -/** @brief Advertising report */ -struct ble_gap_disc_desc { - /** Advertising PDU type. Can be one of following constants: - * - BLE_HCI_ADV_RPT_EVTYPE_ADV_IND - * - BLE_HCI_ADV_RPT_EVTYPE_DIR_IND - * - BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND - * - BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND - * - BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP - */ - uint8_t event_type; - - /** Advertising Data length */ - uint8_t length_data; - - /** Advertiser address */ - ble_addr_t addr; - - /** Received signal strength indication in dBm (127 if unavailable) */ - int8_t rssi; - - /** Advertising data */ - const uint8_t *data; - - /** Directed advertising address. Valid for BLE_HCI_ADV_RPT_EVTYPE_DIR_IND - * event type (BLE_ADDR_ANY otherwise). - */ - ble_addr_t direct_addr; -}; - -struct ble_gap_repeat_pairing { - /** The handle of the relevant connection. */ - uint16_t conn_handle; - - /** Properties of the existing bond. */ - uint8_t cur_key_size; - uint8_t cur_authenticated:1; - uint8_t cur_sc:1; - - /** - * Properties of the imminent secure link if the pairing procedure is - * allowed to continue. - */ - uint8_t new_key_size; - uint8_t new_authenticated:1; - uint8_t new_sc:1; - uint8_t new_bonding:1; -}; - -/** - * Represents a GAP-related event. When such an event occurs, the host - * notifies the application by passing an instance of this structure to an - * application-specified callback. - */ -struct ble_gap_event { - /** - * Indicates the type of GAP event that occurred. This is one of the - * BLE_GAP_EVENT codes. - */ - uint8_t type; - - /** - * A discriminated union containing additional details concerning the GAP - * event. The 'type' field indicates which member of the union is valid. - */ - union { - /** - * Represents a connection attempt. Valid for the following event - * types: - * o BLE_GAP_EVENT_CONNECT - */ - struct { - /** - * The status of the connection attempt; - * o 0: the connection was successfully established. - * o BLE host error code: the connection attempt failed for - * the specified reason. - */ - int status; - - /** The handle of the relevant connection. */ - uint16_t conn_handle; - } connect; - - /** - * Represents a terminated connection. Valid for the following event - * types: - * o BLE_GAP_EVENT_DISCONNECT - */ - struct { - /** - * A BLE host return code indicating the reason for the - * disconnect. - */ - int reason; - - /** Information about the connection prior to termination. */ - struct ble_gap_conn_desc conn; - } disconnect; - - /** - * Represents an advertising report received during a discovery - * procedure. Valid for the following event types: - * o BLE_GAP_EVENT_DISC - */ - struct ble_gap_disc_desc disc; - -#if MYNEWT_VAL(BLE_EXT_ADV) - /** - * Represents an extended advertising report received during a discovery - * procedure. Valid for the following event types: - * o BLE_GAP_EVENT_EXT_DISC - */ - struct ble_gap_ext_disc_desc ext_disc; -#endif - - /** - * Represents a completed discovery procedure. Valid for the following - * event types: - * o BLE_GAP_EVENT_DISC_COMPLETE - */ - struct { - /** - * The reason the discovery procedure stopped. Typical reason - * codes are: - * o 0: Duration expired. - * o BLE_HS_EPREEMPTED: Host aborted procedure to configure a - * peer's identity. - */ - int reason; - } disc_complete; - - /** - * Represents a completed advertise procedure. Valid for the following - * event types: - * o BLE_GAP_EVENT_ADV_COMPLETE - */ - struct { - /** - * The reason the advertise procedure stopped. Typical reason - * codes are: - * o 0: Terminated due to connection. - * o BLE_HS_ETIMEOUT: Duration expired. - * o BLE_HS_EPREEMPTED: Host aborted procedure to configure a - * peer's identity. - */ - int reason; - -#if MYNEWT_VAL(BLE_EXT_ADV) - /** Advertising instance */ - uint8_t instance; - /** The handle of the relevant connection - valid if reason=0 */ - uint16_t conn_handle; - /** - * Number of completed extended advertising events - * - * This field is only valid if non-zero max_events was passed to - * ble_gap_ext_adv_start() and advertising completed due to duration - * timeout or max events transmitted. - * */ - uint8_t num_ext_adv_events; -#endif - } adv_complete; - - /** - * Represents an attempt to update a connection's parameters. If the - * attempt was successful, the connection's descriptor reflects the - * updated parameters. - * - * Valid for the following event types: - * o BLE_GAP_EVENT_CONN_UPDATE - */ - struct { - /** - * The result of the connection update attempt; - * o 0: the connection was successfully updated. - * o BLE host error code: the connection update attempt failed - * for the specified reason. - */ - int status; - - /** The handle of the relevant connection. */ - uint16_t conn_handle; - } conn_update; - - /** - * Represents a peer's request to update the connection parameters. - * This event is generated when a peer performs any of the following - * procedures: - * o L2CAP Connection Parameter Update Procedure - * o Link-Layer Connection Parameters Request Procedure - * - * To reject the request, return a non-zero HCI error code. The value - * returned is the reject reason given to the controller. - * - * Valid for the following event types: - * o BLE_GAP_EVENT_L2CAP_UPDATE_REQ - * o BLE_GAP_EVENT_CONN_UPDATE_REQ - */ - struct { - /** - * Indicates the connection parameters that the peer would like to - * use. - */ - const struct ble_gap_upd_params *peer_params; - - /** - * Indicates the connection parameters that the local device would - * like to use. The application callback should fill this in. By - * default, this struct contains the requested parameters (i.e., - * it is a copy of 'peer_params'). - */ - struct ble_gap_upd_params *self_params; - - /** The handle of the relevant connection. */ - uint16_t conn_handle; - } conn_update_req; - - /** - * Represents a failed attempt to terminate an established connection. - * Valid for the following event types: - * o BLE_GAP_EVENT_TERM_FAILURE - */ - struct { - /** - * A BLE host return code indicating the reason for the failure. - */ - int status; - - /** The handle of the relevant connection. */ - uint16_t conn_handle; - } term_failure; - - /** - * Represents an attempt to change the encrypted state of a - * connection. If the attempt was successful, the connection - * descriptor reflects the updated encrypted state. - * - * Valid for the following event types: - * o BLE_GAP_EVENT_ENC_CHANGE - */ - struct { - /** - * Indicates the result of the encryption state change attempt; - * o 0: the encrypted state was successfully updated; - * o BLE host error code: the encryption state change attempt - * failed for the specified reason. - */ - int status; - - /** The handle of the relevant connection. */ - uint16_t conn_handle; - } enc_change; - - /** - * Represents a passkey query needed to complete a pairing procedure. - * - * Valid for the following event types: - * o BLE_GAP_EVENT_PASSKEY_ACTION - */ - struct { - /** Contains details about the passkey query. */ - struct ble_gap_passkey_params params; - - /** The handle of the relevant connection. */ - uint16_t conn_handle; - } passkey; - - /** - * Represents a received ATT notification or indication. - * - * Valid for the following event types: - * o BLE_GAP_EVENT_NOTIFY_RX - */ - struct { - /** - * The contents of the notification or indication. If the - * application wishes to retain this mbuf for later use, it must - * set this pointer to NULL to prevent the stack from freeing it. - */ - struct os_mbuf *om; - - /** The handle of the relevant ATT attribute. */ - uint16_t attr_handle; - - /** The handle of the relevant connection. */ - uint16_t conn_handle; - - /** - * Whether the received command is a notification or an - * indication; - * o 0: Notification; - * o 1: Indication. - */ - uint8_t indication:1; - } notify_rx; - - /** - * Represents a transmitted ATT notification or indication, or a - * completed indication transaction. - * - * Valid for the following event types: - * o BLE_GAP_EVENT_NOTIFY_TX - */ - struct { - /** - * The status of the notification or indication transaction; - * o 0: Command successfully sent; - * o BLE_HS_EDONE: Confirmation (indication ack) received; - * o BLE_HS_ETIMEOUT: Confirmation (indication ack) never - * received; - * o Other return code: Error. - */ - int status; - - /** The handle of the relevant connection. */ - uint16_t conn_handle; - - /** The handle of the relevant characteristic value. */ - uint16_t attr_handle; - - /** - * Whether the transmitted command is a notification or an - * indication; - * o 0: Notification; - * o 1: Indication. - */ - uint8_t indication:1; - } notify_tx; - - /** - * Represents a state change in a peer's subscription status. In this - * comment, the term "update" is used to refer to either a notification - * or an indication. This event is triggered by any of the following - * occurrences: - * o Peer enables or disables updates via a CCCD write. - * o Connection is about to be terminated and the peer is - * subscribed to updates. - * o Peer is now subscribed to updates after its state was restored - * from persistence. This happens when bonding is restored. - * - * Valid for the following event types: - * o BLE_GAP_EVENT_SUBSCRIBE - */ - struct { - /** The handle of the relevant connection. */ - uint16_t conn_handle; - - /** The value handle of the relevant characteristic. */ - uint16_t attr_handle; - - /** One of the BLE_GAP_SUBSCRIBE_REASON codes. */ - uint8_t reason; - - /** Whether the peer was previously subscribed to notifications. */ - uint8_t prev_notify:1; - - /** Whether the peer is currently subscribed to notifications. */ - uint8_t cur_notify:1; - - /** Whether the peer was previously subscribed to indications. */ - uint8_t prev_indicate:1; - - /** Whether the peer is currently subscribed to indications. */ - uint8_t cur_indicate:1; - } subscribe; - - /** - * Represents a change in an L2CAP channel's MTU. - * - * Valid for the following event types: - * o BLE_GAP_EVENT_MTU - */ - struct { - /** The handle of the relevant connection. */ - uint16_t conn_handle; - - /** - * Indicates the channel whose MTU has been updated; either - * BLE_L2CAP_CID_ATT or the ID of a connection-oriented channel. - */ - uint16_t channel_id; - - /* The channel's new MTU. */ - uint16_t value; - } mtu; - - /** - * Represents a change in peer's identity. This is issued after - * successful pairing when Identity Address Information was received. - * - * Valid for the following event types: - * o BLE_GAP_EVENT_IDENTITY_RESOLVED - */ - struct { - /** The handle of the relevant connection. */ - uint16_t conn_handle; - } identity_resolved; - - /** - * Represents a peer's attempt to pair despite a bond already existing. - * The application has two options for handling this event type: - * o Retry: Return BLE_GAP_REPEAT_PAIRING_RETRY after deleting the - * conflicting bond. The stack will verify the bond has - * been deleted and continue the pairing procedure. If - * the bond is still present, this event will be reported - * again. - * o Ignore: Return BLE_GAP_REPEAT_PAIRING_IGNORE. The stack will - * silently ignore the pairing request. - * - * Valid for the following event types: - * o BLE_GAP_EVENT_REPEAT_PAIRING - */ - struct ble_gap_repeat_pairing repeat_pairing; - - /** - * Represents a change of PHY. This is issue after successful - * change on PHY. - */ - struct { - int status; - uint16_t conn_handle; - - /** - * Indicates enabled TX/RX PHY. Possible values: - * o BLE_GAP_LE_PHY_1M - * o BLE_GAP_LE_PHY_2M - * o BLE_GAP_LE_PHY_CODED - */ - uint8_t tx_phy; - uint8_t rx_phy; - } phy_updated; -#if MYNEWT_VAL(BLE_PERIODIC_ADV) - /** - * Represents a periodic advertising sync established during discovery - * procedure. Valid for the following event types: - * o BLE_GAP_EVENT_PERIODIC_SYNC - */ - struct { - /** BLE_ERR_SUCCESS on success or error code on failure. Other - * fields are valid only for success - */ - uint8_t status; - /** Periodic sync handle */ - uint16_t sync_handle; - - /** Advertising Set ID */ - uint8_t sid; - - /** Advertiser address */ - ble_addr_t adv_addr; - - /** Advertising PHY, can be one of following constants: - * - BLE_HCI_LE_PHY_1M - * - LE_HCI_LE_PHY_2M - * - BLE_HCI_LE_PHY_CODED - */ - uint8_t adv_phy; - - /** Periodic advertising interval */ - uint16_t per_adv_ival; - - /** Advertiser clock accuracy */ - uint8_t adv_clk_accuracy; - } periodic_sync; - - /** - * Represents a periodic advertising report received on established - * sync. Valid for the following event types: - * o BLE_GAP_EVENT_PERIODIC_REPORT - */ - struct { - /** Periodic sync handle */ - uint16_t sync_handle; - - /** Advertiser transmit power in dBm (127 if unavailable) */ - int8_t tx_power; - - /** Received signal strength indication in dBm (127 if unavailable) */ - int8_t rssi; - - /** Advertising data status, can be one of following constants: - * - BLE_HCI_PERIODIC_DATA_STATUS_COMPLETE - * - BLE_HCI_PERIODIC_DATA_STATUS_INCOMPLETE - * - BLE_HCI_PERIODIC_DATA_STATUS_TRUNCATED - */ - uint8_t data_status; - - /** Advertising Data length */ - uint8_t data_length; - - /** Advertising data */ - const uint8_t *data; - } periodic_report; - - /** - * Represents a periodic advertising sync lost of established sync. - * Sync lost reason can be BLE_HS_ETIMEOUT (sync timeout) or - * BLE_HS_EDONE (sync terminated locally). - * Valid for the following event types: - * o BLE_GAP_EVENT_PERIODIC_SYNC_LOST - */ - struct { - /** Periodic sync handle */ - uint16_t sync_handle; - - /** Reason for sync lost, can be BLE_HS_ETIMEOUT for timeout or - * BLE_HS_EDONE for locally terminated sync - */ - int reason; - } periodic_sync_lost; -#endif - -#if MYNEWT_VAL(BLE_EXT_ADV) - /** - * Represents a scan request for an extended advertising instance where - * scan request notifications were enabled. - * Valid for the following event types: - * o BLE_GAP_EVENT_SCAN_REQ_RCVD - */ - struct { - /** Extended advertising instance */ - uint8_t instance; - /** Address of scanner */ - ble_addr_t scan_addr; - } scan_req_rcvd; -#endif -#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) - /** - * Represents a periodic advertising sync transfer received. Valid for - * the following event types: - * o BLE_GAP_EVENT_PERIODIC_TRANSFER - */ - struct { - /** BLE_ERR_SUCCESS on success or error code on failure. Sync handle - * is valid only for success. - */ - uint8_t status; - - /** Periodic sync handle */ - uint16_t sync_handle; - - /** Connection handle */ - uint16_t conn_handle; - - /** Service Data */ - uint16_t service_data; - - /** Advertising Set ID */ - uint8_t sid; - - /** Advertiser address */ - ble_addr_t adv_addr; - - /** Advertising PHY, can be one of following constants: - * - BLE_HCI_LE_PHY_1M - * - LE_HCI_LE_PHY_2M - * - BLE_HCI_LE_PHY_CODED - */ - uint8_t adv_phy; - - /** Periodic advertising interval */ - uint16_t per_adv_itvl; - - /** Advertiser clock accuracy */ - uint8_t adv_clk_accuracy; - } periodic_transfer; -#endif - }; -}; - -typedef int ble_gap_event_fn(struct ble_gap_event *event, void *arg); - -#define BLE_GAP_CONN_MODE_NON 0 -#define BLE_GAP_CONN_MODE_DIR 1 -#define BLE_GAP_CONN_MODE_UND 2 - -#define BLE_GAP_DISC_MODE_NON 0 -#define BLE_GAP_DISC_MODE_LTD 1 -#define BLE_GAP_DISC_MODE_GEN 2 - -/** - * Searches for a connection with the specified handle. If a matching - * connection is found, the supplied connection descriptor is filled - * correspondingly. - * - * @param handle The connection handle to search for. - * @param out_desc On success, this is populated with information relating to - * the matching connection. Pass NULL if you don't need this - * information. - * - * @return 0 on success, BLE_HS_ENOTCONN if no matching connection was - * found. - */ -int ble_gap_conn_find(uint16_t handle, struct ble_gap_conn_desc *out_desc); - -/** - * Searches for a connection with a peer with the specified address. - * If a matching connection is found, the supplied connection descriptor - * is filled correspondingly. - * - * @param addr The ble address of a connected peer device to search for. - * @param out_desc On success, this is populated with information relating to - * the matching connection. Pass NULL if you don't need this - * information. - * - * @return 0 on success, BLE_HS_ENOTCONN if no matching connection was - * found. - */ -int ble_gap_conn_find_by_addr(const ble_addr_t *addr, - struct ble_gap_conn_desc *out_desc); - -/** - * Configures a connection to use the specified GAP event callback. A - * connection's GAP event callback is first specified when the connection is - * created, either via advertising or initiation. This function replaces the - * callback that was last configured. - * - * @param conn_handle The handle of the connection to configure. - * @param cb The callback to associate with the connection. - * @param cb_arg An optional argument that the callback receives. - * - * @return 0 on success, BLE_HS_ENOTCONN if there is no connection - * with the specified handle. - */ -int ble_gap_set_event_cb(uint16_t conn_handle, - ble_gap_event_fn *cb, void *cb_arg); - -/** @brief Start advertising - * - * This function configures and start advertising procedure. - * - * @param own_addr_type The type of address the stack should use for itself. - * Valid values are: - * - BLE_OWN_ADDR_PUBLIC - * - BLE_OWN_ADDR_RANDOM - * - BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT - * - BLE_OWN_ADDR_RPA_RANDOM_DEFAULT - * @param direct_addr The peer's address for directed advertising. This - * parameter shall be non-NULL if directed advertising is - * being used. - * @param duration_ms The duration of the advertisement procedure. On - * expiration, the procedure ends and a - * BLE_GAP_EVENT_ADV_COMPLETE event is reported. Units are - * milliseconds. Specify BLE_HS_FOREVER for no expiration. - * @param adv_params Additional arguments specifying the particulars of the - * advertising procedure. - * @param cb The callback to associate with this advertising - * procedure. If advertising ends, the event is reported - * through this callback. If advertising results in a - * connection, the connection inherits this callback as its - * event-reporting mechanism. - * @param cb_arg The optional argument to pass to the callback function. - * - * @return 0 on success, error code on failure. - */ -int ble_gap_adv_start(uint8_t own_addr_type, const ble_addr_t *direct_addr, - int32_t duration_ms, - const struct ble_gap_adv_params *adv_params, - ble_gap_event_fn *cb, void *cb_arg); - -/** - * Stops the currently-active advertising procedure. A success return - * code indicates that advertising has been fully aborted and a new advertising - * procedure can be initiated immediately. - * - * NOTE: If the caller is running in the same task as the NimBLE host, or if it - * is running in a higher priority task than that of the host, care must be - * taken when restarting advertising. Under these conditions, the following is - * *not* a reliable method to restart advertising: - * ble_gap_adv_stop() - * ble_gap_adv_start() - * - * Instead, the call to `ble_gap_adv_start()` must be made in a separate event - * context. That is, `ble_gap_adv_start()` must be called asynchronously by - * enqueueing an event on the current task's event queue. See - * https://github.com/apache/mynewt-nimble/pull/211 for more information. - * - * @return 0 on success, BLE_HS_EALREADY if there is no active advertising - * procedure, other error code on failure. - */ -int ble_gap_adv_stop(void); - -/** - * Indicates whether an advertisement procedure is currently in progress. - * - * @return 0 if no advertisement procedure in progress, 1 otherwise. - */ -int ble_gap_adv_active(void); - -/** - * Configures the data to include in subsequent advertisements. - * - * @param data Buffer containing the advertising data. - * @param data_len The size of the advertising data, in bytes. - * - * @return 0 on succes, BLE_HS_EBUSY if advertising is in progress, - * other error code on failure. - */ -int ble_gap_adv_set_data(const uint8_t *data, int data_len); - -/** - * Configures the data to include in subsequent scan responses. - * - * @param data Buffer containing the scan response data. - * @param data_len The size of the response data, in bytes. - * - * @return 0 on succes, BLE_HS_EBUSY if advertising is in progress, - * other error code on failure. - */ -int ble_gap_adv_rsp_set_data(const uint8_t *data, int data_len); - -/** - * Configures the fields to include in subsequent advertisements. This is a - * convenience wrapper for ble_gap_adv_set_data(). - * - * @param adv_fields Specifies the advertisement data. - * - * @return 0 on success, - * BLE_HS_EBUSY if advertising is in progress, - * BLE_HS_EMSGSIZE if the specified data is too large to - * fit in an advertisement, - * other error code on failure. - */ -int ble_gap_adv_set_fields(const struct ble_hs_adv_fields *rsp_fields); - -/** - * Configures the fields to include in subsequent scan responses. This is a - * convenience wrapper for ble_gap_adv_rsp_set_data(). - * - * @param adv_fields Specifies the scan response data. - * - * @return 0 on success, - * BLE_HS_EBUSY if advertising is in progress, - * BLE_HS_EMSGSIZE if the specified data is too large to - * fit in a scan response, - * other error code on failure. - */ -int ble_gap_adv_rsp_set_fields(const struct ble_hs_adv_fields *rsp_fields); - -/** - * Configure LE Data Length in controller (OGF = 0x08, OCF = 0x0022). - * - * @param conn_handle Connection handle. - * @param tx_octets The preferred value of payload octets that the Controller - * should use for a new connection (Range - * 0x001B-0x00FB). - * @param tx_time The preferred maximum number of microseconds that the local Controller - * should use to transmit a single link layer packet - * (Range 0x0148-0x4290). - * - * @return 0 on success, - * other error code on failure. - */ -int ble_hs_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets, - uint16_t tx_time); - -/** - * Read host's suggested values for the controller's maximum transmitted number of payload octets - * and maximum packet transmission time (OGF = 0x08, OCF = 0x0024). - * - * @param out_sugg_max_tx_octets The Host's suggested value for the Controller's maximum transmitted - * number of payload octets in LL Data PDUs to be used for new - * connections. (Range 0x001B-0x00FB). - * @param out_sugg_max_tx_time The Host's suggested value for the Controller's maximum packet - * transmission time for packets containing LL Data PDUs to be used - * for new connections. (Range 0x0148-0x4290). - * - * @return 0 on success, - * other error code on failure. - */ -int ble_hs_hci_util_read_sugg_def_data_len(uint16_t *out_sugg_max_tx_octets, - uint16_t *out_sugg_max_tx_time); -/** - * Configure host's suggested maximum transmitted number of payload octets and maximum packet - * transmission time in controller (OGF = 0x08, OCF = 0x0024). - * - * @param sugg_max_tx_octets The Host's suggested value for the Controller's maximum transmitted - * number of payload octets in LL Data PDUs to be used for new - * connections. (Range 0x001B-0x00FB). - * @param sugg_max_tx_time The Host's suggested value for the Controller's maximum packet - * transmission time for packets containing LL Data PDUs to be used - * for new connections. (Range 0x0148-0x4290). - * - * @return 0 on success, - * other error code on failure. - */ -int ble_hs_hci_util_write_sugg_def_data_len(uint16_t sugg_max_tx_octets, uint16_t sugg_max_tx_time); - -#if MYNEWT_VAL(BLE_EXT_ADV) -/** @brief Extended advertising parameters */ -struct ble_gap_ext_adv_params { - /** If perform connectable advertising */ - unsigned int connectable:1; - - /** If perform scannable advertising */ - unsigned int scannable:1; - - /** If perform directed advertising */ - unsigned int directed:1; - - /** If perform high-duty directed advertising */ - unsigned int high_duty_directed:1; - - /** If use legacy PDUs for advertising */ - unsigned int legacy_pdu:1; - - /** If perform anonymous advertising */ - unsigned int anonymous:1; - - /** If include TX power in advertising PDU */ - unsigned int include_tx_power:1; - - /** If enable scan request notification */ - unsigned int scan_req_notif:1; - - /** Minimum advertising interval in 0.625ms units, if 0 stack use sane - * defaults - */ - uint32_t itvl_min; - - /** Maximum advertising interval in 0.625ms units, if 0 stack use sane - * defaults - */ - uint32_t itvl_max; - - /** Advertising channel map , if 0 stack use sane defaults */ - uint8_t channel_map; - - /** Own address type to be used by advertising instance */ - uint8_t own_addr_type; - - /** Peer address for directed advertising, valid only if directed is set */ - ble_addr_t peer; - - /** Advertising Filter policy */ - uint8_t filter_policy; - - /** Primary advertising PHY to use , can be one of following constants: - * - BLE_HCI_LE_PHY_1M - * - BLE_HCI_LE_PHY_CODED - */ - uint8_t primary_phy; - - /** Secondary advertising PHY to use, can be one of following constants: - * - BLE_HCI_LE_PHY_1M - * - LE_HCI_LE_PHY_2M - * - BLE_HCI_LE_PHY_CODED - */ - uint8_t secondary_phy; - - /** Preferred advertiser transmit power */ - int8_t tx_power; - - /** Advertising Set ID */ - uint8_t sid; -}; - -/** - * Configure extended advertising instance - * - * @param instance Instance ID - * @param params Additional arguments specifying the particulars - * of the advertising. - * @param selected_tx_power Selected advertising transmit power will be - * stored in that param if non-NULL. - * @param cb The callback to associate with this advertising - * procedure. Advertising complete event is reported - * through this callback - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_ext_adv_configure(uint8_t instance, - const struct ble_gap_ext_adv_params *params, - int8_t *selected_tx_power, - ble_gap_event_fn *cb, void *cb_arg); - -/** - * Set random address for configured advertising instance. - * - * @param instance Instance ID - * @param addr Random address to be set - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_ext_adv_set_addr(uint8_t instance, const ble_addr_t *addr); - -/** - * Start advertising instance. - * - * @param instance Instance ID - * @param duration The duration of the advertisement procedure. On - * expiration, the procedure ends and - * a BLE_GAP_EVENT_ADV_COMPLETE event is reported. - * Units are 10 milliseconds. Specify 0 for no - * expiration. - * @params max_events Number of advertising events that should be sent - * before advertising ends and - * a BLE_GAP_EVENT_ADV_COMPLETE event is reported. - * Specify 0 for no limit. - * - * @return 0 on success, error code on failure. - */ -int ble_gap_ext_adv_start(uint8_t instance, int duration, int max_events); - -/** - * Stops advertising procedure for specified instance. - * - * @param instance Instance ID - * - * @return 0 on success, BLE_HS_EALREADY if there is no active advertising - * procedure for instance, other error code on failure. - */ -int ble_gap_ext_adv_stop(uint8_t instance); - -/** - * Configures the data to include in advertisements packets for specified - * advertising instance. - * - * @param instance Instance ID - * @param data Chain containing the advertising data. - * - * @return 0 on success or error code on failure. - */ -int ble_gap_ext_adv_set_data(uint8_t instance, struct os_mbuf *data); - -/** - * Configures the data to include in subsequent scan responses for specified - * advertisign instance. - * - * @param instance Instance ID - * @param data Chain containing the scan response data. - * - * @return 0 on success or error code on failure. - */ - -int ble_gap_ext_adv_rsp_set_data(uint8_t instance, struct os_mbuf *data); - -/** - * Remove existing advertising instance. - * - * @param instance Instance ID - * - * @return 0 on success, - * BLE_HS_EBUSY if advertising is in progress, - * other error code on failure. - */ -int ble_gap_ext_adv_remove(uint8_t instance); - -/** - * Clear all existing advertising instances - * @return 0 on success, - * BLE_HS_EBUSY if advertising is in progress, - * other error code on failure. - */ -int ble_gap_ext_adv_clear(void); -#endif - -/* Periodic Advertising */ -#if MYNEWT_VAL(BLE_PERIODIC_ADV) - -/** @brief Periodic advertising parameters */ -struct ble_gap_periodic_adv_params { - /** If include TX power in advertising PDU */ - unsigned int include_tx_power:1; - - /** Minimum advertising interval in 0.625ms units, if 0 stack use sane - * defaults - */ - uint16_t itvl_min; - - /** Maximum advertising interval in 0.625ms units, if 0 stack use sane - * defaults - */ - uint16_t itvl_max; -}; - -/** @brief Periodic sync parameters */ -struct ble_gap_periodic_sync_params { - /** The maximum number of periodic advertising events that controller can - * skip after a successful receive. - * */ - uint16_t skip; - - /** Synchronization timeout for the periodic advertising train in 10ms units - */ - uint16_t sync_timeout; - - /** If reports should be initially disabled when sync is created */ - unsigned int reports_disabled:1; -}; - -/** - * Configure periodic advertising for specified advertising instance - * - * This is allowed only for instances configured as non-announymous, - * non-connectable and non-scannable. - * - * @param instance Instance ID - * @param params Additional arguments specifying the particulars - * of periodic advertising. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_periodic_adv_configure(uint8_t instance, - const struct ble_gap_periodic_adv_params *params); - -/** - * Start periodic advertising for specified advertising instance. - * - * @param instance Instance ID - * - * @return 0 on success, error code on failure. - */ -int ble_gap_periodic_adv_start(uint8_t instance); - -/** - * Stop periodic advertising for specified advertising instance. - * - * @param instance Instance ID - * - * @return 0 on success, error code on failure. - */ -int ble_gap_periodic_adv_stop(uint8_t instance); - -/** - * Configures the data to include in periodic advertisements for specified - * advertising instance. - * - * @param instance Instance ID - * @param data Chain containing the periodic advertising data. - * - * @return 0 on success or error code on failure. - */ -int ble_gap_periodic_adv_set_data(uint8_t instance, struct os_mbuf *data); - -/** - * Performs the Synchronization procedure with periodic advertiser. - * - * @param addr Peer address to synchronize with. If NULL than - * peers from periodic list are used. - * @param adv_sid Advertiser Set ID - * @param params Additional arguments specifying the particulars - * of the synchronization procedure. - * @param cb The callback to associate with this synchrnization - * procedure. BLE_GAP_EVENT_PERIODIC_REPORT events - * are reported only by this callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_periodic_adv_sync_create(const ble_addr_t *addr, uint8_t adv_sid, - const struct ble_gap_periodic_sync_params *params, - ble_gap_event_fn *cb, void *cb_arg); - -/** - * Cancel pending synchronization procedure. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_periodic_adv_sync_create_cancel(void); - -/** - * Terminate synchronization procedure. - * - * @param sync_handle Handle identifying synchronization to terminate. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_periodic_adv_sync_terminate(uint16_t sync_handle); - -#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) -/** - * Disable or enable periodic reports for specified sync. - * - * @param sync_handle Handle identifying synchronization. - * @param enable If reports should be enabled. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_periodic_adv_sync_reporting(uint16_t sync_handle, bool enable); - -/** - * Initialize sync transfer procedure for specified handles. - * - * This allows to transfer periodic sync to which host is synchronized. - * - * @param sync_handle Handle identifying synchronization. - * @param conn_handle Handle identifying connection. - * @param service_data Sync transfer service data - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_periodic_adv_sync_transfer(uint16_t sync_handle, - uint16_t conn_handle, - uint16_t service_data); - -/** - * Initialize set info transfer procedure for specified handles. - * - * This allows to transfer periodic sync which is being advertised by host. - * - * @param instance Advertising instance with periodic adv enabled. - * @param conn_handle Handle identifying connection. - * @param service_data Sync transfer service data - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_periodic_adv_sync_set_info(uint8_t instance, - uint16_t conn_handle, - uint16_t service_data); - -/** - * Enables or disables sync transfer reception on specified connection. - * When sync transfer arrives, BLE_GAP_EVENT_PERIODIC_TRANSFER is sent to the user. - * After that, sync transfer reception on that connection is terminated and user needs - * to call this API again when expect to receive next sync transfers. - * - * Note: If ACL connection gets disconnected before sync transfer arrived, user will - * not receive BLE_GAP_EVENT_PERIODIC_TRANSFER. Instead, sync transfer reception - * is terminated by the host automatically. - * - * @param conn_handle Handle identifying connection. - * @param params Parameters for enabled sync transfer reception. - * Specify NULL to disable reception. - * @param cb The callback to associate with this synchronization - * procedure. BLE_GAP_EVENT_PERIODIC_REPORT events - * are reported only by this callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_periodic_adv_sync_receive(uint16_t conn_handle, - const struct ble_gap_periodic_sync_params *params, - ble_gap_event_fn *cb, void *cb_arg); -#endif - -/** - * Add peer device to periodic synchronization list. - * - * @param addr Peer address to add to list. - * @param adv_sid Advertiser Set ID - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_add_dev_to_periodic_adv_list(const ble_addr_t *peer_addr, - uint8_t adv_sid); - -/** - * Remove peer device from periodic synchronization list. - * - * @param addr Peer address to remove from list. - * @param adv_sid Advertiser Set ID - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_rem_dev_from_periodic_adv_list(const ble_addr_t *peer_addr, - uint8_t adv_sid); - -/** - * Clear periodic synchrnization list. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_clear_periodic_adv_list(void); - -/** - * Get periodic synchronization list size. - * - * @param per_adv_list_size On success list size is stored here. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_read_periodic_adv_list_size(uint8_t *per_adv_list_size); -#endif - - -/** - * Performs the Limited or General Discovery Procedures. - * - * @param own_addr_type The type of address the stack should use for - * itself when sending scan requests. Valid - * values are: - * - BLE_ADDR_TYPE_PUBLIC - * - BLE_ADDR_TYPE_RANDOM - * - BLE_ADDR_TYPE_RPA_PUB_DEFAULT - * - BLE_ADDR_TYPE_RPA_RND_DEFAULT - * This parameter is ignored unless active - * scanning is being used. - * @param duration_ms The duration of the discovery procedure. - * On expiration, the procedure ends and a - * BLE_GAP_EVENT_DISC_COMPLETE event is - * reported. Units are milliseconds. Specify - * BLE_HS_FOREVER for no expiration. Specify - * 0 to use stack defaults. - * @param disc_params Additional arguments specifying the particulars - * of the discovery procedure. - * @param cb The callback to associate with this discovery - * procedure. Advertising reports and - * discovery termination events are reported - * through this callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_disc(uint8_t own_addr_type, int32_t duration_ms, - const struct ble_gap_disc_params *disc_params, - ble_gap_event_fn *cb, void *cb_arg); - -/** - * Performs the Limited or General Extended Discovery Procedures. - * - * @param own_addr_type The type of address the stack should use for - * itself when sending scan requests. Valid - * values are: - * - BLE_ADDR_TYPE_PUBLIC - * - BLE_ADDR_TYPE_RANDOM - * - BLE_ADDR_TYPE_RPA_PUB_DEFAULT - * - BLE_ADDR_TYPE_RPA_RND_DEFAULT - * This parameter is ignored unless active - * scanning is being used. - * @param duration The duration of the discovery procedure. - * On expiration, if period is set to 0, the - * procedure ends and a - * BLE_GAP_EVENT_DISC_COMPLETE event is - * reported. Units are 10 milliseconds. - * Specify 0 for no expiration. - * @param period Time interval from when the Controller started - * its last Scan Duration until it begins the - * subsequent Scan Duration. Specify 0 to scan - * continuously. Units are 1.28 second. - * @param limited If limited discovery procedure should be used. - * @param uncoded_params Additional arguments specifying the particulars - * of the discovery procedure for uncoded PHY. - * If NULL is provided no scan is performed for - * this PHY. - * @param coded_params Additional arguments specifying the particulars - * of the discovery procedure for coded PHY. - * If NULL is provided no scan is performed for - * this PHY. - * @param cb The callback to associate with this discovery - * procedure. Advertising reports and discovery - * termination events are reported through this - * callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_ext_disc(uint8_t own_addr_type, uint16_t duration, uint16_t period, - uint8_t filter_duplicates, uint8_t filter_policy, - uint8_t limited, - const struct ble_gap_ext_disc_params *uncoded_params, - const struct ble_gap_ext_disc_params *coded_params, - ble_gap_event_fn *cb, void *cb_arg); - -/** - * Cancels the discovery procedure currently in progress. A success return - * code indicates that scanning has been fully aborted; a new discovery or - * connect procedure can be initiated immediately. - * - * @return 0 on success; - * BLE_HS_EALREADY if there is no discovery - * procedure to cancel; - * Other nonzero on unexpected error. - */ -int ble_gap_disc_cancel(void); - -/** - * Indicates whether a discovery procedure is currently in progress. - * - * @return 0: No discovery procedure in progress; - * 1: Discovery procedure in progress. - */ -int ble_gap_disc_active(void); - -/** - * Initiates a connect procedure. - * - * @param own_addr_type The type of address the stack should use for - * itself during connection establishment. - * - BLE_OWN_ADDR_PUBLIC - * - BLE_OWN_ADDR_RANDOM - * - BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT - * - BLE_OWN_ADDR_RPA_RANDOM_DEFAULT - * @param peer_addr The address of the peer to connect to. - * If this parameter is NULL, the white list - * is used. - * @param duration_ms The duration of the discovery procedure. - * On expiration, the procedure ends and a - * BLE_GAP_EVENT_DISC_COMPLETE event is - * reported. Units are milliseconds. - * @param conn_params Additional arguments specifying the particulars - * of the connect procedure. Specify null for - * default values. - * @param cb The callback to associate with this connect - * procedure. When the connect procedure - * completes, the result is reported through - * this callback. If the connect procedure - * succeeds, the connection inherits this - * callback as its event-reporting mechanism. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; - * BLE_HS_EALREADY if a connection attempt is - * already in progress; - * BLE_HS_EBUSY if initiating a connection is not - * possible because scanning is in progress; - * BLE_HS_EDONE if the specified peer is already - * connected; - * Other nonzero on error. - */ -int ble_gap_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, - int32_t duration_ms, - const struct ble_gap_conn_params *params, - ble_gap_event_fn *cb, void *cb_arg); - -/** - * Initiates an extended connect procedure. - * - * @param own_addr_type The type of address the stack should use for - * itself during connection establishment. - * - BLE_OWN_ADDR_PUBLIC - * - BLE_OWN_ADDR_RANDOM - * - BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT - * - BLE_OWN_ADDR_RPA_RANDOM_DEFAULT - * @param peer_addr The address of the peer to connect to. - * If this parameter is NULL, the white list - * is used. - * @param duration_ms The duration of the discovery procedure. - * On expiration, the procedure ends and a - * BLE_GAP_EVENT_DISC_COMPLETE event is - * reported. Units are milliseconds. - * @param phy_mask Define on which PHYs connection attempt should - * be done - * @param phy_1m_conn_params Additional arguments specifying the - * particulars of the connect procedure. When - * BLE_GAP_LE_PHY_1M_MASK is set in phy_mask - * this parameter can be specify to null for - * default values. - * @param phy_2m_conn_params Additional arguments specifying the - * particulars of the connect procedure. When - * BLE_GAP_LE_PHY_2M_MASK is set in phy_mask - * this parameter can be specify to null for - * default values. - * @param phy_coded_conn_params Additional arguments specifying the - * particulars of the connect procedure. When - * BLE_GAP_LE_PHY_CODED_MASK is set in - * phy_mask this parameter can be specify to - * null for default values. - * @param cb The callback to associate with this connect - * procedure. When the connect procedure - * completes, the result is reported through - * this callback. If the connect procedure - * succeeds, the connection inherits this - * callback as its event-reporting mechanism. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; - * BLE_HS_EALREADY if a connection attempt is - * already in progress; - * BLE_HS_EBUSY if initiating a connection is not - * possible because scanning is in progress; - * BLE_HS_EDONE if the specified peer is already - * connected; - * Other nonzero on error. - */ -int ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, - int32_t duration_ms, uint8_t phy_mask, - const struct ble_gap_conn_params *phy_1m_conn_params, - const struct ble_gap_conn_params *phy_2m_conn_params, - const struct ble_gap_conn_params *phy_coded_conn_params, - ble_gap_event_fn *cb, void *cb_arg); - -/** - * Aborts a connect procedure in progress. - * - * @return 0 on success; - * BLE_HS_EALREADY if there is no active connect - * procedure. - * Other nonzero on error. - */ -int ble_gap_conn_cancel(void); - -/** - * Indicates whether a connect procedure is currently in progress. - * - * @return 0: No connect procedure in progress; - * 1: Connect procedure in progress. - */ -int ble_gap_conn_active(void); - -/** - * Terminates an established connection. - * - * @param conn_handle The handle corresponding to the connection to - * terminate. - * @param hci_reason The HCI error code to indicate as the reason - * for termination. - * - * @return 0 on success; - * BLE_HS_ENOTCONN if there is no connection with - * the specified handle; - * Other nonzero on failure. - */ -int ble_gap_terminate(uint16_t conn_handle, uint8_t hci_reason); - -/** - * Overwrites the controller's white list with the specified contents. - * - * @param addrs The entries to write to the white list. - * @param white_list_count The number of entries in the white list. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_wl_set(const ble_addr_t *addrs, uint8_t white_list_count); - -/** - * Removes the address from controller's white list. - * - * @param addrs The entry to be removed from the white list. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_wl_tx_rmv(const ble_addr_t *addrs); - -/** - * Initiates a connection parameter update procedure. - * - * @param conn_handle The handle corresponding to the connection to - * update. - * @param params The connection parameters to attempt to update - * to. - * - * @return 0 on success; - * BLE_HS_ENOTCONN if the there is no connection - * with the specified handle; - * BLE_HS_EALREADY if a connection update - * procedure for this connection is already in - * progress; - * BLE_HS_EINVAL if requested parameters are - * invalid; - * Other nonzero on error. - */ -int ble_gap_update_params(uint16_t conn_handle, - const struct ble_gap_upd_params *params); - -/** - * Configure LE Data Length in controller (OGF = 0x08, OCF = 0x0022). - * - * @param conn_handle Connection handle. - * @param tx_octets The preferred value of payload octets that the Controller - * should use for a new connection (Range - * 0x001B-0x00FB). - * @param tx_time The preferred maximum number of microseconds that the local Controller - * should use to transmit a single link layer packet - * (Range 0x0148-0x4290). - * - * @return 0 on success, - * other error code on failure. - */ -int ble_gap_set_data_len(uint16_t conn_handle, uint16_t tx_octets, uint16_t tx_time); - -/** - * Read LE Suggested Default Data Length in controller (OGF = 0x08, OCF = 0x0024). - * - * @param out_sugg_max_tx_octets The Host's suggested value for the Controller's maximum transmitted - * number of payload octets in LL Data PDUs to be used for new - * connections. (Range 0x001B-0x00FB). - * @param out_sugg_max_tx_time The Host's suggested value for the Controller's maximum packet - * transmission time for packets containing LL Data PDUs to be used - * for new connections. (Range 0x0148-0x4290). - * - * @return 0 on success, - * other error code on failure. - */ -int ble_gap_read_sugg_def_data_len(uint16_t *out_sugg_max_tx_octets, - uint16_t *out_sugg_max_tx_time); - -/** - * Configure LE Suggested Default Data Length in controller (OGF = 0x08, OCF = 0x0024). - * - * @param sugg_max_tx_octets The Host's suggested value for the Controller's maximum transmitted - * number of payload octets in LL Data PDUs to be used for new - * connections. (Range 0x001B-0x00FB). - * @param sugg_max_tx_time The Host's suggested value for the Controller's maximum packet - * transmission time for packets containing LL Data PDUs to be used - * for new connections. (Range 0x0148-0x4290). - * - * @return 0 on success, - * other error code on failure. - */ -int ble_gap_write_sugg_def_data_len(uint16_t sugg_max_tx_octets, uint16_t sugg_max_tx_time); - -/** - * Initiates the GAP security procedure. - * - * Depending on connection role and stored security information this function - * will start appropriate security procedure (pairing or encryption). - * - * @param conn_handle The handle corresponding to the connection to - * secure. - * - * @return 0 on success; - * BLE_HS_ENOTCONN if the there is no connection - * with the specified handle; - * BLE_HS_EALREADY if an security procedure for - * this connection is already in progress; - * Other nonzero on error. - */ -int ble_gap_security_initiate(uint16_t conn_handle); - -/** - * Initiates the GAP pairing procedure as a master. This is for testing only and - * should not be used by application. Use ble_gap_security_initiate() instead. - * - * @param conn_handle The handle corresponding to the connection to - * start pairing on. - * - * @return 0 on success; - * BLE_HS_ENOTCONN if the there is no connection - * with the specified handle; - * BLE_HS_EALREADY if an pairing procedure for - * this connection is already in progress; - * Other nonzero on error. - */ -int ble_gap_pair_initiate(uint16_t conn_handle); - -/** - * Initiates the GAP encryption procedure as a master. This is for testing only - * and should not be used by application. Use ble_gap_security_initiate() - * instead. - * - * @param conn_handle The handle corresponding to the connection to - * start encryption. - * @param key_size Encryption key size - * @param ltk Long Term Key to be used for encryption. - * @param udiv Encryption Diversifier for LTK - * @param rand_val Random Value for EDIV and LTK - * @param auth If LTK provided is authenticated. - * - * @return 0 on success; - * BLE_HS_ENOTCONN if the there is no connection - * with the specified handle; - * BLE_HS_EALREADY if an encryption procedure for - * this connection is already in progress; - * Other nonzero on error. - */ -int ble_gap_encryption_initiate(uint16_t conn_handle, uint8_t key_size, - const uint8_t *ltk, uint16_t ediv, - uint64_t rand_val, int auth); - -/** - * Retrieves the most-recently measured RSSI for the specified connection. A - * connection's RSSI is updated whenever a data channel PDU is received. - * - * @param conn_handle Specifies the connection to query. - * @param out_rssi On success, the retrieved RSSI is written here. - * - * @return 0 on success; - * A BLE host HCI return code if the controller - * rejected the request; - * A BLE host core return code on unexpected - * error. - */ -int ble_gap_conn_rssi(uint16_t conn_handle, int8_t *out_rssi); - -/** - * Unpairs a device with the specified address. The keys related to that peer - * device are removed from storage and peer address is removed from the resolve - * list from the controller. If a peer is connected, the connection is terminated. - * - * @param peer_addr Address of the device to be unpaired - * - * @return 0 on success; - * A BLE host HCI return code if the controller - * rejected the request; - * A BLE host core return code on unexpected - * error. - */ -int ble_gap_unpair(const ble_addr_t *peer_addr); - -/** - * Unpairs the oldest bonded peer device. The keys related to that peer - * device are removed from storage and peer address is removed from the resolve - * list from the controller. If a peer is connected, the connection is terminated. - * - * @return 0 on success; - * A BLE host HCI return code if the controller - * rejected the request; - * A BLE host core return code on unexpected - * error. - */ -int ble_gap_unpair_oldest_peer(void); - -/** - * Similar to `ble_gap_unpair_oldest_peer()`, except it makes sure that the - * peer received in input parameters is not deleted. - * - * @param peer_addr Address of the peer (not to be deleted) - * - * @return 0 on success; - * A BLE host HCI return code if the controller - * rejected the request; - * A BLE host core return code on unexpected - * error. - */ -int ble_gap_unpair_oldest_except(const ble_addr_t *peer_addr); - -#define BLE_GAP_PRIVATE_MODE_NETWORK 0 -#define BLE_GAP_PRIVATE_MODE_DEVICE 1 - -/** - * Set privacy mode for specified peer device - * - * @param peer_addr Peer device address - * @param priv_mode Privacy mode to be used. Can be one of following - * constants: - * - BLE_GAP_PRIVATE_MODE_NETWORK - * - BLE_GAP_PRIVATE_MODE_DEVICE - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_set_priv_mode(const ble_addr_t *peer_addr, uint8_t priv_mode); - -#define BLE_GAP_LE_PHY_1M 1 -#define BLE_GAP_LE_PHY_2M 2 -#define BLE_GAP_LE_PHY_CODED 3 -/** - * Read PHYs used for specified connection. - * - * On success output parameters are filled with information about used PHY type. - * - * @param conn_handle Connection handle - * @param tx_phy TX PHY used. Can be one of following constants: - * - BLE_GAP_LE_PHY_1M - * - BLE_GAP_LE_PHY_2M - * - BLE_GAP_LE_PHY_CODED - * @param rx_phy RX PHY used. Can be one of following constants: - * - BLE_GAP_LE_PHY_1M - * - BLE_GAP_LE_PHY_2M - * - BLE_GAP_LE_PHY_CODED - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_read_le_phy(uint16_t conn_handle, uint8_t *tx_phy, uint8_t *rx_phy); - -#define BLE_GAP_LE_PHY_1M_MASK 0x01 -#define BLE_GAP_LE_PHY_2M_MASK 0x02 -#define BLE_GAP_LE_PHY_CODED_MASK 0x04 -#define BLE_GAP_LE_PHY_ANY_MASK 0x0F -/** - * Set preferred default PHYs to be used for connections. - * - * @params tx_phys_mask Preferred TX PHY. Can be mask of following - * constants: - * - BLE_GAP_LE_PHY_1M_MASK - * - BLE_GAP_LE_PHY_2M_MASK - * - BLE_GAP_LE_PHY_CODED_MASK - * - BLE_GAP_LE_PHY_ANY_MASK - * @params rx_phys_mask Preferred RX PHY. Can be mask of following - * constants: - * - BLE_GAP_LE_PHY_1M_MASK - * - BLE_GAP_LE_PHY_2M_MASK - * - BLE_GAP_LE_PHY_CODED_MASK - * - BLE_GAP_LE_PHY_ANY_MASK - - * @return 0 on success; nonzero on failure. - */ -int ble_gap_set_prefered_default_le_phy(uint8_t tx_phys_mask, - uint8_t rx_phys_mask); - -#define BLE_GAP_LE_PHY_CODED_ANY 0 -#define BLE_GAP_LE_PHY_CODED_S2 1 -#define BLE_GAP_LE_PHY_CODED_S8 2 -/** - * Set preferred PHYs to be used for connection. - * - * @param conn_handle Connection handle - * @params tx_phys_mask Preferred TX PHY. Can be mask of following - * constants: - * - BLE_GAP_LE_PHY_1M_MASK - * - BLE_GAP_LE_PHY_2M_MASK - * - BLE_GAP_LE_PHY_CODED_MASK - * - BLE_GAP_LE_PHY_ANY_MASK - * @params rx_phys_mask Preferred RX PHY. Can be mask of following - * constants: - * - BLE_GAP_LE_PHY_1M_MASK - * - BLE_GAP_LE_PHY_2M_MASK - * - BLE_GAP_LE_PHY_CODED_MASK - * - BLE_GAP_LE_PHY_ANY_MASK - * @param phy_opts Additional PHY options. Valid values are: - * - BLE_GAP_LE_PHY_CODED_ANY - * - BLE_GAP_LE_PHY_CODED_S2 - * - BLE_GAP_LE_PHY_CODED_S8 - * - * @return 0 on success; nonzero on failure. - */ -int ble_gap_set_prefered_le_phy(uint16_t conn_handle, uint8_t tx_phys_mask, - uint8_t rx_phys_mask, uint16_t phy_opts); - -/** - * Event listener structure - * - * This should be used as an opaque structure and not modified manually. - */ -struct ble_gap_event_listener { - ble_gap_event_fn *fn; - void *arg; - SLIST_ENTRY(ble_gap_event_listener) link; -}; - -/** - * Registers listener for GAP events - * - * On success listener structure will be initialized automatically and does not - * need to be initialized prior to calling this function. To change callback - * and/or argument unregister listener first and register it again. - * - * @param listener Listener structure - * @param fn Callback function - * @param arg Callback argument - * - * @return 0 on success - * BLE_HS_EINVAL if no callback is specified - * BLE_HS_EALREADY if listener is already registered - */ -int ble_gap_event_listener_register(struct ble_gap_event_listener *listener, - ble_gap_event_fn *fn, void *arg); - -/** - * Unregisters listener for GAP events - * - * @param listener Listener structure - * - * @return 0 on success - * BLE_HS_ENOENT if listener was not registered - */ -int ble_gap_event_listener_unregister(struct ble_gap_event_listener *listener); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_gatt.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_gatt.h deleted file mode 100644 index ee8f177f8..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_gatt.h +++ /dev/null @@ -1,902 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_GATT_ -#define H_BLE_GATT_ - -/** - * @brief Bluetooth Generic Attribute Profile (GATT) - * @defgroup bt_gatt Bluetooth Generic Attribute Profile (GATT) - * @ingroup bt_host - * @{ - */ - -#include -#include "ble_att.h" -#include "ble_uuid.h" -#ifdef __cplusplus -extern "C" { -#endif - -struct ble_hs_conn; -struct ble_att_error_rsp; -struct ble_hs_cfg; - -#define BLE_GATT_REGISTER_OP_SVC 1 -#define BLE_GATT_REGISTER_OP_CHR 2 -#define BLE_GATT_REGISTER_OP_DSC 3 - -#define BLE_GATT_SVC_UUID16 0x1801 -#define BLE_GATT_DSC_CLT_CFG_UUID16 0x2902 - -#define BLE_GATT_CHR_PROP_BROADCAST 0x01 -#define BLE_GATT_CHR_PROP_READ 0x02 -#define BLE_GATT_CHR_PROP_WRITE_NO_RSP 0x04 -#define BLE_GATT_CHR_PROP_WRITE 0x08 -#define BLE_GATT_CHR_PROP_NOTIFY 0x10 -#define BLE_GATT_CHR_PROP_INDICATE 0x20 -#define BLE_GATT_CHR_PROP_AUTH_SIGN_WRITE 0x40 -#define BLE_GATT_CHR_PROP_EXTENDED 0x80 - -#define BLE_GATT_ACCESS_OP_READ_CHR 0 -#define BLE_GATT_ACCESS_OP_WRITE_CHR 1 -#define BLE_GATT_ACCESS_OP_READ_DSC 2 -#define BLE_GATT_ACCESS_OP_WRITE_DSC 3 - -#define BLE_GATT_CHR_F_BROADCAST 0x0001 -#define BLE_GATT_CHR_F_READ 0x0002 -#define BLE_GATT_CHR_F_WRITE_NO_RSP 0x0004 -#define BLE_GATT_CHR_F_WRITE 0x0008 -#define BLE_GATT_CHR_F_NOTIFY 0x0010 -#define BLE_GATT_CHR_F_INDICATE 0x0020 -#define BLE_GATT_CHR_F_AUTH_SIGN_WRITE 0x0040 -#define BLE_GATT_CHR_F_RELIABLE_WRITE 0x0080 -#define BLE_GATT_CHR_F_AUX_WRITE 0x0100 -#define BLE_GATT_CHR_F_READ_ENC 0x0200 -#define BLE_GATT_CHR_F_READ_AUTHEN 0x0400 -#define BLE_GATT_CHR_F_READ_AUTHOR 0x0800 -#define BLE_GATT_CHR_F_WRITE_ENC 0x1000 -#define BLE_GATT_CHR_F_WRITE_AUTHEN 0x2000 -#define BLE_GATT_CHR_F_WRITE_AUTHOR 0x4000 - -#define BLE_GATT_SVC_TYPE_END 0 -#define BLE_GATT_SVC_TYPE_PRIMARY 1 -#define BLE_GATT_SVC_TYPE_SECONDARY 2 - -/*** @client. */ -struct ble_gatt_error { - uint16_t status; - uint16_t att_handle; -}; - -struct ble_gatt_svc { - uint16_t start_handle; - uint16_t end_handle; - ble_uuid_any_t uuid; -}; - -struct ble_gatt_attr { - uint16_t handle; - uint16_t offset; - struct os_mbuf *om; -}; - -struct ble_gatt_chr { - uint16_t def_handle; - uint16_t val_handle; - uint8_t properties; - ble_uuid_any_t uuid; -}; - -struct ble_gatt_dsc { - uint16_t handle; - ble_uuid_any_t uuid; -}; - -typedef int ble_gatt_mtu_fn(uint16_t conn_handle, - const struct ble_gatt_error *error, - uint16_t mtu, void *arg); -typedef int ble_gatt_disc_svc_fn(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_svc *service, - void *arg); - -/** - * The host will free the attribute mbuf automatically after the callback is - * executed. The application can take ownership of the mbuf and prevent it - * from being freed by assigning NULL to attr->om. - */ -typedef int ble_gatt_attr_fn(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, - void *arg); - -/** - * The host will free the attribute mbufs automatically after the callback is - * executed. The application can take ownership of the mbufs and prevent them - * from being freed by assigning NULL to each attribute's om field. - */ -typedef int ble_gatt_reliable_attr_fn(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attrs, - uint8_t num_attrs, void *arg); - -typedef int ble_gatt_chr_fn(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_chr *chr, void *arg); - -typedef int ble_gatt_dsc_fn(uint16_t conn_handle, - const struct ble_gatt_error *error, - uint16_t chr_val_handle, - const struct ble_gatt_dsc *dsc, - void *arg); - -/** - * Initiates GATT procedure: Exchange MTU. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_exchange_mtu(uint16_t conn_handle, - ble_gatt_mtu_fn *cb, void *cb_arg); - -/** - * Initiates GATT procedure: Discover All Primary Services. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - */ -int ble_gattc_disc_all_svcs(uint16_t conn_handle, - ble_gatt_disc_svc_fn *cb, void *cb_arg); - -/** - * Initiates GATT procedure: Discover Primary Service by Service UUID. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param service_uuid128 The 128-bit UUID of the service to discover. - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_disc_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *uuid, - ble_gatt_disc_svc_fn *cb, void *cb_arg); - -/** - * Initiates GATT procedure: Find Included Services. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param start_handle The handle to begin the search at (generally - * the service definition handle). - * @param end_handle The handle to end the search at (generally the - * last handle in the service). - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_find_inc_svcs(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle, - ble_gatt_disc_svc_fn *cb, void *cb_arg); - -/** - * Initiates GATT procedure: Discover All Characteristics of a Service. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param start_handle The handle to begin the search at (generally - * the service definition handle). - * @param end_handle The handle to end the search at (generally the - * last handle in the service). - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle, ble_gatt_chr_fn *cb, - void *cb_arg); - -/** - * Initiates GATT procedure: Discover Characteristics by UUID. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param start_handle The handle to begin the search at (generally - * the service definition handle). - * @param end_handle The handle to end the search at (generally the - * last handle in the service). - * @param chr_uuid128 The 128-bit UUID of the characteristic to - * discover. - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle, const ble_uuid_t *uuid, - ble_gatt_chr_fn *cb, void *cb_arg); - -/** - * Initiates GATT procedure: Discover All Characteristic Descriptors. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param chr_val_handle The handle of the characteristic value - * attribute. - * @param chr_end_handle The last handle in the characteristic - * definition. - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle, - ble_gatt_dsc_fn *cb, void *cb_arg); - -/** - * Initiates GATT procedure: Read Characteristic Value. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param attr_handle The handle of the characteristic value to read. - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_read(uint16_t conn_handle, uint16_t attr_handle, - ble_gatt_attr_fn *cb, void *cb_arg); - -/** - * Initiates GATT procedure: Read Using Characteristic UUID. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param start_handle The first handle to search (generally the - * handle of the service definition). - * @param end_handle The last handle to search (generally the - * last handle in the service definition). - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle, const ble_uuid_t *uuid, - ble_gatt_attr_fn *cb, void *cb_arg); - -/** - * Initiates GATT procedure: Read Long Characteristic Values. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param handle The handle of the characteristic value to read. - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_read_long(uint16_t conn_handle, uint16_t handle, uint16_t offset, - ble_gatt_attr_fn *cb, void *cb_arg); - -/** - * Initiates GATT procedure: Read Multiple Characteristic Values. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param handles An array of 16-bit attribute handles to read. - * @param num_handles The number of entries in the "handles" array. - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, - uint8_t num_handles, ble_gatt_attr_fn *cb, - void *cb_arg); - -/** - * Initiates GATT procedure: Write Without Response. This function consumes - * the supplied mbuf regardless of the outcome. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param attr_handle The handle of the characteristic value to write - * to. - * @param txom The value to write to the characteristic. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle, - struct os_mbuf *om); - -/** - * Initiates GATT procedure: Write Without Response. This function consumes - * the supplied mbuf regardless of the outcome. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param attr_handle The handle of the characteristic value to write - * to. - * @param value The value to write to the characteristic. - * @param value_len The number of bytes to write. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_write_no_rsp_flat(uint16_t conn_handle, uint16_t attr_handle, - const void *data, uint16_t data_len); - -/** - * Initiates GATT procedure: Write Characteristic Value. This function - * consumes the supplied mbuf regardless of the outcome. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param attr_handle The handle of the characteristic value to write - * to. - * @param txom The value to write to the characteristic. - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, - struct os_mbuf *om, - ble_gatt_attr_fn *cb, void *cb_arg); - -/** - * Initiates GATT procedure: Write Characteristic Value (flat buffer version). - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param attr_handle The handle of the characteristic value to write - * to. - * @param value The value to write to the characteristic. - * @param value_len The number of bytes to write. - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_write_flat(uint16_t conn_handle, uint16_t attr_handle, - const void *data, uint16_t data_len, - ble_gatt_attr_fn *cb, void *cb_arg); - -/** - * Initiates GATT procedure: Write Long Characteristic Values. This function - * consumes the supplied mbuf regardless of the outcome. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param attr_handle The handle of the characteristic value to write - * to. - * @param txom The value to write to the characteristic. - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle, - uint16_t offset, struct os_mbuf *om, - ble_gatt_attr_fn *cb, void *cb_arg); - -/** - * Initiates GATT procedure: Reliable Writes. This function consumes the - * supplied mbufs regardless of the outcome. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param attrs An array of attribute descriptors; specifies - * which characteristics to write to and what - * data to write to them. The mbuf pointer in - * each attribute is set to NULL by this - * function. - * @param num_attrs The number of characteristics to write; equal - * to the number of elements in the 'attrs' - * array. - * @param cb The function to call to report procedure status - * updates; null for no callback. - * @param cb_arg The optional argument to pass to the callback - * function. - */ -int ble_gattc_write_reliable(uint16_t conn_handle, - struct ble_gatt_attr *attrs, - int num_attrs, ble_gatt_reliable_attr_fn *cb, - void *cb_arg); - -/** - * Sends a "free-form" characteristic notification. This function consumes the - * supplied mbuf regardless of the outcome. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param chr_val_handle The attribute handle to indicate in the - * outgoing notification. - * @param txom The value to write to the characteristic. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_notify_custom(uint16_t conn_handle, uint16_t att_handle, - struct os_mbuf *om); - -/** - * Sends a characteristic notification. The content of the message is read - * from the specified characteristic. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param chr_val_handle The value attribute handle of the - * characteristic to include in the outgoing - * notification. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle); - -/** - * Sends a "free-form" characteristic indication. The provided mbuf contains - * the indication payload. This function consumes the supplied mbuf regardless - * of the outcome. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param chr_val_handle The value attribute handle of the - * characteristic to include in the outgoing - * indication. - * @param txom The data to include in the indication. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle, - struct os_mbuf *txom); - -/** - * Sends a characteristic indication. The content of the message is read from - * the specified characteristic. - * - * @param conn_handle The connection over which to execute the - * procedure. - * @param chr_val_handle The value attribute handle of the - * characteristic to include in the outgoing - * indication. - * - * @return 0 on success; nonzero on failure. - */ -int ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle); - -int ble_gattc_init(void); - -/*** @server. */ - -struct ble_gatt_access_ctxt; -typedef int ble_gatt_access_fn(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg); - -typedef uint16_t ble_gatt_chr_flags; - -struct ble_gatt_chr_def { - /** - * Pointer to characteristic UUID; use BLE_UUIDxx_DECLARE macros to declare - * proper UUID; NULL if there are no more characteristics in the service. - */ - const ble_uuid_t *uuid; - - /** - * Callback that gets executed when this characteristic is read or - * written. - */ - ble_gatt_access_fn *access_cb; - - /** Optional argument for callback. */ - void *arg; - - /** - * Array of this characteristic's descriptors. NULL if no descriptors. - * Do not include CCCD; it gets added automatically if this - * characteristic's notify or indicate flag is set. - */ - struct ble_gatt_dsc_def *descriptors; - - /** Specifies the set of permitted operations for this characteristic. */ - ble_gatt_chr_flags flags; - - /** Specifies minimum required key size to access this characteristic. */ - uint8_t min_key_size; - - /** - * At registration time, this is filled in with the characteristic's value - * attribute handle. - */ - uint16_t *val_handle; -}; - -struct ble_gatt_svc_def { - /** - * One of the following: - * o BLE_GATT_SVC_TYPE_PRIMARY - primary service - * o BLE_GATT_SVC_TYPE_SECONDARY - secondary service - * o 0 - No more services in this array. - */ - uint8_t type; - - /** - * Pointer to service UUID; use BLE_UUIDxx_DECLARE macros to declare - * proper UUID; NULL if there are no more characteristics in the service. - */ - const ble_uuid_t *uuid; - - /** - * Array of pointers to other service definitions. These services are - * reported as "included services" during service discovery. Terminate the - * array with NULL. - */ - const struct ble_gatt_svc_def **includes; - - /** - * Array of characteristic definitions corresponding to characteristics - * belonging to this service. - */ - const struct ble_gatt_chr_def *characteristics; -}; - -struct ble_gatt_dsc_def { - /** - * Pointer to descriptor UUID; use BLE_UUIDxx_DECLARE macros to declare - * proper UUID; NULL if there are no more characteristics in the service. - */ - const ble_uuid_t *uuid; - - /** Specifies the set of permitted operations for this descriptor. */ - uint8_t att_flags; - - /** Specifies minimum required key size to access this descriptor. */ - uint8_t min_key_size; - - /** Callback that gets executed when the descriptor is read or written. */ - ble_gatt_access_fn *access_cb; - - /** Optional argument for callback. */ - void *arg; -}; - -/** - * Context for an access to a GATT characteristic or descriptor. When a client - * reads or writes a locally registered characteristic or descriptor, an - * instance of this struct gets passed to the application callback. - */ -struct ble_gatt_access_ctxt { - /** - * Indicates the gatt operation being performed. This is equal to one of - * the following values: - * o BLE_GATT_ACCESS_OP_READ_CHR - * o BLE_GATT_ACCESS_OP_WRITE_CHR - * o BLE_GATT_ACCESS_OP_READ_DSC - * o BLE_GATT_ACCESS_OP_WRITE_DSC - */ - uint8_t op; - - /** - * A container for the GATT access data. - * o For reads: The application populates this with the value of the - * characteristic or descriptor being read. - * o For writes: This is already populated with the value being written - * by the peer. If the application wishes to retain this mbuf for - * later use, the access callback must set this pointer to NULL to - * prevent the stack from freeing it. - */ - struct os_mbuf *om; - - /** - * The GATT operation being performed dictates which field in this union is - * valid. If a characteristic is being accessed, the chr field is valid. - * Otherwise a descriptor is being accessed, in which case the dsc field - * is valid. - */ - union { - /** - * The characteristic definition corresponding to the characteristic - * being accessed. This is what the app registered at startup. - */ - const struct ble_gatt_chr_def *chr; - - /** - * The descriptor definition corresponding to the descriptor being - * accessed. This is what the app registered at startup. - */ - const struct ble_gatt_dsc_def *dsc; - }; -}; - -/** - * Context passed to the registration callback; represents the GATT service, - * characteristic, or descriptor being registered. - */ -struct ble_gatt_register_ctxt { - /** - * Indicates the gatt registration operation just performed. This is - * equal to one of the following values: - * o BLE_GATT_REGISTER_OP_SVC - * o BLE_GATT_REGISTER_OP_CHR - * o BLE_GATT_REGISTER_OP_DSC - */ - uint8_t op; - - /** - * The value of the op field determines which field in this union is valid. - */ - union { - /** Service; valid if op == BLE_GATT_REGISTER_OP_SVC. */ - struct { - /** The ATT handle of the service definition attribute. */ - uint16_t handle; - - /** - * The service definition representing the service being - * registered. - */ - const struct ble_gatt_svc_def *svc_def; - } svc; - - /** Characteristic; valid if op == BLE_GATT_REGISTER_OP_CHR. */ - struct { - /** The ATT handle of the characteristic definition attribute. */ - uint16_t def_handle; - - /** The ATT handle of the characteristic value attribute. */ - uint16_t val_handle; - - /** - * The characteristic definition representing the characteristic - * being registered. - */ - const struct ble_gatt_chr_def *chr_def; - - /** - * The service definition corresponding to the characteristic's - * parent service. - */ - const struct ble_gatt_svc_def *svc_def; - } chr; - - /** Descriptor; valid if op == BLE_GATT_REGISTER_OP_DSC. */ - struct { - /** The ATT handle of the descriptor definition attribute. */ - uint16_t handle; - - /** - * The descriptor definition corresponding to the descriptor being - * registered. - */ - const struct ble_gatt_dsc_def *dsc_def; - - /** - * The characteristic definition corresponding to the descriptor's - * parent characteristic. - */ - const struct ble_gatt_chr_def *chr_def; - - /** - * The service definition corresponding to the descriptor's - * grandparent service - */ - const struct ble_gatt_svc_def *svc_def; - } dsc; - }; -}; - -typedef void ble_gatt_register_fn(struct ble_gatt_register_ctxt *ctxt, - void *arg); - -/** - * Queues a set of service definitions for registration. All services queued - * in this manner get registered when ble_gatts_start() is called. - * - * @param svcs An array of service definitions to queue for - * registration. This array must be - * terminated with an entry whose 'type' - * equals 0. - * - * @return 0 on success; - * BLE_HS_ENOMEM on heap exhaustion. - */ -int ble_gatts_add_svcs(const struct ble_gatt_svc_def *svcs); - -/** - * Set visibility of local GATT service. Invisible services are not removed - * from database but are not discoverable by peer devices. Service Changed - * should be handled by application when needed by calling - * ble_svc_gatt_changed(). - * - * @param handle Handle of service - * @param visible non-zero if service should be visible - * - * @return 0 on success; - * BLE_HS_ENOENT if service wasn't found. - */ -int ble_gatts_svc_set_visibility(uint16_t handle, int visible); - -/** - * Adjusts a host configuration object's settings to accommodate the specified - * service definition array. This function adds the counts to the appropriate - * fields in the supplied configuration object without clearing them first, so - * it can be called repeatedly with different inputs to calculate totals. Be - * sure to zero the GATT server settings prior to the first call to this - * function. - * - * @param defs The service array containing the resource - * definitions to be counted. - * - * @return 0 on success; - * BLE_HS_EINVAL if the svcs array contains an - * invalid resource definition. - */ -int ble_gatts_count_cfg(const struct ble_gatt_svc_def *defs); - -/** - * Send notification (or indication) to any connected devices that have - * subscribed for notification (or indication) for specified characteristic. - * - * @param chr_val_handle Characteristic value handle - */ -void ble_gatts_chr_updated(uint16_t chr_val_handle); - -/** - * Retrieves the attribute handle associated with a local GATT service. - * - * @param uuid The UUID of the service to look up. - * @param out_handle On success, populated with the handle of the - * service attribute. Pass null if you don't - * need this value. - * - * @return 0 on success; - * BLE_HS_ENOENT if the specified service could - * not be found. - */ -int ble_gatts_find_svc(const ble_uuid_t *uuid, uint16_t *out_handle); - -/** - * Retrieves the pair of attribute handles associated with a local GATT - * characteristic. - * - * @param svc_uuid The UUID of the parent service. - * @param chr_uuid The UUID of the characteristic to look up. - * @param out_def_handle On success, populated with the handle - * of the characteristic definition attribute. - * Pass null if you don't need this value. - * @param out_val_handle On success, populated with the handle - * of the characteristic value attribute. - * Pass null if you don't need this value. - * - * @return 0 on success; - * BLE_HS_ENOENT if the specified service or - * characteristic could not be found. - */ -int ble_gatts_find_chr(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid, - uint16_t *out_def_handle, uint16_t *out_val_handle); - -/** - * Retrieves the attribute handle associated with a local GATT descriptor. - * - * @param svc_uuid The UUID of the grandparent service. - * @param chr_uuid The UUID of the parent characteristic. - * @param dsc_uuid The UUID of the descriptor ro look up. - * @param out_handle On success, populated with the handle - * of the descriptor attribute. Pass null if - * you don't need this value. - * - * @return 0 on success; - * BLE_HS_ENOENT if the specified service, - * characteristic, or descriptor could not be - * found. - */ -int ble_gatts_find_dsc(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid, - const ble_uuid_t *dsc_uuid, uint16_t *out_dsc_handle); - -typedef void (*ble_gatt_svc_foreach_fn)(const struct ble_gatt_svc_def *svc, - uint16_t handle, - uint16_t end_group_handle, - void *arg); - -/** - * Prints dump of local GATT database. This is useful to log local state of - * database in human readable form. - */ -void ble_gatts_show_local(void); - -/** - * Resets the GATT server to its initial state. On success, this function - * removes all supported services, characteristics, and descriptors. This - * function requires that: - * o No peers are connected, and - * o No GAP operations are active (advertise, discover, or connect). - * - * @return 0 on success; - * BLE_HS_EBUSY if the GATT server could not be - * reset due to existing connections or active - * GAP procedures. - */ -int ble_gatts_reset(void); - -/** - * Makes all registered services available to peers. This function gets called - * automatically by the NimBLE host on startup; manual calls are only necessary - * for replacing the set of supported services with a new one. This function - * requires that: - * o No peers are connected, and - * o No GAP operations are active (advertise, discover, or connect). - * - * @return 0 on success; - * A BLE host core return code on unexpected - * error. - */ -int ble_gatts_start(void); - -/** - * Resets the GATT configuration parameters and deallocates the memory of attributes. - * - */ -void ble_gatts_stop(void); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs.h deleted file mode 100644 index f24b8a9e0..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs.h +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_HS_ -#define H_BLE_HS_ - -/** - * @brief Bluetooth Host - * @defgroup bt_host Bluetooth Host - * @{ - */ - -#include -#include "nimble/nimble/include/nimble/hci_common.h" -#include "ble_att.h" -#include "ble_eddystone.h" -#include "ble_gap.h" -#include "ble_gatt.h" -#include "ble_hs_adv.h" -#include "ble_hs_id.h" -#include "ble_hs_hci.h" -#include "ble_hs_log.h" -#include "ble_hs_mbuf.h" -#include "ble_hs_stop.h" -#include "ble_ibeacon.h" -#include "ble_l2cap.h" -#include "ble_sm.h" -#include "ble_store.h" -#include "ble_uuid.h" -#include "nimble/nimble/include/nimble/nimble_npl.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define BLE_HS_FOREVER INT32_MAX - -/** Connection handle not present */ -#define BLE_HS_CONN_HANDLE_NONE 0xffff - -/** - * @brief Bluetooth Host Error Code - * @defgroup bt_host_err Bluetooth Host Error Code - * - * Defines error codes returned by Bluetooth host. If error comes from specific - * component (eg L2CAP or Security Manager) it is shifted by base allowing to - * identify component. - * @{ - */ - -#define BLE_HS_EAGAIN 1 -#define BLE_HS_EALREADY 2 -#define BLE_HS_EINVAL 3 -#define BLE_HS_EMSGSIZE 4 -#define BLE_HS_ENOENT 5 -#define BLE_HS_ENOMEM 6 -#define BLE_HS_ENOTCONN 7 -#define BLE_HS_ENOTSUP 8 -#define BLE_HS_EAPP 9 -#define BLE_HS_EBADDATA 10 -#define BLE_HS_EOS 11 -#define BLE_HS_ECONTROLLER 12 -#define BLE_HS_ETIMEOUT 13 -#define BLE_HS_EDONE 14 -#define BLE_HS_EBUSY 15 -#define BLE_HS_EREJECT 16 -#define BLE_HS_EUNKNOWN 17 -#define BLE_HS_EROLE 18 -#define BLE_HS_ETIMEOUT_HCI 19 -#define BLE_HS_ENOMEM_EVT 20 -#define BLE_HS_ENOADDR 21 -#define BLE_HS_ENOTSYNCED 22 -#define BLE_HS_EAUTHEN 23 -#define BLE_HS_EAUTHOR 24 -#define BLE_HS_EENCRYPT 25 -#define BLE_HS_EENCRYPT_KEY_SZ 26 -#define BLE_HS_ESTORE_CAP 27 -#define BLE_HS_ESTORE_FAIL 28 -#define BLE_HS_EPREEMPTED 29 -#define BLE_HS_EDISABLED 30 -#define BLE_HS_ESTALLED 31 - -/** Error base for ATT errors */ -#define BLE_HS_ERR_ATT_BASE 0x100 - -/** Converts error to ATT base */ -#define BLE_HS_ATT_ERR(x) ((x) ? BLE_HS_ERR_ATT_BASE + (x) : 0) - -/** Error base for HCI errors */ -#define BLE_HS_ERR_HCI_BASE 0x200 - -/** Converts error to HCI base */ -#define BLE_HS_HCI_ERR(x) ((x) ? BLE_HS_ERR_HCI_BASE + (x) : 0) - -/** Error base for L2CAP errors */ -#define BLE_HS_ERR_L2C_BASE 0x300 - -/** Converts error to L2CAP base */ -#define BLE_HS_L2C_ERR(x) ((x) ? BLE_HS_ERR_L2C_BASE + (x) : 0) - -/** Error base for local Security Manager errors */ -#define BLE_HS_ERR_SM_US_BASE 0x400 - -/** Converts error to local Security Manager base */ -#define BLE_HS_SM_US_ERR(x) ((x) ? BLE_HS_ERR_SM_US_BASE + (x) : 0) - -/** Error base for remote (peer) Security Manager errors */ -#define BLE_HS_ERR_SM_PEER_BASE 0x500 - -/** Converts error to remote (peer) Security Manager base */ -#define BLE_HS_SM_PEER_ERR(x) ((x) ? BLE_HS_ERR_SM_PEER_BASE + (x) : 0) - -/** Error base for hardware errors */ -#define BLE_HS_ERR_HW_BASE 0x600 - -/** Converts error to hardware error base */ -#define BLE_HS_HW_ERR(x) (BLE_HS_ERR_HW_BASE + (x)) - -/** - * @} - */ - -/** - * @brief Bluetooth Host Configuration - * @defgroup bt_host_conf Bluetooth Host Configuration - * - * @{ - */ - -/** - * @brief Local Input-Output capabilities of device - * @defgroup bt_host_io_local Local Input-Output capabilities of device - * - * @{ - */ - -/** DisplayOnly IO capability */ -#define BLE_HS_IO_DISPLAY_ONLY 0x00 - -/** DisplayYesNo IO capability */ -#define BLE_HS_IO_DISPLAY_YESNO 0x01 - -/** KeyboardOnly IO capability */ -#define BLE_HS_IO_KEYBOARD_ONLY 0x02 - -/** NoInputNoOutput IO capability */ -#define BLE_HS_IO_NO_INPUT_OUTPUT 0x03 - -/** KeyboardDisplay Only IO capability */ -#define BLE_HS_IO_KEYBOARD_DISPLAY 0x04 - -/** - * @} - */ - -/** @brief Stack reset callback - * - * @param reason Reason code for reset - */ -typedef void ble_hs_reset_fn(int reason); - - -/** @brief Stack sync callback */ -typedef void ble_hs_sync_fn(void); - -/** @brief Bluetooth Host main configuration structure - * - * Those can be used by application to configure stack. - * - * The only reason Security Manager (sm_ members) is configurable at runtime is - * to simplify security testing. Defaults for those are configured by selecting - * proper options in application's syscfg. - */ -struct ble_hs_cfg { - /** - * An optional callback that gets executed upon registration of each GATT - * resource (service, characteristic, or descriptor). - */ - ble_gatt_register_fn *gatts_register_cb; - - /** - * An optional argument that gets passed to the GATT registration - * callback. - */ - void *gatts_register_arg; - - /** Security Manager Local Input Output Capabilities */ - uint8_t sm_io_cap; - - /** @brief Security Manager OOB flag - * - * If set proper flag in Pairing Request/Response will be set. - */ - unsigned sm_oob_data_flag:1; - - /** @brief Security Manager Bond flag - * - * If set proper flag in Pairing Request/Response will be set. This results - * in storing keys distributed during bonding. - */ - unsigned sm_bonding:1; - - /** @brief Security Manager MITM flag - * - * If set proper flag in Pairing Request/Response will be set. This results - * in requiring Man-In-The-Middle protection when pairing. - */ - unsigned sm_mitm:1; - - /** @brief Security Manager Secure Connections flag - * - * If set proper flag in Pairing Request/Response will be set. This results - * in using LE Secure Connections for pairing if also supported by remote - * device. Fallback to legacy pairing if not supported by remote. - */ - unsigned sm_sc:1; - - /** @brief Security Manager Key Press Notification flag - * - * Currently unsupported and should not be set. - */ - unsigned sm_keypress:1; - - /** @brief Security Manager Local Key Distribution Mask */ - uint8_t sm_our_key_dist; - - /** @brief Security Manager Remote Key Distribution Mask */ - uint8_t sm_their_key_dist; - - /** @brief Stack reset callback - * - * This callback is executed when the host resets itself and the controller - * due to fatal error. - */ - ble_hs_reset_fn *reset_cb; - - /** @brief Stack sync callback - * - * This callback is executed when the host and controller become synced. - * This happens at startup and after a reset. - */ - ble_hs_sync_fn *sync_cb; - - /* XXX: These need to go away. Instead, the nimble host package should - * require the host-store API (not yet implemented).. - */ - /** Storage Read callback handles read of security material */ - ble_store_read_fn *store_read_cb; - - /** Storage Write callback handles write of security material */ - ble_store_write_fn *store_write_cb; - - /** Storage Delete callback handles deletion of security material */ - ble_store_delete_fn *store_delete_cb; - - /** @brief Storage Status callback. - * - * This callback gets executed when a persistence operation cannot be - * performed or a persistence failure is imminent. For example, if is - * insufficient storage capacity for a record to be persisted, this - * function gets called to give the application the opportunity to make - * room. - */ - ble_store_status_fn *store_status_cb; - - /** An optional argument that gets passed to the storage status callback. */ - void *store_status_arg; -}; - -extern struct ble_hs_cfg ble_hs_cfg; - -/** - * @} - */ - -/** - * @brief Indicates whether the host is enabled. The host is enabled if it is - * starting or fully started. It is disabled if it is stopping or stopped. - * - * @return 1 if the host is enabled; - * 0 if the host is disabled. - */ -int ble_hs_is_enabled(void); - -/** - * Indicates whether the host has synchronized with the controller. - * Synchronization must occur before any host procedures can be performed. - * - * @return 1 if the host and controller are in sync; - * 0 if the host and controller are out of sync. - */ -int ble_hs_synced(void); - -/** - * Synchronizes the host with the controller by sending a sequence of HCI - * commands. This function must be called before any other host functionality - * is used, but it must be called after both the host and controller are - * initialized. Typically, the host-parent-task calls this function at the top - * of its task routine. This function must only be called in the host parent - * task. A safe alternative for starting the stack from any task is to call - * `ble_hs_sched_start()`. - * - * If the host fails to synchronize with the controller (if the controller is - * not fully booted, for example), the host will attempt to resynchronize every - * 100 ms. For this reason, an error return code is not necessarily fatal. - * - * @return 0 on success; nonzero on error. - */ -int ble_hs_start(void); - -/** - * Enqueues a host start event to the default event queue. The actual host - * startup is performed in the host parent task, but using the default queue - * here ensures the event won't run until the end of main() when this is - * called during system initialization. This allows the application to - * configure the host package in the meantime. - * - * If auto-start is disabled, the application should use this function to start - * the BLE stack. This function can be called at any time as long as the host - * is stopped. When the host successfully starts, the application is notified - * via the ble_hs_cfg.sync_cb callback. - */ -void ble_hs_sched_start(void); - -/** - * Causes the host to reset the NimBLE stack as soon as possible. The - * application is notified when the reset occurs via the host reset callback. - * - * @param reason The host error code that gets passed to the reset callback. - */ -void ble_hs_sched_reset(int reason); - -/** - * Designates the specified event queue for NimBLE host work. By default, the - * host uses the default event queue and runs in the main task. This function - * is useful if you want the host to run in a different task. - * - * @param evq The event queue to use for host work. - */ -void ble_hs_evq_set(struct ble_npl_eventq *evq); - -/** - * Initializes the NimBLE host. This function must be called before the OS is - * started. The NimBLE stack requires an application task to function. One - * application task in particular is designated as the "host parent task". In - * addition to application-specific work, the host parent task does work for - * NimBLE by processing events generated by the host. - */ -void ble_hs_init(void); - -/** - * Deinitializes the NimBLE host. This function must be called after the - * NimBLE host stop procedure is complete. - */ -void ble_hs_deinit(void); - -/** - * @brief Called when the system is shutting down. Stops the BLE host. - * - * @param reason The reason for the shutdown. One of the - * HAL_RESET_[...] codes or an - * implementation-defined value. - * - * @return SYSDOWN_IN_PROGRESS. - */ -int ble_hs_shutdown(int reason); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_adv.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_adv.h deleted file mode 100644 index ae2965328..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_adv.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_HS_ADV_ -#define H_BLE_HS_ADV_ - -#include -#include "ble_uuid.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define BLE_HS_ADV_MAX_SZ BLE_HCI_MAX_ADV_DATA_LEN - -/** Max field payload size (account for 2-byte header). */ -#define BLE_HS_ADV_MAX_FIELD_SZ (BLE_HS_ADV_MAX_SZ - 2) - -struct ble_hs_adv_field { - uint8_t length; - uint8_t type; - uint8_t value[0]; -}; - -typedef int (* ble_hs_adv_parse_func_t) (const struct ble_hs_adv_field *, - void *); - -struct ble_hs_adv_fields { - /*** 0x01 - Flags. */ - uint8_t flags; - - /*** 0x02,0x03 - 16-bit service class UUIDs. */ - const ble_uuid16_t *uuids16; - uint8_t num_uuids16; - unsigned uuids16_is_complete:1; - - /*** 0x04,0x05 - 32-bit service class UUIDs. */ - const ble_uuid32_t *uuids32; - uint8_t num_uuids32; - unsigned uuids32_is_complete:1; - - /*** 0x06,0x07 - 128-bit service class UUIDs. */ - const ble_uuid128_t *uuids128; - uint8_t num_uuids128; - unsigned uuids128_is_complete:1; - - /*** 0x08,0x09 - Local name. */ - const uint8_t *name; - uint8_t name_len; - unsigned name_is_complete:1; - - /*** 0x0a - Tx power level. */ - int8_t tx_pwr_lvl; - unsigned tx_pwr_lvl_is_present:1; - - /*** 0x0d - Slave connection interval range. */ - const uint8_t *slave_itvl_range; - - /*** 0x16 - Service data - 16-bit UUID. */ - const uint8_t *svc_data_uuid16; - uint8_t svc_data_uuid16_len; - - /*** 0x17 - Public target address. */ - const uint8_t *public_tgt_addr; - uint8_t num_public_tgt_addrs; - - /*** 0x19 - Appearance. */ - uint16_t appearance; - unsigned appearance_is_present:1; - - /*** 0x1a - Advertising interval. */ - uint16_t adv_itvl; - unsigned adv_itvl_is_present:1; - - /*** 0x20 - Service data - 32-bit UUID. */ - const uint8_t *svc_data_uuid32; - uint8_t svc_data_uuid32_len; - - /*** 0x21 - Service data - 128-bit UUID. */ - const uint8_t *svc_data_uuid128; - uint8_t svc_data_uuid128_len; - - /*** 0x24 - URI. */ - const uint8_t *uri; - uint8_t uri_len; - - /*** 0xff - Manufacturer specific data. */ - const uint8_t *mfg_data; - uint8_t mfg_data_len; -}; - -#define BLE_HS_ADV_TYPE_FLAGS 0x01 -#define BLE_HS_ADV_TYPE_INCOMP_UUIDS16 0x02 -#define BLE_HS_ADV_TYPE_COMP_UUIDS16 0x03 -#define BLE_HS_ADV_TYPE_INCOMP_UUIDS32 0x04 -#define BLE_HS_ADV_TYPE_COMP_UUIDS32 0x05 -#define BLE_HS_ADV_TYPE_INCOMP_UUIDS128 0x06 -#define BLE_HS_ADV_TYPE_COMP_UUIDS128 0x07 -#define BLE_HS_ADV_TYPE_INCOMP_NAME 0x08 -#define BLE_HS_ADV_TYPE_COMP_NAME 0x09 -#define BLE_HS_ADV_TYPE_TX_PWR_LVL 0x0a -#define BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE 0x12 -#define BLE_HS_ADV_TYPE_SOL_UUIDS16 0x14 -#define BLE_HS_ADV_TYPE_SOL_UUIDS128 0x15 -#define BLE_HS_ADV_TYPE_SVC_DATA_UUID16 0x16 -#define BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR 0x17 -#define BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR 0x18 -#define BLE_HS_ADV_TYPE_APPEARANCE 0x19 -#define BLE_HS_ADV_TYPE_ADV_ITVL 0x1a -#define BLE_HS_ADV_TYPE_SVC_DATA_UUID32 0x20 -#define BLE_HS_ADV_TYPE_SVC_DATA_UUID128 0x21 -#define BLE_HS_ADV_TYPE_URI 0x24 -#define BLE_HS_ADV_TYPE_MESH_PROV 0x29 -#define BLE_HS_ADV_TYPE_MESH_MESSAGE 0x2a -#define BLE_HS_ADV_TYPE_MESH_BEACON 0x2b -#define BLE_HS_ADV_TYPE_MFG_DATA 0xff - -#define BLE_HS_ADV_FLAGS_LEN 1 -#define BLE_HS_ADV_F_DISC_LTD 0x01 -#define BLE_HS_ADV_F_DISC_GEN 0x02 -#define BLE_HS_ADV_F_BREDR_UNSUP 0x04 - -#define BLE_HS_ADV_TX_PWR_LVL_LEN 1 - -/** - * Set the tx_pwr_lvl field to this if you want the stack to fill in the tx - * power level field. - */ -#define BLE_HS_ADV_TX_PWR_LVL_AUTO (-128) - -#define BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN 4 - -#define BLE_HS_ADV_SVC_DATA_UUID16_MIN_LEN 2 - -#define BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN 6 - -#define BLE_HS_ADV_APPEARANCE_LEN 2 - -#define BLE_HS_ADV_ADV_ITVL_LEN 2 - -#define BLE_HS_ADV_SVC_DATA_UUID32_MIN_LEN 4 - -#define BLE_HS_ADV_SVC_DATA_UUID128_MIN_LEN 16 - -int ble_hs_adv_set_fields_mbuf(const struct ble_hs_adv_fields *adv_fields, - struct os_mbuf *om); - -int ble_hs_adv_set_fields(const struct ble_hs_adv_fields *adv_fields, - uint8_t *dst, uint8_t *dst_len, uint8_t max_len); - -int ble_hs_adv_parse_fields(struct ble_hs_adv_fields *adv_fields, - const uint8_t *src, uint8_t src_len); - -int ble_hs_adv_parse(const uint8_t *data, uint8_t length, - ble_hs_adv_parse_func_t func, void *user_data); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_hci.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_hci.h deleted file mode 100644 index e10b8e62a..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_hci.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_HS_HCI_ -#define H_BLE_HS_HCI_ - -/** - * @brief Bluetooth Host HCI utils - * @defgroup bt_host_hci Bluetooth Host HCI utils - * @ingroup bt_host - * @{ - */ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Queries the controller for the channel map used with the specified - * connection. The channel map is represented as an array of five bytes, with - * each bit corresponding to an individual channel. The array is interpreted - * as little-endian, such that: - * map[0] & 0x01 --> Channel 0. - * map[0] & 0x02 --> Channel 1. - * ... - * map[1] & 0x01 --> Channel 8. - * - * As there are 37 channels, only the first 37 bits get written. - * - * If a bit is 1, the corresponding channel is used. Otherwise, the channel is - * unused. - * - * @param conn_handle The handle of the connection whose channel map - * is being read. - * @param out_chan_map On success, the retrieved channel map gets - * written here. This buffer must have a size - * >= 5 bytes. - * - * @return 0 on success; - * A BLE host HCI return code if the controller - * rejected the request; - * A BLE host core return code on unexpected - * error. - */ -int ble_hs_hci_read_chan_map(uint16_t conn_handle, uint8_t *out_chan_map); - -/** - * Instructs the controller to use the specified channel map. The channel map - * is represented as an array of five bytes, with each bit corresponding to an - * individual channel. The array is interpreted as little-endian, such that: - * map[0] & 0x01 --> Channel 0. - * map[0] & 0x02 --> Channel 1. - * ... - * map[1] & 0x01 --> Channel 8. - * - * As there are 37 channels, only the first 37 bits should be written are used. - * - * If a bit is 1, the corresponding channel can be used. Otherwise, the - * channel should not be used. - * - * @param chan_map The channel map to configure. This buffer - * should have a size of 5 bytes. - * - * @return 0 on success; - * A BLE host HCI return code if the controller - * rejected the request; - * A BLE host core return code on unexpected - * error. - */ -int ble_hs_hci_set_chan_class(const uint8_t *chan_map); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_id.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_id.h deleted file mode 100644 index 568303412..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_id.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_HS_ID_ -#define H_BLE_HS_ID_ - -/** - * @brief Bluetooth Host Identity - * @defgroup bt_host_id Bluetooth Host Identity - * @ingroup bt_host - * @{ - */ - -#include -#include "nimble/nimble/include/nimble/ble.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Generates a new random address. This function does not configure the device - * with the new address; the caller can use the address in subsequent - * operations. - * - * @param nrpa The type of random address to generate: - * 0: static - * 1: non-resolvable private - * @param out_addr On success, the generated address gets written - * here. - * - * @return 0 on success; nonzero on failure. - */ -int ble_hs_id_gen_rnd(int nrpa, ble_addr_t *out_addr); - -/** - * Sets the device's random address. The address type (static vs. - * non-resolvable private) is inferred from the most-significant byte of the - * address. The address is specified in host byte order (little-endian!). - * - * @param rnd_addr The random address to set. - * - * @return 0 on success; - * BLE_HS_EINVAL if the specified address is not a - * valid static random or non-resolvable - * private address. - * Other nonzero on error. - */ -int ble_hs_id_set_rnd(const uint8_t *rnd_addr); - -/** - * Retrieves one of the device's identity addresses. The device can have two - * identity addresses: one public and one random. The id_addr_type argument - * specifies which of these two addresses to retrieve. - * - * @param id_addr_type The type of identity address to retrieve. - * Valid values are: - * o BLE_ADDR_PUBLIC - * o BLE_ADDR_RANDOM - * @param out_id_addr On success, the requested identity address is - * copied into this buffer. The buffer must - * be at least six bytes in size. Pass NULL - * if you do not require this information. - * @param out_is_nrpa On success, the pointed-to value indicates - * whether the retrieved address is a - * non-resolvable private address. Pass NULL - * if you do not require this information. - * - * @return 0 on success; - * BLE_HS_EINVAL if an invalid address type was - * specified; - * BLE_HS_ENOADDR if the device does not have an - * identity address of the requested type; - * Other BLE host core code on error. - */ -int ble_hs_id_copy_addr(uint8_t id_addr_type, uint8_t *out_id_addr, - int *out_is_nrpa); - -/** - * Determines the best address type to use for automatic address type - * resolution. Calculation of the best address type is done as follows: - * - * if privacy requested: - * if we have a random static address: - * --> RPA with static random ID - * else - * --> RPA with public ID - * end - * else - * if we have a random static address: - * --> random static address - * else - * --> public address - * end - * end - * - * @param privacy (0/1) Whether to use a private address. - * @param out_addr_type On success, the "own addr type" code gets - * written here. - * - * @return 0 if an address type was successfully inferred. - * BLE_HS_ENOADDR if the device does not have a - * suitable address. - * Other BLE host core code on error. - */ -int ble_hs_id_infer_auto(int privacy, uint8_t *out_addr_type); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_log.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_log.h deleted file mode 100644 index 0646b0bae..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_log.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_HS_LOG_ -#define H_BLE_HS_LOG_ - -#include "nimble/porting/nimble/include/modlog/modlog.h" -#include "nimble/porting/nimble/include/log/log.h" - -/* Only include the logcfg header if this version of newt can generate it. */ -#if MYNEWT_VAL(NEWT_FEATURE_LOGCFG) -#include "nimble/porting/nimble/include/logcfg/logcfg.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -struct os_mbuf; - -#define BLE_HS_LOG(lvl, ...) \ - BLE_HS_LOG_ ## lvl(__VA_ARGS__) - -#define BLE_HS_LOG_ADDR(lvl, addr) \ - BLE_HS_LOG_ ## lvl("%02x:%02x:%02x:%02x:%02x:%02x", \ - (addr)[5], (addr)[4], (addr)[3], \ - (addr)[2], (addr)[1], (addr)[0]) - - -void ble_hs_log_mbuf(const struct os_mbuf *om); -void ble_hs_log_flat_buf(const void *data, int len); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_mbuf.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_mbuf.h deleted file mode 100644 index a3c2c0296..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_mbuf.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_HS_MBUF_ -#define H_BLE_HS_MBUF_ - -/** - * @brief Bluetooth Host chained memory buffer (mbuf) - * @defgroup bt_host_mbuf Bluetooth Host chained memory buffer (mbuf) - * @ingroup bt_host - * @{ - */ - -#include -#ifdef __cplusplus -extern "C" { -#endif - -struct os_mbuf; - -/** - * Allocates an mbuf suitable for an ATT command packet. The resulting packet - * has sufficient leading space for: - * - ACL data header - * - L2CAP B-frame header - * - Largest ATT command base (prepare write request / response). - * - * @return An empty mbuf on success, NULL on error. - */ -struct os_mbuf *ble_hs_mbuf_att_pkt(void); - -/** - * Allocates an mbuf and fills it with the contents of the specified flat - * buffer. - * - * @param buf The flat buffer to copy from. - * @param len The length of the flat buffer. - * - * @return A newly-allocated mbuf on success, NULL on error. - */ -struct os_mbuf *ble_hs_mbuf_from_flat(const void *buf, uint16_t len); - -/** - * Copies the contents of an mbuf into the specified flat buffer. If the flat - * buffer is too small to contain the mbuf's contents, it is filled to capacity - * and BLE_HS_EMSGSIZE is returned. - * - * @param om The mbuf to copy from. - * @param flat The destination flat buffer. - * @param max_len The size of the flat buffer. - * @param out_copy_len The number of bytes actually copied gets written here. - * - * @return 0 on success or BLE host core return code on error. - */ -int ble_hs_mbuf_to_flat(const struct os_mbuf *om, void *flat, uint16_t max_len, - uint16_t *out_copy_len); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_pvcy.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_pvcy.h deleted file mode 100644 index 26450f4f8..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_pvcy.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2020 Espressif Systems (Shanghai) PTE LTD - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_HS_PVCY_ -#define H_BLE_HS_PVCY_ - -#include "ble_hs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) - -#define NIMBLE_HOST_DISABLE_PRIVACY 0x00 -#define NIMBLE_HOST_ENABLE_RPA 0x01 -#define NIMBLE_HOST_ENABLE_NRPA 0x02 - -/* Called to configure local(own) privacy (RPA/NRPA) when using Host based privacy. - * In Host based privacy, as controller is not aware of RPA/NRPA address is in use, - * we do it through 'BLE_ADDR_RANDOM (0x01)' addr_type route. This is necessary - * so as to set the private address as random address in controller. - * Remember to configure `BLE_SM_PAIR_KEY_DIST_ID` in our & their - * key distributions for using RPA. For NRPA part of privacy it is not - * necessary to configure key distributions in host, as anyway NRPA is non-resolvable. - * Please call this API once host-controller are synced as we set the private - * (RPA/NRPA) address using host-controller HCI commands. - * - * To give brief information on how to use this feature, - * please refer to following steps while using RPA feature: - * - * 1. Include "host/ble_hs_pvcy.h". - * 2. Set own_addr_type to `BLE_OWN_ADDR_RANDOM`. - * 3. Add `BLE_SM_PAIR_KEY_DIST_ID` to key distribution in - * `ble_hs_cfg.sm_our_key_dist` & `ble_hs_cfg.sm_their_key_dist`. - * 4. Call `ble_hs_pvcy_rpa_config(1)` in Host-Controller sync callback. - * - * In case of NRPA, steps 1, 2 and calling ble_hs_pvcy_rpa_config(2) will - * suffice. - * - * @param enable RPA when param = 1 (NIMBLE_HOST_ENABLE_RPA) - * enable NRPA when param = 2 (NIMBLE_HOST_ENABLE_NRPA) - * disable privacy when param = 0 (NIMBLE_HOST_DISABLE_PRIVACY) - * - * @return return 0 when successful. - * return appropriate error code otherwise - */ -int ble_hs_pvcy_rpa_config(uint8_t enable); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_stop.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_stop.h deleted file mode 100644 index d16c9c27b..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs_stop.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_HS_STOP_ -#define H_BLE_HS_STOP_ - -/** @typedef ble_hs_stop_fn - * @brief Callback function; reports the result of a host stop procedure. - * - * @param status The result of the host stop procedure. One of - * the HAL_RESET_[...] codes or an - * implementation-defined value. - * @param arg Optional argument specified when the stop - * procedure was initiated. - * - */ -typedef void ble_hs_stop_fn(int status, void *arg); - -/** - * @brief Used to report the result of a stop procedure. - * - * This should be used as an opaque structure and not modified manually. - */ -struct ble_hs_stop_listener { - ble_hs_stop_fn *fn; - void *arg; - SLIST_ENTRY(ble_hs_stop_listener) link; -}; - -/** - * @brief Stops the BLE host. - * - * Aborts all active GAP procedures and terminates all open connections. - * Connection termination is performed asynchronously, so this function's - * result is reported via the provided listener. - * - * @param listener A listener to populate. This object's initial - * value doesn't matter, but its lifetime must - * extend until the stop procedure completes. - * @param fn The callback to execute when the stop procedure - * completes. - * @param arg Optional argument to pass to the callback. - * - * @return 0: Stop procedure successfully initiated. - * BLE_HS_EBUSY: Stop procedure already in - * progress; the provided callback gets called - * when the procedure completes. - * BLE_HS_EALREADY: Host already stopped; the - * provided callback does *not* get called. - */ -int ble_hs_stop(struct ble_hs_stop_listener *listener, - ble_hs_stop_fn *fn, void *arg); - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_ibeacon.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_ibeacon.h deleted file mode 100644 index fff7c57ae..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_ibeacon.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_IBEACON_ -#define H_BLE_IBEACON_ - -#ifdef __cplusplus -extern "C" { -#endif - -int ble_ibeacon_set_adv_data(void *uuid128, uint16_t major, - uint16_t minor, int8_t measured_power); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_l2cap.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_l2cap.h deleted file mode 100644 index 9d92c08f1..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_l2cap.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_L2CAP_ -#define H_BLE_L2CAP_ - -#include "nimble/nimble/include/nimble/nimble_opt.h" -#ifdef __cplusplus -extern "C" { -#endif - -struct ble_l2cap_sig_update_req; -struct ble_hs_conn; - -#define BLE_L2CAP_CID_ATT 4 -#define BLE_L2CAP_CID_SIG 5 -#define BLE_L2CAP_CID_SM 6 - -#define BLE_L2CAP_SIG_OP_REJECT 0x01 -#define BLE_L2CAP_SIG_OP_CONNECT_REQ 0x02 -#define BLE_L2CAP_SIG_OP_CONNECT_RSP 0x03 -#define BLE_L2CAP_SIG_OP_CONFIG_REQ 0x04 -#define BLE_L2CAP_SIG_OP_CONFIG_RSP 0x05 -#define BLE_L2CAP_SIG_OP_DISCONN_REQ 0x06 -#define BLE_L2CAP_SIG_OP_DISCONN_RSP 0x07 -#define BLE_L2CAP_SIG_OP_ECHO_REQ 0x08 -#define BLE_L2CAP_SIG_OP_ECHO_RSP 0x09 -#define BLE_L2CAP_SIG_OP_INFO_REQ 0x0a -#define BLE_L2CAP_SIG_OP_INFO_RSP 0x0b -#define BLE_L2CAP_SIG_OP_CREATE_CHAN_REQ 0x0c -#define BLE_L2CAP_SIG_OP_CREATE_CHAN_RSP 0x0d -#define BLE_L2CAP_SIG_OP_MOVE_CHAN_REQ 0x0e -#define BLE_L2CAP_SIG_OP_MOVE_CHAN_RSP 0x0f -#define BLE_L2CAP_SIG_OP_MOVE_CHAN_CONF_REQ 0x10 -#define BLE_L2CAP_SIG_OP_MOVE_CHAN_CONF_RSP 0x11 -#define BLE_L2CAP_SIG_OP_UPDATE_REQ 0x12 -#define BLE_L2CAP_SIG_OP_UPDATE_RSP 0x13 -#define BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_REQ 0x14 -#define BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_RSP 0x15 -#define BLE_L2CAP_SIG_OP_FLOW_CTRL_CREDIT 0x16 -#define BLE_L2CAP_SIG_OP_CREDIT_CONNECT_REQ 0x17 -#define BLE_L2CAP_SIG_OP_CREDIT_CONNECT_RSP 0x18 -#define BLE_L2CAP_SIG_OP_CREDIT_RECONFIG_REQ 0x19 -#define BLE_L2CAP_SIG_OP_CREDIT_RECONFIG_RSP 0x1A -#define BLE_L2CAP_SIG_OP_MAX 0x1B - -#define BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD 0x0000 -#define BLE_L2CAP_SIG_ERR_MTU_EXCEEDED 0x0001 -#define BLE_L2CAP_SIG_ERR_INVALID_CID 0x0002 - -#define BLE_L2CAP_COC_ERR_CONNECTION_SUCCESS 0x0000 -#define BLE_L2CAP_COC_ERR_UNKNOWN_LE_PSM 0x0002 -#define BLE_L2CAP_COC_ERR_NO_RESOURCES 0x0004 -#define BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHEN 0x0005 -#define BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHOR 0x0006 -#define BLE_L2CAP_COC_ERR_INSUFFICIENT_KEY_SZ 0x0007 -#define BLE_L2CAP_COC_ERR_INSUFFICIENT_ENC 0x0008 -#define BLE_L2CAP_COC_ERR_INVALID_SOURCE_CID 0x0009 -#define BLE_L2CAP_COC_ERR_SOURCE_CID_ALREADY_USED 0x000A -#define BLE_L2CAP_COC_ERR_UNACCEPTABLE_PARAMETERS 0x000B -#define BLE_L2CAP_COC_ERR_INVALID_PARAMETERS 0x000C - -#define BLE_L2CAP_ERR_RECONFIG_SUCCEED 0x0000 -#define BLE_L2CAP_ERR_RECONFIG_REDUCTION_MTU_NOT_ALLOWED 0x0001 -#define BLE_L2CAP_ERR_RECONFIG_REDUCTION_MPS_NOT_ALLOWED 0x0002 -#define BLE_L2CAP_ERR_RECONFIG_INVALID_DCID 0x0003 -#define BLE_L2CAP_ERR_RECONFIG_UNACCAPTED_PARAM 0x0004 - -#define BLE_L2CAP_EVENT_COC_CONNECTED 0 -#define BLE_L2CAP_EVENT_COC_DISCONNECTED 1 -#define BLE_L2CAP_EVENT_COC_ACCEPT 2 -#define BLE_L2CAP_EVENT_COC_DATA_RECEIVED 3 -#define BLE_L2CAP_EVENT_COC_TX_UNSTALLED 4 -#define BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED 5 -#define BLE_L2CAP_EVENT_COC_PEER_RECONFIGURED 6 - -typedef void ble_l2cap_sig_update_fn(uint16_t conn_handle, int status, - void *arg); - -struct ble_l2cap_sig_update_params { - uint16_t itvl_min; - uint16_t itvl_max; - uint16_t slave_latency; - uint16_t timeout_multiplier; -}; - -int ble_l2cap_sig_update(uint16_t conn_handle, - struct ble_l2cap_sig_update_params *params, - ble_l2cap_sig_update_fn *cb, void *cb_arg); - -struct ble_l2cap_chan; - -/** - * Represents a L2CAP-related event. - * When such an event occurs, the host notifies the application by passing an - * instance of this structure to an application-specified callback. - */ -struct ble_l2cap_event { - /** - * Indicates the type of L2CAP event that occurred. This is one of the - * BLE_L2CAP_EVENT codes. - */ - uint8_t type; - - /** - * A discriminated union containing additional details concerning the L2CAP - * event. The 'type' field indicates which member of the union is valid. - */ - union { - /** - * Represents a connection attempt. Valid for the following event - * types: - * o BLE_L2CAP_EVENT_COC_CONNECTED */ - struct { - /** - * The status of the connection attempt; - * o 0: the connection was successfully established. - * o BLE host error code: the connection attempt failed for - * the specified reason. - */ - int status; - - /** Connection handle of the relevant connection */ - uint16_t conn_handle; - - /** The L2CAP channel of the relevant L2CAP connection. */ - struct ble_l2cap_chan *chan; - } connect; - - /** - * Represents a terminated connection. Valid for the following event - * types: - * o BLE_L2CAP_EVENT_COC_DISCONNECTED - */ - struct { - /** Connection handle of the relevant connection */ - uint16_t conn_handle; - - /** Information about the L2CAP connection prior to termination. */ - struct ble_l2cap_chan *chan; - } disconnect; - - /** - * Represents connection accept. Valid for the following event - * types: - * o BLE_L2CAP_EVENT_COC_ACCEPT - */ - struct { - /** Connection handle of the relevant connection */ - uint16_t conn_handle; - - /** MTU supported by peer device on the channel */ - uint16_t peer_sdu_size; - - /** The L2CAP channel of the relevant L2CAP connection. */ - struct ble_l2cap_chan *chan; - } accept; - - /** - * Represents received data. Valid for the following event - * types: - * o BLE_L2CAP_EVENT_COC_DATA_RECEIVED - */ - struct { - /** Connection handle of the relevant connection */ - uint16_t conn_handle; - - /** The L2CAP channel of the relevant L2CAP connection. */ - struct ble_l2cap_chan *chan; - - /** The mbuf with received SDU. */ - struct os_mbuf *sdu_rx; - } receive; - - /** - * Represents tx_unstalled data. Valid for the following event - * types: - * o BLE_L2CAP_EVENT_COC_TX_UNSTALLED - */ - struct { - /** Connection handle of the relevant connection */ - uint16_t conn_handle; - - /** The L2CAP channel of the relevant L2CAP connection. */ - struct ble_l2cap_chan *chan; - - /** - * The status of the send attempt which was stalled due to - * lack of credits; This can be non zero only if there - * is an issue with memory allocation for following SDU fragments. - * In such a case last SDU has been partially sent to peer device - * and it is up to application to decide how to handle it. - */ - int status; - } tx_unstalled; - - /** - * Represents reconfiguration done. Valid for the following event - * types: - * o BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED - * o BLE_L2CAP_EVENT_COC_PEER_RECONFIGURED - */ - struct { - /** - * The status of the reconfiguration attempt; - * o 0: the reconfiguration was successfully done. - * o BLE host error code: the reconfiguration attempt failed for - * the specified reason. - */ - int status; - - /** Connection handle of the relevant connection */ - uint16_t conn_handle; - - /** The L2CAP channel of the relevant L2CAP connection. */ - struct ble_l2cap_chan *chan; - } reconfigured; - }; -}; - -struct ble_l2cap_chan_info { - uint16_t scid; - uint16_t dcid; - uint16_t our_l2cap_mtu; - uint16_t peer_l2cap_mtu; - uint16_t psm; - uint16_t our_coc_mtu; - uint16_t peer_coc_mtu; -}; - -typedef int ble_l2cap_event_fn(struct ble_l2cap_event *event, void *arg); - - -uint16_t ble_l2cap_get_conn_handle(struct ble_l2cap_chan *chan); -int ble_l2cap_create_server(uint16_t psm, uint16_t mtu, - ble_l2cap_event_fn *cb, void *cb_arg); - -int ble_l2cap_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu, - struct os_mbuf *sdu_rx, - ble_l2cap_event_fn *cb, void *cb_arg); -int ble_l2cap_disconnect(struct ble_l2cap_chan *chan); -int ble_l2cap_send(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_tx); -int ble_l2cap_recv_ready(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_rx); -int ble_l2cap_get_chan_info(struct ble_l2cap_chan *chan, struct ble_l2cap_chan_info *chan_info); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_monitor.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_monitor.h deleted file mode 100644 index 2c3602402..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_monitor.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_MONITOR_ -#define H_BLE_MONITOR_ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" - -#undef BLE_MONITOR -#define BLE_MONITOR (MYNEWT_VAL(BLE_MONITOR_UART) || MYNEWT_VAL(BLE_MONITOR_RTT)) - -#ifdef __cplusplus -extern "C" { -#endif - -int ble_monitor_log(int level, const char *fmt, ...); - -int ble_monitor_out(int c); -void ble_monitor_deinit(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_sm.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_sm.h deleted file mode 100644 index 42414d584..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_sm.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_SM_ -#define H_BLE_SM_ - -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define BLE_SM_ERR_PASSKEY 0x01 -#define BLE_SM_ERR_OOB 0x02 -#define BLE_SM_ERR_AUTHREQ 0x03 -#define BLE_SM_ERR_CONFIRM_MISMATCH 0x04 -#define BLE_SM_ERR_PAIR_NOT_SUPP 0x05 -#define BLE_SM_ERR_ENC_KEY_SZ 0x06 -#define BLE_SM_ERR_CMD_NOT_SUPP 0x07 -#define BLE_SM_ERR_UNSPECIFIED 0x08 -#define BLE_SM_ERR_REPEATED 0x09 -#define BLE_SM_ERR_INVAL 0x0a -#define BLE_SM_ERR_DHKEY 0x0b -#define BLE_SM_ERR_NUMCMP 0x0c -#define BLE_SM_ERR_ALREADY 0x0d -#define BLE_SM_ERR_CROSS_TRANS 0x0e -#define BLE_SM_ERR_MAX_PLUS_1 0x0f - -#define BLE_SM_PAIR_ALG_JW 0 -#define BLE_SM_PAIR_ALG_PASSKEY 1 -#define BLE_SM_PAIR_ALG_OOB 2 -#define BLE_SM_PAIR_ALG_NUMCMP 3 - -#define BLE_SM_PAIR_KEY_DIST_ENC 0x01 -#define BLE_SM_PAIR_KEY_DIST_ID 0x02 -#define BLE_SM_PAIR_KEY_DIST_SIGN 0x04 -#define BLE_SM_PAIR_KEY_DIST_LINK 0x08 -#define BLE_SM_PAIR_KEY_DIST_RESERVED 0xf0 - -#define BLE_SM_IO_CAP_DISP_ONLY 0x00 -#define BLE_SM_IO_CAP_DISP_YES_NO 0x01 -#define BLE_SM_IO_CAP_KEYBOARD_ONLY 0x02 -#define BLE_SM_IO_CAP_NO_IO 0x03 -#define BLE_SM_IO_CAP_KEYBOARD_DISP 0x04 -#define BLE_SM_IO_CAP_RESERVED 0x05 - -#define BLE_SM_PAIR_OOB_NO 0x00 -#define BLE_SM_PAIR_OOB_YES 0x01 -#define BLE_SM_PAIR_OOB_RESERVED 0x02 - -#define BLE_SM_PAIR_AUTHREQ_BOND 0x01 -#define BLE_SM_PAIR_AUTHREQ_MITM 0x04 -#define BLE_SM_PAIR_AUTHREQ_SC 0x08 -#define BLE_SM_PAIR_AUTHREQ_KEYPRESS 0x10 -#define BLE_SM_PAIR_AUTHREQ_RESERVED 0xe2 - -#define BLE_SM_PAIR_KEY_SZ_MIN 7 -#define BLE_SM_PAIR_KEY_SZ_MAX 16 - -/* - * The security manager asks the application to perform a key generation - * action. The application passes the passkey back to SM via - * ble_sm_inject_io(). - */ -#define BLE_SM_IOACT_NONE 0 -#define BLE_SM_IOACT_OOB 1 -#define BLE_SM_IOACT_INPUT 2 -#define BLE_SM_IOACT_DISP 3 -#define BLE_SM_IOACT_NUMCMP 4 -#define BLE_SM_IOACT_OOB_SC 5 -#define BLE_SM_IOACT_MAX_PLUS_ONE 6 - -struct ble_sm_sc_oob_data { - /** Random Number. */ - uint8_t r[16]; - - /** Confirm Value. */ - uint8_t c[16]; -}; - -struct ble_sm_io { - uint8_t action; - union { - uint32_t passkey; - uint8_t oob[16]; - uint8_t numcmp_accept; - struct { - struct ble_sm_sc_oob_data *local; - struct ble_sm_sc_oob_data *remote; - } oob_sc_data; - }; -}; - -int ble_sm_sc_oob_generate_data(struct ble_sm_sc_oob_data *oob_data); - -#if NIMBLE_BLE_SM -int ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey); -#else -#define ble_sm_inject_io(conn_handle, pkey) \ - ((void)(conn_handle), BLE_HS_ENOTSUP) -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_store.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_store.h deleted file mode 100644 index 8e6721bf3..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_store.h +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_STORE_ -#define H_BLE_STORE_ - -#include -#include "nimble/nimble/include/nimble/ble.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define BLE_STORE_OBJ_TYPE_OUR_SEC 1 -#define BLE_STORE_OBJ_TYPE_PEER_SEC 2 -#define BLE_STORE_OBJ_TYPE_CCCD 3 -#define BLE_STORE_OBJ_TYPE_PEER_DEV_REC 4 - -/** Failed to persist record; insufficient storage capacity. */ -#define BLE_STORE_EVENT_OVERFLOW 1 - -/** About to execute a procedure that may fail due to overflow. */ -#define BLE_STORE_EVENT_FULL 2 - -/** - * Used as a key for lookups of security material. This struct corresponds to - * the following store object types: - * o BLE_STORE_OBJ_TYPE_OUR_SEC - * o BLE_STORE_OBJ_TYPE_PEER_SEC - */ -struct ble_store_key_sec { - /** - * Key by peer identity address; - * peer_addr=BLE_ADDR_NONE means don't key off peer. - */ - ble_addr_t peer_addr; - - /** Key by ediv; ediv_rand_present=0 means don't key off ediv. */ - uint16_t ediv; - - /** Key by rand_num; ediv_rand_present=0 means don't key off rand_num. */ - uint64_t rand_num; - - unsigned ediv_rand_present:1; - - /** Number of results to skip; 0 means retrieve the first match. */ - uint8_t idx; -}; - -/** - * Represents stored security material. This struct corresponds to the - * following store object types: - * o BLE_STORE_OBJ_TYPE_OUR_SEC - * o BLE_STORE_OBJ_TYPE_PEER_SEC - */ -struct ble_store_value_sec { - ble_addr_t peer_addr; - - uint8_t key_size; - uint16_t ediv; - uint64_t rand_num; - uint8_t ltk[16]; - uint8_t ltk_present:1; - - uint8_t irk[16]; - uint8_t irk_present:1; - - uint8_t csrk[16]; - uint8_t csrk_present:1; - - unsigned authenticated:1; - uint8_t sc:1; -}; - -/** - * Used as a key for lookups of stored client characteristic configuration - * descriptors (CCCDs). This struct corresponds to the BLE_STORE_OBJ_TYPE_CCCD - * store object type. - */ -struct ble_store_key_cccd { - /** - * Key by peer identity address; - * peer_addr=BLE_ADDR_NONE means don't key off peer. - */ - ble_addr_t peer_addr; - - /** - * Key by characteristic value handle; - * chr_val_handle=0 means don't key off characteristic handle. - */ - uint16_t chr_val_handle; - - /** Number of results to skip; 0 means retrieve the first match. */ - uint8_t idx; -}; - -/** - * Represents a stored client characteristic configuration descriptor (CCCD). - * This struct corresponds to the BLE_STORE_OBJ_TYPE_CCCD store object type. - */ -struct ble_store_value_cccd { - ble_addr_t peer_addr; - uint16_t chr_val_handle; - uint16_t flags; - unsigned value_changed:1; -}; - -/** - * Used as a key for store lookups. This union must be accompanied by an - * object type code to indicate which field is valid. - */ -union ble_store_key { - struct ble_store_key_sec sec; - struct ble_store_key_cccd cccd; -}; - -/** - * Represents stored data. This union must be accompanied by an object type - * code to indicate which field is valid. - */ -union ble_store_value { - struct ble_store_value_sec sec; - struct ble_store_value_cccd cccd; -}; - -struct ble_store_status_event { - /** - * The type of event being reported; one of the BLE_STORE_EVENT_TYPE_[...] - * codes. - */ - int event_code; - - /** - * Additional data related to the event; the valid field is inferred from - * the obj_type,event_code pair. - */ - union { - /** - * Represents a write that failed due to storage exhaustion. Valid for - * the following event types: - * o BLE_STORE_EVENT_OVERFLOW - */ - struct { - /** The type of object that failed to be written. */ - int obj_type; - - /** The object that failed to be written. */ - const union ble_store_value *value; - } overflow; - - /** - * Represents the possibility that a scheduled write will fail due to - * storage exhaustion. Valid for the following event types: - * o BLE_STORE_EVENT_FULL - */ - struct { - /** The type of object that may fail to be written. */ - int obj_type; - - /** The handle of the connection which prompted the write. */ - uint16_t conn_handle; - } full; - }; -}; - -/** - * Searches the store for an object matching the specified criteria. If a - * match is found, it is read from the store and the dst parameter is populated - * with the retrieved object. - * - * @param obj_type The type of object to search for; one of the - * BLE_STORE_OBJ_TYPE_[...] codes. - * @param key Specifies properties of the object to search - * for. An object is retrieved if it matches - * these criteria. - * @param dst On success, this is populated with the - * retrieved object. - * - * @return 0 if an object was successfully retreived; - * BLE_HS_ENOENT if no matching object was found; - * Other nonzero on error. - */ -typedef int ble_store_read_fn(int obj_type, const union ble_store_key *key, - union ble_store_value *dst); - -/** - * Writes the specified object to the store. If an object with the same - * identity is already in the store, it is replaced. If the store lacks - * sufficient capacity to write the object, this function may remove previously - * stored values to make room. - * - * @param obj_type The type of object being written; one of the - * BLE_STORE_OBJ_TYPE_[...] codes. - * @param val The object to persist. - * - * @return 0 if the object was successfully written; - * Other nonzero on error. - */ -typedef int ble_store_write_fn(int obj_type, const union ble_store_value *val); - -/** - * Searches the store for the first object matching the specified criteria. If - * a match is found, it is deleted from the store. - * - * @param obj_type The type of object to delete; one of the - * BLE_STORE_OBJ_TYPE_[...] codes. - * @param key Specifies properties of the object to search - * for. An object is deleted if it matches - * these criteria. - * @return 0 if an object was successfully retrieved; - * BLE_HS_ENOENT if no matching object was found; - * Other nonzero on error. - */ -typedef int ble_store_delete_fn(int obj_type, const union ble_store_key *key); - -/** - * Indicates an inability to perform a store operation. This callback should - * do one of two things: - * o Address the problem and return 0, indicating that the store operation - * should proceed. - * o Return nonzero to indicate that the store operation should be aborted. - * - * @param event Describes the store event being reported. - * @param arg Optional user argument. - * - * @return 0 if the store operation should proceed; - * nonzero if the store operation should be - * aborted. - */ -typedef int ble_store_status_fn(struct ble_store_status_event *event, - void *arg); - -int ble_store_read(int obj_type, const union ble_store_key *key, - union ble_store_value *val); -int ble_store_write(int obj_type, const union ble_store_value *val); -int ble_store_delete(int obj_type, const union ble_store_key *key); -int ble_store_overflow_event(int obj_type, const union ble_store_value *value); -int ble_store_full_event(int obj_type, uint16_t conn_handle); - -int ble_store_read_our_sec(const struct ble_store_key_sec *key_sec, - struct ble_store_value_sec *value_sec); -int ble_store_write_our_sec(const struct ble_store_value_sec *value_sec); -int ble_store_delete_our_sec(const struct ble_store_key_sec *key_sec); -int ble_store_read_peer_sec(const struct ble_store_key_sec *key_sec, - struct ble_store_value_sec *value_sec); -int ble_store_write_peer_sec(const struct ble_store_value_sec *value_sec); -int ble_store_delete_peer_sec(const struct ble_store_key_sec *key_sec); - -int ble_store_read_cccd(const struct ble_store_key_cccd *key, - struct ble_store_value_cccd *out_value); -int ble_store_write_cccd(const struct ble_store_value_cccd *value); -int ble_store_delete_cccd(const struct ble_store_key_cccd *key); - -void ble_store_key_from_value_sec(struct ble_store_key_sec *out_key, - const struct ble_store_value_sec *value); -void ble_store_key_from_value_cccd(struct ble_store_key_cccd *out_key, - const struct ble_store_value_cccd *value); - -void ble_store_key_from_value(int obj_type, - union ble_store_key *out_key, - const union ble_store_value *value); - -typedef int ble_store_iterator_fn(int obj_type, - union ble_store_value *val, - void *cookie); - -int ble_store_iterate(int obj_type, - ble_store_iterator_fn *callback, - void *cookie); - -int ble_store_clear(void); - -/*** Utility functions. */ - -int ble_store_util_bonded_peers(ble_addr_t *out_peer_id_addrs, - int *out_num_peers, - int max_peers); -int ble_store_util_delete_all(int type, const union ble_store_key *key); -int ble_store_util_delete_peer(const ble_addr_t *peer_id_addr); -int ble_store_util_delete_oldest_peer(void); -int ble_store_util_count(int type, int *out_count); -int ble_store_util_status_rr(struct ble_store_status_event *event, void *arg); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_uuid.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_uuid.h deleted file mode 100644 index d3576c595..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_uuid.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_UUID_ -#define H_BLE_UUID_ - -/** - * @brief Bluetooth UUID - * @defgroup bt_uuid Bluetooth UUID - * @ingroup bt_host - * @{ - */ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct os_mbuf; - -/** Type of UUID */ -enum { - /** 16-bit UUID (BT SIG assigned) */ - BLE_UUID_TYPE_16 = 16, - - /** 32-bit UUID (BT SIG assigned) */ - BLE_UUID_TYPE_32 = 32, - - /** 128-bit UUID */ - BLE_UUID_TYPE_128 = 128, -}; - -/** Generic UUID type, to be used only as a pointer */ -typedef struct { - /** Type of the UUID */ - uint8_t type; -} ble_uuid_t; - -/** 16-bit UUID */ -typedef struct { - ble_uuid_t u; - uint16_t value; -} ble_uuid16_t; - -/** 32-bit UUID */ -typedef struct { - ble_uuid_t u; - uint32_t value; -} ble_uuid32_t; - -/** 128-bit UUID */ -typedef struct { - ble_uuid_t u; - uint8_t value[16]; -} ble_uuid128_t; - -/** Universal UUID type, to be used for any-UUID static allocation */ -typedef union { - ble_uuid_t u; - ble_uuid16_t u16; - ble_uuid32_t u32; - ble_uuid128_t u128; -} ble_uuid_any_t; - -#define BLE_UUID16_INIT(uuid16) \ - { \ - .u.type = BLE_UUID_TYPE_16, \ - .value = (uuid16), \ - } - -#define BLE_UUID32_INIT(uuid32) \ - { \ - .u.type = BLE_UUID_TYPE_32, \ - .value = (uuid32), \ - } - -#define BLE_UUID128_INIT(uuid128...) \ - { \ - .u.type = BLE_UUID_TYPE_128, \ - .value = { uuid128 }, \ - } - -#define BLE_UUID16_DECLARE(uuid16) \ - ((ble_uuid_t *) (&(ble_uuid16_t) BLE_UUID16_INIT(uuid16))) - -#define BLE_UUID32_DECLARE(uuid32) \ - ((ble_uuid_t *) (&(ble_uuid32_t) BLE_UUID32_INIT(uuid32))) - -#define BLE_UUID128_DECLARE(uuid128...) \ - ((ble_uuid_t *) (&(ble_uuid128_t) BLE_UUID128_INIT(uuid128))) - -#define BLE_UUID16(u) \ - ((ble_uuid16_t *) (u)) - -#define BLE_UUID32(u) \ - ((ble_uuid32_t *) (u)) - -#define BLE_UUID128(u) \ - ((ble_uuid128_t *) (u)) - -/** Size of buffer needed to store UUID as a string. - * Includes trailing \0. - */ -#define BLE_UUID_STR_LEN (37) - -/** @brief Constructs a UUID object from a byte array. - * - * @param uuid On success, this gets populated with the constructed UUID. - * @param buf The source buffer to parse. - * @param len The size of the buffer, in bytes. - * - * @return 0 on success, BLE_HS_EINVAL if the source buffer does not contain - * a valid UUID. - */ -int ble_uuid_init_from_buf(ble_uuid_any_t *uuid, const void *buf, size_t len); - -/** @brief Compares two Bluetooth UUIDs. - * - * @param uuid1 The first UUID to compare. - * @param uuid2 The second UUID to compare. - * - * @return 0 if the two UUIDs are equal, nonzero if the UUIDs differ. - */ -int ble_uuid_cmp(const ble_uuid_t *uuid1, const ble_uuid_t *uuid2); - -/** @brief Copy Bluetooth UUID - * - * @param dst Destination UUID. - * @param src Source UUID. - */ -void ble_uuid_copy(ble_uuid_any_t *dst, const ble_uuid_t *src); - -/** @brief Converts the specified UUID to its string representation. - * - * Example string representations: - * o 16-bit: 0x1234 - * o 32-bit: 0x12345678 - * o 128-bit: 12345678-1234-1234-1234-123456789abc - * - * @param uuid The source UUID to convert. - * @param dst The destination buffer. - * - * @return A pointer to the supplied destination buffer. - */ -char *ble_uuid_to_str(const ble_uuid_t *uuid, char *dst); - -/** @brief Converts the specified 16-bit UUID to a uint16_t. - * - * @param uuid The source UUID to convert. - * - * @return The converted integer on success, NULL if the specified UUID is - * not 16 bits. - */ -uint16_t ble_uuid_u16(const ble_uuid_t *uuid); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif /* _BLE_HOST_UUID_H */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/access.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/access.h deleted file mode 100644 index 9f923cb9e..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/access.h +++ /dev/null @@ -1,681 +0,0 @@ -/** @file - * @brief Bluetooth Mesh Access Layer APIs. - */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __BT_MESH_ACCESS_H -#define __BT_MESH_ACCESS_H - -/** - * @brief Bluetooth Mesh Access Layer - * @defgroup bt_mesh_access Bluetooth Mesh Access Layer - * @ingroup bt_mesh - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#define BT_MESH_ADDR_UNASSIGNED 0x0000 -#define BT_MESH_ADDR_ALL_NODES 0xffff -#define BT_MESH_ADDR_PROXIES 0xfffc -#define BT_MESH_ADDR_FRIENDS 0xfffd -#define BT_MESH_ADDR_RELAYS 0xfffe - -#define BT_MESH_KEY_UNUSED 0xffff -#define BT_MESH_KEY_ANY 0xffff -#define BT_MESH_KEY_DEV 0xfffe -#define BT_MESH_KEY_DEV_LOCAL BT_MESH_KEY_DEV -#define BT_MESH_KEY_DEV_REMOTE 0xfffd -#define BT_MESH_KEY_DEV_ANY 0xfffc - -#define BT_MESH_ADDR_IS_UNICAST(addr) ((addr) && (addr) < 0x8000) -#define BT_MESH_ADDR_IS_GROUP(addr) ((addr) >= 0xc000 && (addr) <= 0xff00) -#define BT_MESH_ADDR_IS_VIRTUAL(addr) ((addr) >= 0x8000 && (addr) < 0xc000) -#define BT_MESH_ADDR_IS_RFU(addr) ((addr) >= 0xff00 && (addr) <= 0xfffb) - -#define BT_MESH_IS_DEV_KEY(key) (key == BT_MESH_KEY_DEV_LOCAL || \ - key == BT_MESH_KEY_DEV_REMOTE) - -#define BT_MESH_APP_SEG_SDU_MAX 12 -#define BT_MESH_TX_SDU_MAX (CONFIG_BT_MESH_TX_SEG_MAX * BT_MESH_APP_SEG_SDU_MAX) -#define BT_MESH_RX_SDU_MAX (CONFIG_BT_MESH_RX_SEG_MAX * BT_MESH_APP_SEG_SDU_MAX) -/** Helper to define a mesh element within an array. - * - * In case the element has no SIG or Vendor models the helper - * macro BT_MESH_MODEL_NONE can be given instead. - * - * @param _loc Location Descriptor. - * @param _mods Array of models. - * @param _vnd_mods Array of vendor models. - */ -#define BT_MESH_ELEM(_loc, _mods, _vnd_mods) \ -{ \ - .loc = (_loc), \ - .model_count = ARRAY_SIZE(_mods), \ - .models = (_mods), \ - .vnd_model_count = ARRAY_SIZE(_vnd_mods), \ - .vnd_models = (_vnd_mods), \ -} - -/** Abstraction that describes a Mesh Element */ -struct bt_mesh_elem { - /* Unicast Address. Set at runtime during provisioning. */ - uint16_t addr; - - /* Location Descriptor (GATT Bluetooth Namespace Descriptors) */ - const uint16_t loc; - - const uint8_t model_count; - const uint8_t vnd_model_count; - - struct bt_mesh_model * const models; - struct bt_mesh_model * const vnd_models; -}; - -/* Foundation Models */ -#define BT_MESH_MODEL_ID_CFG_SRV 0x0000 -#define BT_MESH_MODEL_ID_CFG_CLI 0x0001 -#define BT_MESH_MODEL_ID_HEALTH_SRV 0x0002 -#define BT_MESH_MODEL_ID_HEALTH_CLI 0x0003 - -/* Models from the Mesh Model Specification */ -#define BT_MESH_MODEL_ID_GEN_ONOFF_SRV 0x1000 -#define BT_MESH_MODEL_ID_GEN_ONOFF_CLI 0x1001 -#define BT_MESH_MODEL_ID_GEN_LEVEL_SRV 0x1002 -#define BT_MESH_MODEL_ID_GEN_LEVEL_CLI 0x1003 -#define BT_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV 0x1004 -#define BT_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI 0x1005 -#define BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV 0x1006 -#define BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV 0x1007 -#define BT_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI 0x1008 -#define BT_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV 0x1009 -#define BT_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV 0x100a -#define BT_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI 0x100b -#define BT_MESH_MODEL_ID_GEN_BATTERY_SRV 0x100c -#define BT_MESH_MODEL_ID_GEN_BATTERY_CLI 0x100d -#define BT_MESH_MODEL_ID_GEN_LOCATION_SRV 0x100e -#define BT_MESH_MODEL_ID_GEN_LOCATION_SETUPSRV 0x100f -#define BT_MESH_MODEL_ID_GEN_LOCATION_CLI 0x1010 -#define BT_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV 0x1011 -#define BT_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV 0x1012 -#define BT_MESH_MODEL_ID_GEN_USER_PROP_SRV 0x1013 -#define BT_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV 0x1014 -#define BT_MESH_MODEL_ID_GEN_PROP_CLI 0x1015 -#define BT_MESH_MODEL_ID_SENSOR_SRV 0x1100 -#define BT_MESH_MODEL_ID_SENSOR_SETUP_SRV 0x1101 -#define BT_MESH_MODEL_ID_SENSOR_CLI 0x1102 -#define BT_MESH_MODEL_ID_TIME_SRV 0x1200 -#define BT_MESH_MODEL_ID_TIME_SETUP_SRV 0x1201 -#define BT_MESH_MODEL_ID_TIME_CLI 0x1202 -#define BT_MESH_MODEL_ID_SCENE_SRV 0x1203 -#define BT_MESH_MODEL_ID_SCENE_SETUP_SRV 0x1204 -#define BT_MESH_MODEL_ID_SCENE_CLI 0x1205 -#define BT_MESH_MODEL_ID_SCHEDULER_SRV 0x1206 -#define BT_MESH_MODEL_ID_SCHEDULER_SETUP_SRV 0x1207 -#define BT_MESH_MODEL_ID_SCHEDULER_CLI 0x1208 -#define BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV 0x1300 -#define BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV 0x1301 -#define BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI 0x1302 -#define BT_MESH_MODEL_ID_LIGHT_CTL_SRV 0x1303 -#define BT_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV 0x1304 -#define BT_MESH_MODEL_ID_LIGHT_CTL_CLI 0x1305 -#define BT_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV 0x1306 -#define BT_MESH_MODEL_ID_LIGHT_HSL_SRV 0x1307 -#define BT_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV 0x1308 -#define BT_MESH_MODEL_ID_LIGHT_HSL_CLI 0x1309 -#define BT_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV 0x130a -#define BT_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV 0x130b -#define BT_MESH_MODEL_ID_LIGHT_XYL_SRV 0x130c -#define BT_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV 0x130d -#define BT_MESH_MODEL_ID_LIGHT_XYL_CLI 0x130e -#define BT_MESH_MODEL_ID_LIGHT_LC_SRV 0x130f -#define BT_MESH_MODEL_ID_LIGHT_LC_SETUPSRV 0x1310 -#define BT_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311 - -/** Message sending context. */ -struct bt_mesh_msg_ctx { - /** NetKey Index of the subnet to send the message on. */ - uint16_t net_idx; - - /** AppKey Index to encrypt the message with. */ - uint16_t app_idx; - - /** Remote address. */ - uint16_t addr; - - /** Destination address of a received message. Not used for sending. */ - uint16_t recv_dst; - - /** RSSI of received packet. Not used for sending. */ - int8_t recv_rssi; - - /** Received TTL value. Not used for sending. */ - uint8_t recv_ttl; - - /** Force sending reliably by using segment acknowledgement */ - bool send_rel; - - /** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */ - uint8_t send_ttl; -}; - -struct bt_mesh_model_op { - /* OpCode encoded using the BT_MESH_MODEL_OP_* macros */ - const uint32_t opcode; - - /* Minimum required message length */ - const size_t min_len; - - /* Message handler for the opcode */ - void (*const func)(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf); -}; - -#define BT_MESH_MODEL_OP_1(b0) (b0) -#define BT_MESH_MODEL_OP_2(b0, b1) (((b0) << 8) | (b1)) -#define BT_MESH_MODEL_OP_3(b0, cid) ((((b0) << 16) | 0xc00000) | (cid)) - -#define BT_MESH_MODEL_OP_END { 0, 0, NULL } -#define BT_MESH_MODEL_NO_OPS ((struct bt_mesh_model_op []) \ - { BT_MESH_MODEL_OP_END }) - -/** Helper to define an empty model array */ -#define BT_MESH_MODEL_NONE ((struct bt_mesh_model []){}) - -/** Length of a short Mesh MIC. */ -#define BT_MESH_MIC_SHORT 4 -/** Length of a long Mesh MIC. */ -#define BT_MESH_MIC_LONG 8 - -/** @def BT_MESH_MODEL_OP_LEN - * - * @brief Helper to determine the length of an opcode. - * - * @param _op Opcode. - */ -#define BT_MESH_MODEL_OP_LEN(_op) ((_op) <= 0xff ? 1 : (_op) <= 0xffff ? 2 : 3) - -/** @def BT_MESH_MODEL_BUF_LEN - * - * @brief Helper for model message buffer length. - * - * Returns the length of a Mesh model message buffer, including the opcode - * length and a short MIC. - * - * @param _op Opcode of the message. - * @param _payload_len Length of the model payload. - */ -#define BT_MESH_MODEL_BUF_LEN(_op, _payload_len) \ - (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_SHORT) - -/** @def BT_MESH_MODEL_BUF_LEN_LONG_MIC - * - * @brief Helper for model message buffer length. - * - * Returns the length of a Mesh model message buffer, including the opcode - * length and a long MIC. - * - * @param _op Opcode of the message. - * @param _payload_len Length of the model payload. - */ -#define BT_MESH_MODEL_BUF_LEN_LONG_MIC(_op, _payload_len) \ - (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_LONG) - -/** @def BT_MESH_MODEL_BUF_DEFINE - * - * @brief Define a Mesh model message buffer using @ref NET_BUF_SIMPLE. - * - * @param _op Opcode of the message. - * @param _payload_len Length of the model message payload. - */ -#define BT_MESH_MODEL_BUF(_op, _payload_len) \ - NET_BUF_SIMPLE(BT_MESH_MODEL_BUF_LEN(_op, (_payload_len))) - -/** @def BT_MESH_MODEL_CB - * - * @brief Composition data SIG model entry with callback functions. - * - * @param _id Model ID. - * @param _op Array of model opcode handlers. - * @param _pub Model publish parameters. - * @param _user_data User data for the model. - * @param _cb Callback structure, or NULL to keep no callbacks. - */ -#define BT_MESH_MODEL_CB(_id, _op, _pub, _user_data, _cb) \ -{ \ - .id = (_id), \ - .op = _op, \ - .keys = { [0 ... (CONFIG_BT_MESH_MODEL_KEY_COUNT - 1)] = \ - BT_MESH_KEY_UNUSED }, \ - .pub = _pub, \ - .groups = { [0 ... (CONFIG_BT_MESH_MODEL_GROUP_COUNT - 1)] = \ - BT_MESH_ADDR_UNASSIGNED }, \ - .user_data = _user_data, \ - .cb = _cb, \ -} - -/** @def BT_MESH_MODEL_VND_CB - * - * @brief Composition data vendor model entry with callback functions. - * - * @param _company Company ID. - * @param _id Model ID. - * @param _op Array of model opcode handlers. - * @param _pub Model publish parameters. - * @param _user_data User data for the model. - * @param _cb Callback structure, or NULL to keep no callbacks. - */ -#define BT_MESH_MODEL_VND_CB(_company, _id, _op, _pub, _user_data, _cb) \ -{ \ - .vnd.company = (_company), \ - .vnd.id = (_id), \ - .op = _op, \ - .pub = _pub, \ - .keys = { [0 ... (CONFIG_BT_MESH_MODEL_KEY_COUNT - 1)] = \ - BT_MESH_KEY_UNUSED }, \ - .groups = { [0 ... (CONFIG_BT_MESH_MODEL_GROUP_COUNT - 1)] = \ - BT_MESH_ADDR_UNASSIGNED }, \ - .user_data = _user_data, \ - .cb = _cb, \ -} - - -/** @def BT_MESH_MODEL - * - * @brief Composition data SIG model entry. - * - * @param _id Model ID. - * @param _op Array of model opcode handlers. - * @param _pub Model publish parameters. - * @param _user_data User data for the model. - */ -#define BT_MESH_MODEL(_id, _op, _pub, _user_data) \ - BT_MESH_MODEL_CB(_id, _op, _pub, _user_data, NULL) - -/** @def BT_MESH_MODEL_VND - * - * @brief Composition data vendor model entry. - * - * @param _company Company ID. - * @param _id Model ID. - * @param _op Array of model opcode handlers. - * @param _pub Model publish parameters. - * @param _user_data User data for the model. - */ -#define BT_MESH_MODEL_VND(_company, _id, _op, _pub, _user_data) \ - BT_MESH_MODEL_VND_CB(_company, _id, _op, _pub, _user_data, NULL) - -/** @def BT_MESH_TRANSMIT - * - * @brief Encode transmission count & interval steps. - * - * @param count Number of retransmissions (first transmission is excluded). - * @param int_ms Interval steps in milliseconds. Must be greater than 0, - * less than or equal to 320, and a multiple of 10. - * - * @return Mesh transmit value that can be used e.g. for the default - * values of the configuration model data. - */ -#define BT_MESH_TRANSMIT(count, int_ms) ((count) | (((int_ms / 10) - 1) << 3)) - -/** @def BT_MESH_TRANSMIT_COUNT - * - * @brief Decode transmit count from a transmit value. - * - * @param transmit Encoded transmit count & interval value. - * - * @return Transmission count (actual transmissions is N + 1). - */ -#define BT_MESH_TRANSMIT_COUNT(transmit) (((transmit) & (uint8_t)BIT_MASK(3))) - -/** @def BT_MESH_TRANSMIT_INT - * - * @brief Decode transmit interval from a transmit value. - * - * @param transmit Encoded transmit count & interval value. - * - * @return Transmission interval in milliseconds. - */ -#define BT_MESH_TRANSMIT_INT(transmit) ((((transmit) >> 3) + 1) * 10) - -/** @def BT_MESH_PUB_TRANSMIT - * - * @brief Encode Publish Retransmit count & interval steps. - * - * @param count Number of retransmissions (first transmission is excluded). - * @param int_ms Interval steps in milliseconds. Must be greater than 0 - * and a multiple of 50. - * - * @return Mesh transmit value that can be used e.g. for the default - * values of the configuration model data. - */ -#define BT_MESH_PUB_TRANSMIT(count, int_ms) BT_MESH_TRANSMIT(count, \ - (int_ms) / 5) - -/** @def BT_MESH_PUB_TRANSMIT_COUNT - * - * @brief Decode Pubhlish Retransmit count from a given value. - * - * @param transmit Encoded Publish Retransmit count & interval value. - * - * @return Retransmission count (actual transmissions is N + 1). - */ -#define BT_MESH_PUB_TRANSMIT_COUNT(transmit) BT_MESH_TRANSMIT_COUNT(transmit) - -/** @def BT_MESH_PUB_TRANSMIT_INT - * - * @brief Decode Publish Retransmit interval from a given value. - * - * @param transmit Encoded Publish Retransmit count & interval value. - * - * @return Transmission interval in milliseconds. - */ -#define BT_MESH_PUB_TRANSMIT_INT(transmit) ((((transmit) >> 3) + 1) * 50) - -/** Model publication context. */ -struct bt_mesh_model_pub { - /** The model the context belongs to. Initialized by the stack. */ - struct bt_mesh_model *mod; - - uint16_t addr; /**< Publish Address. */ - uint16_t key; /**< Publish AppKey Index. */ - - uint8_t ttl; /**< Publish Time to Live. */ - uint8_t retransmit; /**< Retransmit Count & Interval Steps. */ - uint8_t period; /**< Publish Period. */ - uint8_t period_div:4, /**< Divisor for the Period. */ - cred:1, /**< Friendship Credentials Flag. */ - send_rel:1, - fast_period:1,/**< Use FastPeriodDivisor */ - count:3; /**< Retransmissions left. */ - - uint32_t period_start; /**< Start of the current period. */ - - /** @brief Publication buffer, containing the publication message. - * - * The application is expected to initialize this with - * a valid os_mbuf pointer, with the help of e.g. - * the NET_BUF_SIMPLE() macro. The publication buffer must - * contain a valid publication message before calling the - * bt_mesh_model_publish() API or after the publication's - * @ref bt_mesh_model_pub.update callback has been called - * and returned success. The buffer must be created outside - * of function context, i.e. it must not be on the stack. - * This is most conveniently acheived by creating it inline - * when declaring the publication context: - * - * static struct bt_mesh_model_pub my_pub = { - * .msg = NET_BUF_SIMPLE(size), - * }; - */ - struct os_mbuf *msg; - - /** @brief Callback for updating the publication buffer. - * - * When set to NULL, the model is assumed not to support - * periodic publishing. When set to non-NULL the callback - * will be called periodically and is expected to update - * @ref bt_mesh_model_pub.msg with a valid publication - * message. - * - * If the callback returns non-zero, the publication is skipped - * and will resume on the next periodic publishing interval. - * - * - * @param mod The Model the Publication Context belogs to. - * - * @return Zero on success or (negative) error code otherwise. - */ - int (*update)(struct bt_mesh_model *mod); - - /** Publish Period Timer. Only for stack-internal use. */ - struct k_delayed_work timer; -}; - -/** Model callback functions. */ -struct bt_mesh_model_cb { - /** @brief Set value handler of user data tied to the model. - * - * @sa settings_handler::h_set - * - * @param model Model to set the persistent data of. - * @param name Name/key of the settings item. - * @param val Data from the backend. - * - * @return 0 on success, error otherwise. - */ - int (*const settings_set)(struct bt_mesh_model *model, - const char *name, char *val); - - /** @brief Callback called when the mesh is started. - * - * This handler gets called after the node has been provisioned, or - * after all mesh data has been loaded from persistent storage. - * - * @sa settings_handler::h_commit - * - * @param model Model this callback belongs to. - * - * @return 0 on success, error otherwise. - */ - int (*const start)(struct bt_mesh_model *model); - - /** @brief Model init callback. - * - * Called on every model instance during mesh initialization. - * - * - * If any of the model init callbacks return an error, the Mesh - * subsystem initialization will be aborted, and the error will be - * returned to the caller of @ref bt_mesh_init. - * - * @param model Model to be initialized. - * - * @return 0 on success, error otherwise. - */ - int (*const init)(struct bt_mesh_model *model); - - /** @brief Model reset callback. - * - * Called when the mesh node is reset. All model data is deleted on - * reset, and the model should clear its state. - * - * @note If the model stores any persistent data, this needs to be - * erased manually. - * - * @param model Model this callback belongs to. - */ - void (*const reset)(struct bt_mesh_model *model); -}; - -/** Abstraction that describes a Mesh Model instance */ -struct bt_mesh_model { - union { - const uint16_t id; - struct { - uint16_t company; - uint16_t id; - } vnd; - }; - - /* Internal information, mainly for persistent storage */ - uint8_t elem_idx; /* Belongs to Nth element */ - uint8_t mod_idx; /* Is the Nth model in the element */ - uint16_t flags; /* Model flags for internal bookkeeping */ - - /* Model Publication */ - struct bt_mesh_model_pub * const pub; - - /* AppKey List */ - uint16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT]; - - /* Subscription List (group or virtual addresses) */ - uint16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT]; - - const struct bt_mesh_model_op * const op; - - /* Model callback structure. */ - const struct bt_mesh_model_cb * const cb; - -#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS) - /* Pointer to the next model in a model extension tree. */ - struct bt_mesh_model *next; - /* Pointer to the first model this model extends. */ - struct bt_mesh_model *extends; -#endif - /* Model-specific user data */ - void *user_data; -}; - -struct bt_mesh_send_cb { - void (*start)(uint16_t duration, int err, void *cb_data); - void (*end)(int err, void *cb_data); -}; - -void bt_mesh_model_msg_init(struct os_mbuf *msg, uint32_t opcode); - -/** Special TTL value to request using configured default TTL */ -#define BT_MESH_TTL_DEFAULT 0xff - -/** Maximum allowed TTL value */ -#define BT_MESH_TTL_MAX 0x7f - -/** - * @brief Send an Access Layer message. - * - * @param model Mesh (client) Model that the message belongs to. - * @param ctx Message context, includes keys, TTL, etc. - * @param msg Access Layer payload (the actual message to be sent). - * @param cb Optional "message sent" callback. - * @param cb_data User data to be passed to the callback. - * - * @return 0 on success, or (negative) error code on failure. - */ -int bt_mesh_model_send(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *msg, - const struct bt_mesh_send_cb *cb, - void *cb_data); - -/** - * @brief Send a model publication message. - * - * Before calling this function, the user needs to ensure that the model - * publication message (@ref bt_mesh_model_pub.msg) contains a valid - * message to be sent. Note that this API is only to be used for - * non-period publishing. For periodic publishing the app only needs - * to make sure that @ref bt_mesh_model_pub.msg contains a valid message - * whenever the @ref bt_mesh_model_pub.update callback is called. - * - * @param model Mesh (client) Model that's publishing the message. - * - * @return 0 on success, or (negative) error code on failure. - */ -int bt_mesh_model_publish(struct bt_mesh_model *model); - -/** - * @brief Get the element that a model belongs to. - * - * @param mod Mesh model. - * - * @return Pointer to the element that the given model belongs to. - */ -struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod); - -/** @brief Find a SIG model. - * - * @param elem Element to search for the model in. - * @param id Model ID of the model. - * - * @return A pointer to the Mesh model matching the given parameters, or NULL - * if no SIG model with the given ID exists in the given element. - */ -struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, - uint16_t id); - -/** @brief Find a vendor model. - * - * @param elem Element to search for the model in. - * @param company Company ID of the model. - * @param id Model ID of the model. - * - * @return A pointer to the Mesh model matching the given parameters, or NULL - * if no vendor model with the given ID exists in the given element. - */ -struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, - uint16_t company, uint16_t id); - -/** @brief Get whether the model is in the primary element of the device. - * - * @param mod Mesh model. - * - * @return true if the model is on the primary element, false otherwise. - */ -static inline bool bt_mesh_model_in_primary(const struct bt_mesh_model *mod) -{ - return (mod->elem_idx == 0); -} - -/** @brief Immediately store the model's user data in persistent storage. - * - * @param mod Mesh model. - * @param vnd This is a vendor model. - * @param name Name/key of the settings item. - * @param data Model data to store, or NULL to delete any model data. - * @param data_len Length of the model data. - * - * @return 0 on success, or (negative) error code on failure. - */ -int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, - const char *name, const void *data, size_t data_len); - -/** @brief Let a model extend another. - * - * Mesh models may be extended to reuse their functionality, forming a more - * complex model. A Mesh model may extend any number of models, in any element. - * The extensions may also be nested, ie a model that extends another may itself - * be extended. Extensions may not be cyclical, and a model can only be extended - * by one other model. - * - * A set of models that extend each other form a model extension tree. - * - * All models in an extension tree share one subscription list per element. The - * access layer will utilize the combined subscription list of all models in an - * extension tree and element, giving the models extended subscription list - * capacity. - * - * @param[in] mod Mesh model. - * @param[in] base_mod The model being extended. - * - * @retval 0 Successfully extended the base_mod model. - * @retval -EALREADY The base_mod model is already extended. - */ -int bt_mesh_model_extend(struct bt_mesh_model *mod, - struct bt_mesh_model *base_mod); - -/** Node Composition */ -struct bt_mesh_comp { - uint16_t cid; - uint16_t pid; - uint16_t vid; - - size_t elem_count; - struct bt_mesh_elem *elem; -}; - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif /* __BT_MESH_ACCESS_H */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/atomic.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/atomic.h deleted file mode 100644 index 2c7317948..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/atomic.h +++ /dev/null @@ -1,409 +0,0 @@ -/* atomic operations */ - -/* - * Copyright (c) 1997-2015, Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __ATOMIC_H__ -#define __ATOMIC_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef int atomic_t; -typedef atomic_t atomic_val_t; - -/** - * @defgroup atomic_apis Atomic Services APIs - * @ingroup kernel_apis - * @{ - */ - -/** - * @brief Atomic compare-and-set. - * - * This routine performs an atomic compare-and-set on @a target. If the current - * value of @a target equals @a old_value, @a target is set to @a new_value. - * If the current value of @a target does not equal @a old_value, @a target - * is left unchanged. - * - * @param target Address of atomic variable. - * @param old_value Original value to compare against. - * @param new_value New value to store. - * @return 1 if @a new_value is written, 0 otherwise. - */ -static inline int atomic_cas(atomic_t *target, atomic_val_t old_value, - atomic_val_t new_value) -{ - return __atomic_compare_exchange_n(target, &old_value, new_value, - 0, __ATOMIC_SEQ_CST, - __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic addition. - * - * This routine performs an atomic addition on @a target. - * - * @param target Address of atomic variable. - * @param value Value to add. - * - * @return Previous value of @a target. - */ -static inline atomic_val_t atomic_add(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_add(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic subtraction. - * - * This routine performs an atomic subtraction on @a target. - * - * @param target Address of atomic variable. - * @param value Value to subtract. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic increment. - * - * This routine performs an atomic increment by 1 on @a target. - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_inc(atomic_t *target) -{ - return atomic_add(target, 1); -} - -/** - * - * @brief Atomic decrement. - * - * This routine performs an atomic decrement by 1 on @a target. - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_dec(atomic_t *target) -{ - return atomic_sub(target, 1); -} - -/** - * - * @brief Atomic get. - * - * This routine performs an atomic read on @a target. - * - * @param target Address of atomic variable. - * - * @return Value of @a target. - */ - -static inline atomic_val_t atomic_get(const atomic_t *target) -{ - return __atomic_load_n(target, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic get-and-set. - * - * This routine atomically sets @a target to @a value and returns - * the previous value of @a target. - * - * @param target Address of atomic variable. - * @param value Value to write to @a target. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value) -{ - /* This builtin, as described by Intel, is not a traditional - * test-and-set operation, but rather an atomic exchange operation. It - * writes value into *ptr, and returns the previous contents of *ptr. - */ - return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic clear. - * - * This routine atomically sets @a target to zero and returns its previous - * value. (Hence, it is equivalent to atomic_set(target, 0).) - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_clear(atomic_t *target) -{ - return atomic_set(target, 0); -} - -/** - * - * @brief Atomic bitwise inclusive OR. - * - * This routine atomically sets @a target to the bitwise inclusive OR of - * @a target and @a value. - * - * @param target Address of atomic variable. - * @param value Value to OR. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic bitwise exclusive OR (XOR). - * - * This routine atomically sets @a target to the bitwise exclusive OR (XOR) of - * @a target and @a value. - * - * @param target Address of atomic variable. - * @param value Value to XOR - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_xor(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic bitwise AND. - * - * This routine atomically sets @a target to the bitwise AND of @a target - * and @a value. - * - * @param target Address of atomic variable. - * @param value Value to AND. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic bitwise NAND. - * - * This routine atomically sets @a target to the bitwise NAND of @a target - * and @a value. (This operation is equivalent to target = ~(target & value).) - * - * @param target Address of atomic variable. - * @param value Value to NAND. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_nand(target, value, __ATOMIC_SEQ_CST); -} - - /** - * @brief Initialize an atomic variable. - * - * This macro can be used to initialize an atomic variable. For example, - * @code atomic_t my_var = ATOMIC_INIT(75); @endcode - * - * @param i Value to assign to atomic variable. - */ -#define ATOMIC_INIT(i) (i) - - /** - * @cond INTERNAL_HIDDEN - */ - -#define ATOMIC_BITS (sizeof(atomic_val_t) * 8) -#define ATOMIC_MASK(bit) (1 << ((bit) & (ATOMIC_BITS - 1))) -#define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS)) - - /** - * INTERNAL_HIDDEN @endcond - */ - - /** - * @brief Define an array of atomic variables. - * - * This macro defines an array of atomic variables containing at least - * @a num_bits bits. - * - * @note - * If used from file scope, the bits of the array are initialized to zero; - * if used from within a function, the bits are left uninitialized. - * - * @param name Name of array of atomic variables. - * @param num_bits Number of bits needed. - */ -#define ATOMIC_DEFINE(name, num_bits) \ - atomic_t name[1 + ((num_bits) - 1) / ATOMIC_BITS] - - /** - * @brief Atomically test a bit. - * - * This routine tests whether bit number @a bit of @a target is set or not. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return 1 if the bit was set, 0 if it wasn't. - */ - static inline int - atomic_test_bit(const atomic_t *target, int bit) - { - atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit)); - - return (1 & (val >> (bit & (ATOMIC_BITS - 1)))); - } - - /** - * @brief Atomically test and clear a bit. - * - * Atomically clear bit number @a bit of @a target and return its old value. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return 1 if the bit was set, 0 if it wasn't. - */ - static inline int - atomic_test_and_clear_bit(atomic_t *target, int bit) - { - atomic_val_t mask = ATOMIC_MASK(bit); - atomic_val_t old; - - old = atomic_and(ATOMIC_ELEM(target, bit), ~mask); - - return (old & mask) != 0; - } - - /** - * @brief Atomically set a bit. - * - * Atomically set bit number @a bit of @a target and return its old value. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return 1 if the bit was set, 0 if it wasn't. - */ - static inline int - atomic_test_and_set_bit(atomic_t *target, int bit) - { - atomic_val_t mask = ATOMIC_MASK(bit); - atomic_val_t old; - - old = atomic_or(ATOMIC_ELEM(target, bit), mask); - - return (old & mask) != 0; - } - - /** - * @brief Atomically clear a bit. - * - * Atomically clear bit number @a bit of @a target. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return N/A - */ - static inline void - atomic_clear_bit(atomic_t *target, int bit) - { - atomic_val_t mask = ATOMIC_MASK(bit); - - atomic_and(ATOMIC_ELEM(target, bit), ~mask); - } - - /** - * @brief Atomically set a bit. - * - * Atomically set bit number @a bit of @a target. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return N/A - */ - static inline void - atomic_set_bit(atomic_t *target, int bit) - { - atomic_val_t mask = ATOMIC_MASK(bit); - - atomic_or(ATOMIC_ELEM(target, bit), mask); - } - -/** -* @brief Atomically set a bit to a given value. -* -* Atomically set bit number @a bit of @a target to value @a val. -* The target may be a single atomic variable or an array of them. -* -* @param target Address of atomic variable or array. -* @param bit Bit number (starting from 0). -* @param val true for 1, false for 0. -* -* @return N/A -*/ -static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val) -{ - atomic_val_t mask = ATOMIC_MASK(bit); - - if (val) { - (void)atomic_or(ATOMIC_ELEM(target, bit), mask); - } else { - (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask); - } -} - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ATOMIC_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/cdb.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/cdb.h deleted file mode 100644 index 050ccf281..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/cdb.h +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2019 Tobias Svehagen - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef _BLUETOOTH_MESH_CDB_H_ -#define _BLUETOOTH_MESH_CDB_H_ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" - -#if MYNEWT_VAL(BLE_MESH_CDB) -#define NODE_COUNT CONFIG_BT_MESH_NODE_COUNT -#define SUBNET_COUNT CONFIG_BT_MESH_SUBNET_COUNT -#define APP_KEY_COUNT CONFIG_BT_MESH_APP_KEY_COUNT -#else -#define NODE_COUNT 0 -#define SUBNET_COUNT 0 -#define APP_KEY_COUNT 0 -#endif - -#include "atomic.h" - -enum { - BT_MESH_CDB_NODE_CONFIGURED, - BT_MESH_CDB_NODE_BLACKLISTED, - - BT_MESH_CDB_NODE_FLAG_COUNT -}; - -struct bt_mesh_cdb_node { - uint8_t uuid[16]; - uint16_t addr; - uint16_t net_idx; - uint8_t num_elem; - uint8_t dev_key[16]; - - ATOMIC_DEFINE(flags, BT_MESH_CDB_NODE_FLAG_COUNT); -}; - -struct bt_mesh_cdb_subnet { - uint16_t net_idx; - - bool kr_flag; - uint8_t kr_phase; - - struct { - uint8_t net_key[16]; - } keys[2]; -}; - -struct bt_mesh_cdb_app_key { - uint16_t net_idx; - uint16_t app_idx; - - struct { - uint8_t app_key[16]; - } keys[2]; -}; - -enum { - BT_MESH_CDB_VALID, - BT_MESH_CDB_SUBNET_PENDING, - BT_MESH_CDB_KEYS_PENDING, - BT_MESH_CDB_NODES_PENDING, - BT_MESH_CDB_IVU_IN_PROGRESS, - - BT_MESH_CDB_FLAG_COUNT, -}; - -struct bt_mesh_cdb { - uint32_t iv_index; - - ATOMIC_DEFINE(flags, BT_MESH_CDB_FLAG_COUNT); - - struct bt_mesh_cdb_node nodes[NODE_COUNT]; - struct bt_mesh_cdb_subnet subnets[SUBNET_COUNT]; - struct bt_mesh_cdb_app_key app_keys[APP_KEY_COUNT]; -}; - -extern struct bt_mesh_cdb bt_mesh_cdb; - -/** @brief Create the Mesh Configuration Database. - * - * Create and initialize the Mesh Configuration Database. A primary subnet, - * ie one with NetIdx 0, will be added and the provided key will be used as - * NetKey for that subnet. - * - * @param key The NetKey to be used for the primary subnet. - * - * @return 0 on success or negative error code on failure. - */ -int bt_mesh_cdb_create(const uint8_t key[16]); - -/** @brief Clear the Mesh Configuration Database. - * - * Remove all nodes, subnets and app-keys stored in the database and mark - * the database as invalid. The data will be cleared from persistent storage - * if CONFIG_BT_SETTINGS is enabled. - */ -void bt_mesh_cdb_clear(void); - -/** @brief Set and store the IV Index and IV Update flag. - * - * The IV Index stored in the CDB will be the one used during provisioning - * of new nodes. This function is generally only used from inside the stack. - * - * This function will store the data to persistent storage if - * CONFIG_BT_SETTINGS is enabled. - * - * @param iv_index The new IV Index to use. - * @param iv_update True if there is an ongoing IV Update procedure. - */ -void bt_mesh_cdb_iv_update(uint32_t iv_index, bool iv_update); - -/** @brief Allocate a node. - * - * Allocate a new node in the CDB. - * - * @param uuid UUID of the node. - * @param addr Address of the node's primary element. If 0, the lowest - * possible address available will be assigned to the node. - * @param num_elem Number of elements that the node has. - * @param net_idx NetIdx that the node was provisioned to. - * - * @return The new node or NULL if it cannot be allocated. - */ -struct bt_mesh_cdb_node *bt_mesh_cdb_node_alloc(const uint8_t uuid[16], uint16_t addr, - uint8_t num_elem, uint16_t net_idx); - -/** @brief Delete a node. - * - * Delete a node from the CDB. - * - * @param node The node to be deleted. - * @param store If true, the node will be cleared from persistent storage. - */ -void bt_mesh_cdb_node_del(struct bt_mesh_cdb_node *node, bool store); - -/** @brief Get a node by address. - * - * Try to find the node that has the provided address assigned to one of its - * elements. - * - * @param addr Address of the element to look for. - * - * @return The node that has an element with address addr or NULL if no such - * node exists. - */ -struct bt_mesh_cdb_node *bt_mesh_cdb_node_get(uint16_t addr); - -/** @brief Store node to persistent storage. - * - * @param node Node to be stored. - */ -void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node); - -enum { - BT_MESH_CDB_ITER_STOP = 0, - BT_MESH_CDB_ITER_CONTINUE, -}; - -/** @typedef bt_mesh_cdb_node_func_t - * @brief Node iterator callback. - * - * @param node Node found. - * @param user_data Data given. - * - * @return BT_MESH_CDB_ITER_CONTINUE to continue to iterate through the nodes - * or BT_MESH_CDB_ITER_STOP to stop. - */ -typedef uint8_t (*bt_mesh_cdb_node_func_t)(struct bt_mesh_cdb_node *node, - void *user_data); - -/** @brief Node iterator. - * - * Iterate nodes in the Mesh Configuration Database. The callback function - * will only be called for valid, ie allocated, nodes. - * - * @param func Callback function. - * @param user_data Data to pass to the callback. - */ -void bt_mesh_cdb_node_foreach(bt_mesh_cdb_node_func_t func, void *user_data); - -/** @brief Allocate a subnet. - * - * Allocate a new subnet in the CDB. - * - * @param net_idx NetIdx of the subnet. - * - * @return The new subnet or NULL if it cannot be allocated. - */ -struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_alloc(uint16_t net_idx); - -/** @brief Delete a subnet. - * - * Delete a subnet from the CDB. - * - * @param sub The subnet to be deleted. - * @param store If true, the subnet will be cleared from persistent storage. - */ -void bt_mesh_cdb_subnet_del(struct bt_mesh_cdb_subnet *sub, bool store); - -/** @brief Get a subnet by NetIdx - * - * Try to find the subnet with the specified NetIdx. - * - * @param net_idx NetIdx of the subnet to look for. - * - * @return The subnet with the specified NetIdx or NULL if no such subnet - * exists. - */ -struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_get(uint16_t net_idx); - -/** @brief Store subnet to persistent storage. - * - * @param sub Subnet to be stored. - */ -void bt_mesh_cdb_subnet_store(const struct bt_mesh_cdb_subnet *sub); - -/** @brief Get the flags for a subnet - * - * @param sub The subnet to get flags for. - * - * @return The flags for the subnet. - */ -uint8_t bt_mesh_cdb_subnet_flags(const struct bt_mesh_cdb_subnet *sub); - - -/** @brief Allocate an application key. - * - * Allocate a new application key in the CDB. - * - * @param net_idx NetIdx of NetKey that the application key is bound to. - * @param app_idx AppIdx of the application key. - * - * @return The new application key or NULL if it cannot be allocated. - */ -struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_alloc(uint16_t net_idx, - uint16_t app_idx); - -/** @brief Delete an application key. - * - * Delete an application key from the CDB. - * - * @param key The application key to be deleted. - * @param store If true, the key will be cleared from persistent storage. - */ -void bt_mesh_cdb_app_key_del(struct bt_mesh_cdb_app_key *key, bool store); - -/** @brief Get an application key by AppIdx - * - * Try to find the application key with the specified AppIdx. - * - * @param app_idx AppIdx of the application key to look for. - * - * @return The application key with the specified AppIdx or NULL if no such key - * exists. - */ -struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(uint16_t app_idx); - -/** @brief Store application key to persistent storage. - * - * @param key Application key to be stored. - */ -void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key); - -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_CDB_H_ */ \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/cfg.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/cfg.h deleted file mode 100644 index 378f0a0aa..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/cfg.h +++ /dev/null @@ -1,485 +0,0 @@ -/** @file - * @brief Bluetooth Mesh Runtime Configuration APIs. - */ - -/* - * Copyright (c) 2020 Nordic Semiconductor - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef _BT_MESH_CFG_H_ -#define _BT_MESH_CFG_H_ - -#include -#include -#include - -/** - * @brief Bluetooth Mesh Runtime Configuration API - * @defgroup bt_mesh_cfg Bluetooth Mesh Runtime Configuration - * @ingroup bt_mesh - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** Bluetooth Mesh Feature states */ -enum bt_mesh_feat_state { - /** Feature is supported, but disabled. */ - BT_MESH_FEATURE_DISABLED, - /** Feature is supported and enabled. */ - BT_MESH_FEATURE_ENABLED, - /** Feature is not supported, and cannot be enabled. */ - BT_MESH_FEATURE_NOT_SUPPORTED, -}; - -/* Legacy feature defines */ -#define BT_MESH_RELAY_DISABLED BT_MESH_FEATURE_DISABLED -#define BT_MESH_RELAY_ENABLED BT_MESH_FEATURE_ENABLED -#define BT_MESH_RELAY_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED - -#define BT_MESH_BEACON_DISABLED BT_MESH_FEATURE_DISABLED -#define BT_MESH_BEACON_ENABLED BT_MESH_FEATURE_ENABLED - -#define BT_MESH_GATT_PROXY_DISABLED BT_MESH_FEATURE_DISABLED -#define BT_MESH_GATT_PROXY_ENABLED BT_MESH_FEATURE_ENABLED -#define BT_MESH_GATT_PROXY_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED - -#define BT_MESH_FRIEND_DISABLED BT_MESH_FEATURE_DISABLED -#define BT_MESH_FRIEND_ENABLED BT_MESH_FEATURE_ENABLED -#define BT_MESH_FRIEND_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED - -#define BT_MESH_NODE_IDENTITY_STOPPED BT_MESH_FEATURE_DISABLED -#define BT_MESH_NODE_IDENTITY_RUNNING BT_MESH_FEATURE_ENABLED -#define BT_MESH_NODE_IDENTITY_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED - -/** @brief Enable or disable sending of the Secure Network Beacon. - * - * @param beacon New Secure Network Beacon state. - */ -void bt_mesh_beacon_set(bool beacon); - -/** @brief Get the current Secure Network Beacon state. - * - * @returns Whether the Secure Network Beacon feature is enabled. - */ -bool bt_mesh_beacon_enabled(void); - -/** @brief Set the default TTL value. - * - * The default TTL value is used when no explicit TTL value is set. Models will - * use the default TTL value when @ref bt_mesh_msg_ctx::send_ttl is - * @ref BT_MESH_TTL_DEFAULT. - * - * @param default_ttl The new default TTL value. Valid values are 0x00 and 0x02 - * to @ref BT_MESH_TTL_MAX. - * - * @retval 0 Successfully set the default TTL value. - * @retval -EINVAL Invalid TTL value. - */ -int bt_mesh_default_ttl_set(uint8_t default_ttl); - -/** @brief Get the current default TTL value. - * - * @return The current default TTL value. - */ -uint8_t bt_mesh_default_ttl_get(void); - -/** @brief Set the Network Transmit parameters. - * - * The Network Transmit parameters determine the parameters local messages are - * transmitted with. - * - * @see BT_MESH_TRANSMIT - * - * @param xmit New Network Transmit parameters. Use @ref BT_MESH_TRANSMIT for - * encoding. - */ -void bt_mesh_net_transmit_set(uint8_t xmit); - -/** @brief Get the current Network Transmit parameters. - * - * The @ref BT_MESH_TRANSMIT_COUNT and @ref BT_MESH_TRANSMIT_INT macros can be - * used to decode the Network Transmit parameters. - * - * @return The current Network Transmit parameters. - */ -uint8_t bt_mesh_net_transmit_get(void); - -/** @brief Configure the Relay feature. - * - * Enable or disable the Relay feature, and configure the parameters to - * transmit relayed messages with. - * - * Support for the Relay feature must be enabled through the - * @c CONFIG_BT_MESH_RELAY configuration option. - * - * @see BT_MESH_TRANSMIT - * - * @param relay New Relay feature state. Must be one of - * @ref BT_MESH_FEATURE_ENABLED and - * @ref BT_MESH_FEATURE_DISABLED. - * @param xmit New Relay retransmit parameters. Use @ref BT_MESH_TRANSMIT for - * encoding. - * - * @retval 0 Successfully changed the Relay configuration. - * @retval -ENOTSUP The Relay feature is not supported. - * @retval -EINVAL Invalid parameter. - * @retval -EALREADY Already using the given parameters. - */ -int bt_mesh_relay_set(enum bt_mesh_feat_state relay, uint8_t xmit); - -/** @brief Get the current Relay feature state. - * - * @returns The Relay feature state. - */ -enum bt_mesh_feat_state bt_mesh_relay_get(void); - -/** @brief Get the current Relay Retransmit parameters. - * - * The @ref BT_MESH_TRANSMIT_COUNT and @ref BT_MESH_TRANSMIT_INT macros can be - * used to decode the Relay Retransmit parameters. - * - * @return The current Relay Retransmit parameters, or 0 if relay is not - * supported. - */ -uint8_t bt_mesh_relay_retransmit_get(void); - -/** @brief Enable or disable the GATT Proxy feature. - * - * Support for the GATT Proxy feature must be enabled through the - * @c CONFIG_BT_MESH_GATT_PROXY configuration option. - * - * @note The GATT Proxy feature only controls a Proxy node's ability to relay - * messages to the mesh network. A node that supports GATT Proxy will - * still advertise Connectable Proxy beacons, even if the feature is - * disabled. The Proxy feature can only be fully disabled through compile - * time configuration. - * - * @param gatt_proxy New GATT Proxy state. Must be one of - * @ref BT_MESH_FEATURE_ENABLED and - * @ref BT_MESH_FEATURE_DISABLED. - * - * @retval 0 Successfully changed the GATT Proxy feature state. - * @retval -ENOTSUP The GATT Proxy feature is not supported. - * @retval -EINVAL Invalid parameter. - * @retval -EALREADY Already in the given state. - */ -int bt_mesh_gatt_proxy_set(enum bt_mesh_feat_state gatt_proxy); - -/** @brief Get the current GATT Proxy state. - * - * @returns The GATT Proxy feature state. - */ -enum bt_mesh_feat_state bt_mesh_gatt_proxy_get(void); - -/** @brief Enable or disable the Friend feature. - * - * Any active friendships will be terminated immediately if the Friend feature - * is disabled. - * - * Support for the Friend feature must be enabled through the - * @c CONFIG_BT_MESH_FRIEND configuration option. - * - * @param friendship New Friend feature state. Must be one of - * @ref BT_MESH_FEATURE_ENABLED and - * @ref BT_MESH_FEATURE_DISABLED. - * - * @retval 0 Successfully changed the Friend feature state. - * @retval -ENOTSUP The Friend feature is not supported. - * @retval -EINVAL Invalid parameter. - * @retval -EALREADY Already in the given state. - */ -int bt_mesh_friend_set(enum bt_mesh_feat_state friendship); - -/** @brief Get the current Friend state. - * - * @returns The Friend feature state. - */ -enum bt_mesh_feat_state bt_mesh_friend_get(void); - -/** - * @brief Bluetooth Mesh Subnet Configuration - * @defgroup bt_mesh_cfg_subnet Bluetooth Mesh Subnet Configuration - * @{ - */ - -/** @brief Add a Subnet. - * - * Adds a subnet with the given network index and network key to the list of - * known Subnets. All messages sent on the given Subnet will be processed by - * this node, and the node may send and receive Network Beacons on the given - * Subnet. - * - * @param net_idx Network index. - * @param key Root network key of the Subnet. All other keys are derived - * from this. - * - * @retval STATUS_SUCCESS The Subnet was successfully added. - * @retval STATUS_INSUFF_RESOURCES No room for this Subnet. - * @retval STATUS_UNSPECIFIED The Subnet couldn't be created for some reason. - */ -uint8_t bt_mesh_subnet_add(uint16_t net_idx, const uint8_t key[16]); - -/** @brief Update the given Subnet. - * - * Starts the Key Refresh procedure for this Subnet by adding a second set of - * encryption keys. The Subnet will continue sending with the old key (but - * receiving messages using both) until the Subnet enters Key Refresh phase 2. - * - * This allows a network configurator to replace old network and application - * keys for the entire network, effectively removing access for all nodes that - * aren't given the new keys. - * - * @param net_idx Network index. - * @param key New root network key of the Subnet. - * - * @retval STATUS_SUCCESS The Subnet was updated with a second key. - * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. - * @retval STATUS_IDX_ALREADY_STORED The @c key value is the same as the - * current key. - * @retval STATUS_CANNOT_UPDATE The Subnet cannot be updated for some reason. - */ -uint8_t bt_mesh_subnet_update(uint16_t net_idx, const uint8_t key[16]); - -/** @brief Delete a Subnet. - * - * Removes the Subnet with the given network index from the node. The node will - * stop sending Network Beacons with the given Subnet, and can no longer - * process messages on this Subnet. - * - * All Applications bound to this Subnet are also deleted. - * - * @param net_idx Network index. - * - * @retval STATUS_SUCCESS The Subnet was deleted. - * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. - */ -uint8_t bt_mesh_subnet_del(uint16_t net_idx); - -/** @brief Check whether a Subnet is known. - * - * @param net_idx Network index - * - * @return true if a Subnet with the given index exists, false otherwise. - */ -bool bt_mesh_subnet_exists(uint16_t net_idx); - -/** @brief Set the Subnet's Key Refresh phase. - * - * The Key Refresh procedure is started by updating the Subnet keys through - * @ref bt_mesh_subnet_update. This puts the Subnet in Key Refresh Phase 1. - * Once all nodes have received the new Subnet key, Key Refresh Phase 2 can be - * activated through this function to start transmitting with the new network - * key. Finally, to revoke the old key, set the Key Refresh Phase to 3. This - * removes the old keys from the node, and returns the Subnet back to normal - * single-key operation with the new key set. - * - * @param net_idx Network index. - * @param phase Pointer to the new Key Refresh phase. Will return the actual - * Key Refresh phase after updating. - * - * @retval STATUS_SUCCESS The Key Refresh phase of the Subnet was successfully - * changed. - * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. - * @retval STATUS_CANNOT_UPDATE The given phase change is invalid. - */ -uint8_t bt_mesh_subnet_kr_phase_set(uint16_t net_idx, uint8_t *phase); - -/** @brief Get the Subnet's Key Refresh phase. - * - * @param net_idx Network index. - * @param phase Pointer to the Key Refresh variable to fill. - * - * @retval STATUS_SUCCESS Successfully populated the @c phase variable. - * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. - */ -uint8_t bt_mesh_subnet_kr_phase_get(uint16_t net_idx, uint8_t *phase); - -/** @brief Set the Node Identity state of the Subnet. - * - * The Node Identity state of a Subnet determines whether the Subnet advertises - * connectable Node Identity beacons for Proxy Clients to connect to. - * Once started, the Node Identity beacon runs for 60 seconds, or until it is - * stopped. - * - * This function serves the same purpose as @ref bt_mesh_proxy_identity_enable, - * but only acts on a single Subnet. - * - * GATT Proxy support must be enabled through - * @option{CONFIG_BT_MESH_GATT_PROXY}. - * - * @param net_idx Network index. - * @param node_id New Node Identity state, must be either @ref - * BT_MESH_FEATURE_ENABLED or @ref BT_MESH_FEATURE_DISABLED. - * - * @retval STATUS_SUCCESS Successfully set the Node Identity state of the - * Subnet. - * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. - * @retval STATUS_FEAT_NOT_SUPP The Node Identity feature is not supported. - * @retval STATUS_CANNOT_SET Couldn't set the Node Identity state. - */ -uint8_t bt_mesh_subnet_node_id_set(uint16_t net_idx, - enum bt_mesh_feat_state node_id); - -/** @brief Get the Node Identity state of the Subnet. - * - * @param net_idx Network index. - * @param node_id Node Identity variable to fill. - * - * @retval STATUS_SUCCESS Successfully populated the @c node_id variable. - * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. - */ -uint8_t bt_mesh_subnet_node_id_get(uint16_t net_idx, - enum bt_mesh_feat_state *node_id); - -/** @brief Get a list of all known Subnet indexes. - * - * Builds a list of all known Subnet indexes in the @c net_idxs array. - * If the @c net_idxs array is smaller than the list of known Subnets, this - * function fills all available entries and returns @c -ENOMEM. In this - * case, the next @c max entries of the list can be read out by calling - * @code - * bt_mesh_subnets_get(list, max, max); - * @endcode - * - * Note that any changes to the Subnet list between calls to this function - * could change the order and number of entries in the list. - * - * @param net_idxs Array to fill. - * @param max Max number of indexes to return. - * @param skip Number of indexes to skip. Enables batched processing of the - * list. - * - * @return The number of indexes added to the @c net_idxs array, or @c -ENOMEM - * if the number of known Subnets exceeds the @c max parameter. - */ -ssize_t bt_mesh_subnets_get(uint16_t net_idxs[], size_t max, off_t skip); - -/** - * @} - */ - -/** - * @brief Bluetooth Mesh Application Configuration - * @defgroup bt_mesh_cfg_app Bluetooth Mesh Application Configuration - * @{ - */ - -/** @brief Add an Application key. - * - * Adds the Application with the given index to the list of known applications. - * Allows the node to send and receive model messages encrypted with this - * Application key. - * - * Every Application is bound to a specific Subnet. The node must know the - * Subnet the Application is bound to before it can add the Application. - * - * @param app_idx Application index. - * @param net_idx Network index the Application is bound to. - * @param key Application key value. - * - * @retval STATUS_SUCCESS The Application was successfully added. - * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. - * @retval STATUS_INSUFF_RESOURCES There's no room for storing this - * Application. - * @retval STATUS_INVALID_BINDING This AppIdx is already bound to another - * Subnet. - * @retval STATUS_IDX_ALREADY_STORED This AppIdx is already stored with a - * different key value. - * @retval STATUS_CANNOT_SET Cannot set the Application key for some reason. - */ -uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, - const uint8_t key[16]); - -/** @brief Update an Application key. - * - * Update an Application with a second Application key, as part of the - * Key Refresh procedure of the bound Subnet. The node will continue - * transmitting with the old application key (but receiving on both) until the - * Subnet enters Key Refresh phase 2. Once the Subnet enters Key Refresh phase - * 3, the old application key will be deleted. - * - * @note The Application key can only be updated if the bound Subnet is in Key - * Refresh phase 1. - * - * @param app_idx Application index. - * @param net_idx Network index the Application is bound to, or - * @ref BT_MESH_KEY_ANY to skip the binding check. - * @param key New key value. - * - * @retval STATUS_SUCCESS The Application key was successfully updated. - * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. - * @retval STATUS_INVALID_BINDING This AppIdx is not bound to the given NetIdx. - * @retval STATUS_CANNOT_UPDATE The Application key cannot be updated for some - * reason. - * @retval STATUS_IDX_ALREADY_STORED This AppIdx is already updated with a - * different key value. - */ -uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx, - const uint8_t key[16]); - -/** @brief Delete an Application key. - * - * All models bound to this application will remove this binding. - * All models publishing with this application will stop publishing. - * - * @param app_idx Application index. - * @param net_idx Network index. - * - * @retval STATUS_SUCCESS The Application key was successfully deleted. - * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. - * @retval STATUS_INVALID_BINDING This AppIdx is not bound to the given NetIdx. - */ -uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx); - -/** @brief Check if an Application key is known. - * - * @param app_idx Application index. - * - * @return true if the Application is known, false otherwise. - */ -bool bt_mesh_app_key_exists(uint16_t app_idx); - -/** @brief Get a list of all known Application key indexes. - * - * Builds a list of all Application indexes for the given network index in the - * @c app_idxs array. If the @c app_idxs array cannot fit all bound - * Applications, this function fills all available entries and returns @c - * -ENOMEM. In this case, the next @c max entries of the list can be read out - * by calling - * @code - * bt_mesh_app_keys_get(net_idx, list, max, max); - * @endcode - * - * Note that any changes to the Application key list between calls to this - * function could change the order and number of entries in the list. - * - * @param net_idx Network Index to get the Applications of, or @ref - * BT_MESH_KEY_ANY to get all Applications. - * @param app_idxs Array to fill. - * @param max Max number of indexes to return. - * @param skip Number of indexes to skip. Enables batched processing of the - * list. - * - * @return The number of indexes added to the @c app_idxs array, or @c -ENOMEM - * if the number of known Applications exceeds the @c max parameter. - */ -ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max, - off_t skip); - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif /* _BT_MESH_CFG_H_ */ \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/cfg_cli.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/cfg_cli.h deleted file mode 100644 index bd2f9fe5b..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/cfg_cli.h +++ /dev/null @@ -1,278 +0,0 @@ -/** @file - * @brief Bluetooth Mesh Configuration Client Model APIs. - */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __BT_MESH_CFG_CLI_H -#define __BT_MESH_CFG_CLI_H - -/** - * @brief Bluetooth Mesh - * @defgroup bt_mesh_cfg_cli Bluetooth Mesh Configuration Client Model - * @ingroup bt_mesh - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** Mesh Configuration Client Model Context */ -struct bt_mesh_cfg_cli { - struct bt_mesh_model *model; - - struct k_sem op_sync; - uint32_t op_pending; - void *op_param; -}; - -extern const struct bt_mesh_model_op bt_mesh_cfg_cli_op[]; -extern const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb; - -#define BT_MESH_MODEL_CFG_CLI(cli_data) \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_CFG_CLI, bt_mesh_cfg_cli_op, NULL, \ - cli_data, &bt_mesh_cfg_cli_cb) - -int bt_mesh_cfg_node_reset(uint16_t net_idx, uint16_t addr, bool *status); - -int bt_mesh_cfg_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page, - uint8_t *status, struct os_mbuf *comp); - -int bt_mesh_cfg_beacon_get(uint16_t net_idx, uint16_t addr, uint8_t *status); - -int bt_mesh_cfg_beacon_set(uint16_t net_idx, uint16_t addr, uint8_t val, uint8_t *status); - -int bt_mesh_cfg_ttl_get(uint16_t net_idx, uint16_t addr, uint8_t *ttl); - -int bt_mesh_cfg_ttl_set(uint16_t net_idx, uint16_t addr, uint8_t val, uint8_t *ttl); - -int bt_mesh_cfg_friend_get(uint16_t net_idx, uint16_t addr, uint8_t *status); - -int bt_mesh_cfg_friend_set(uint16_t net_idx, uint16_t addr, uint8_t val, uint8_t *status); - -int bt_mesh_cfg_gatt_proxy_get(uint16_t net_idx, uint16_t addr, uint8_t *status); - -int bt_mesh_cfg_gatt_proxy_set(uint16_t net_idx, uint16_t addr, uint8_t val, - uint8_t *status); - -int bt_mesh_cfg_net_transmit_get(uint16_t net_idx, uint16_t addr, - uint8_t *transmit); - -int bt_mesh_cfg_net_transmit_set(uint16_t net_idx, uint16_t addr, - uint8_t val, uint8_t *transmit); - -int bt_mesh_cfg_relay_get(uint16_t net_idx, uint16_t addr, uint8_t *status, - uint8_t *transmit); - -int bt_mesh_cfg_relay_set(uint16_t net_idx, uint16_t addr, uint8_t new_relay, - uint8_t new_transmit, uint8_t *status, uint8_t *transmit); - -int bt_mesh_cfg_net_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, - const uint8_t net_key[16], uint8_t *status); - -int bt_mesh_cfg_net_key_get(uint16_t net_idx, uint16_t addr, uint16_t *keys, - size_t *key_cnt); - -int bt_mesh_cfg_net_key_del(uint16_t net_idx, uint16_t addr, - uint16_t key_net_idx, uint8_t *status); - -int bt_mesh_cfg_app_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, - uint16_t key_app_idx, const uint8_t app_key[16], - uint8_t *status); - -int bt_mesh_cfg_app_key_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, - uint8_t *status, uint16_t *keys, size_t *key_cnt); - -int bt_mesh_cfg_app_key_del(uint16_t net_idx, uint16_t addr, - uint16_t key_net_idx, uint16_t key_app_idx, uint8_t *status); - -int bt_mesh_cfg_mod_app_bind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_app_idx, uint16_t mod_id, uint8_t *status); - -int bt_mesh_cfg_mod_app_unbind(uint16_t net_idx, uint16_t addr, - uint16_t elem_addr, uint16_t mod_app_idx, - uint16_t mod_id, uint8_t *status); - -int bt_mesh_cfg_mod_app_bind_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_app_idx, uint16_t mod_id, uint16_t cid, - uint8_t *status); - -int bt_mesh_cfg_mod_app_unbind_vnd(uint16_t net_idx, uint16_t addr, - uint16_t elem_addr, uint16_t mod_app_idx, uint16_t mod_id, - uint16_t cid, uint8_t *status); - -int bt_mesh_cfg_mod_app_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint8_t *status, uint16_t *apps, - size_t *app_cnt); - -int bt_mesh_cfg_mod_app_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint16_t cid, uint8_t *status, - uint16_t *apps, size_t *app_cnt); - -/** @def BT_MESH_PUB_PERIOD_100MS - * - * @brief Helper macro to encode model publication period in units of 100ms - * - * @param steps Number of 100ms steps. - * - * @return Encoded value that can be assigned to bt_mesh_cfg_mod_pub.period - */ -#define BT_MESH_PUB_PERIOD_100MS(steps) ((steps) & BIT_MASK(6)) - -/** @def BT_MESH_PUB_PERIOD_SEC - * - * @brief Helper macro to encode model publication period in units of 1 second - * - * @param steps Number of 1 second steps. - * - * @return Encoded value that can be assigned to bt_mesh_cfg_mod_pub.period - */ -#define BT_MESH_PUB_PERIOD_SEC(steps) (((steps) & BIT_MASK(6)) | (1 << 6)) - -/** @def BT_MESH_PUB_PERIOD_10SEC - * - * @brief Helper macro to encode model publication period in units of 10 - * seconds - * - * @param steps Number of 10 second steps. - * - * @return Encoded value that can be assigned to bt_mesh_cfg_mod_pub.period - */ -#define BT_MESH_PUB_PERIOD_10SEC(steps) (((steps) & BIT_MASK(6)) | (2 << 6)) - -/** @def BT_MESH_PUB_PERIOD_10MIN - * - * @brief Helper macro to encode model publication period in units of 10 - * minutes - * - * @param steps Number of 10 minute steps. - * - * @return Encoded value that can be assigned to bt_mesh_cfg_mod_pub.period - */ -#define BT_MESH_PUB_PERIOD_10MIN(steps) (((steps) & BIT_MASK(6)) | (3 << 6)) - -struct bt_mesh_cfg_mod_pub { - uint16_t addr; - uint16_t app_idx; - bool cred_flag; - uint8_t ttl; - uint8_t period; - uint8_t transmit; -}; - -int bt_mesh_cfg_mod_pub_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, struct bt_mesh_cfg_mod_pub *pub, - uint8_t *status); - -int bt_mesh_cfg_mod_pub_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint16_t cid, - struct bt_mesh_cfg_mod_pub *pub, uint8_t *status); - -int bt_mesh_cfg_mod_pub_set(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, struct bt_mesh_cfg_mod_pub *pub, - uint8_t *status); - -int bt_mesh_cfg_mod_pub_set_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint16_t cid, - struct bt_mesh_cfg_mod_pub *pub, uint8_t *status); - -int bt_mesh_cfg_mod_sub_add(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t sub_addr, uint16_t mod_id, uint8_t *status); - -int bt_mesh_cfg_mod_sub_add_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t sub_addr, uint16_t mod_id, uint16_t cid, - uint8_t *status); - -int bt_mesh_cfg_mod_sub_del(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t sub_addr, uint16_t mod_id, uint8_t *status); - -int bt_mesh_cfg_mod_sub_del_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t sub_addr, uint16_t mod_id, uint16_t cid, - uint8_t *status); - -int bt_mesh_cfg_mod_sub_overwrite(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t sub_addr, uint16_t mod_id, uint8_t *status); - -int bt_mesh_cfg_mod_sub_overwrite_vnd(uint16_t net_idx, uint16_t addr, - uint16_t elem_addr, uint16_t sub_addr, - uint16_t mod_id, uint16_t cid, uint8_t *status); - -int bt_mesh_cfg_mod_sub_va_add(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - const uint8_t label[16], uint16_t mod_id, - uint16_t *virt_addr, uint8_t *status); - -int bt_mesh_cfg_mod_sub_va_add_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - const uint8_t label[16], uint16_t mod_id, - uint16_t cid, uint16_t *virt_addr, uint8_t *status); - -int bt_mesh_cfg_mod_sub_va_del(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - const uint8_t label[16], uint16_t mod_id, - uint16_t *virt_addr, uint8_t *status); - -int bt_mesh_cfg_mod_sub_va_del_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - const uint8_t label[16], uint16_t mod_id, - uint16_t cid, uint16_t *virt_addr, uint8_t *status); - -int bt_mesh_cfg_mod_sub_va_overwrite(uint16_t net_idx, uint16_t addr, - uint16_t elem_addr, const uint8_t label[16], - uint16_t mod_id, uint16_t *virt_addr, - uint8_t *status); - -int bt_mesh_cfg_mod_sub_va_overwrite_vnd(uint16_t net_idx, uint16_t addr, - uint16_t elem_addr, const uint8_t label[16], - uint16_t mod_id, uint16_t cid, - uint16_t *virt_addr, uint8_t *status); - -int bt_mesh_cfg_mod_sub_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint8_t *status, uint16_t *subs, - size_t *sub_cnt); - -int bt_mesh_cfg_mod_sub_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint16_t cid, uint8_t *status, - uint16_t *subs, size_t *sub_cnt); - -struct bt_mesh_cfg_hb_sub { - uint16_t src; - uint16_t dst; - uint8_t period; - uint8_t count; - uint8_t min; - uint8_t max; -}; - -int bt_mesh_cfg_hb_sub_set(uint16_t net_idx, uint16_t addr, - struct bt_mesh_cfg_hb_sub *sub, uint8_t *status); - -int bt_mesh_cfg_hb_sub_get(uint16_t net_idx, uint16_t addr, - struct bt_mesh_cfg_hb_sub *sub, uint8_t *status); - -struct bt_mesh_cfg_hb_pub { - uint16_t dst; - uint8_t count; - uint8_t period; - uint8_t ttl; - uint16_t feat; - uint16_t net_idx; -}; - -int bt_mesh_cfg_hb_pub_set(uint16_t net_idx, uint16_t addr, - const struct bt_mesh_cfg_hb_pub *pub, uint8_t *status); - -int bt_mesh_cfg_hb_pub_get(uint16_t net_idx, uint16_t addr, - struct bt_mesh_cfg_hb_pub *pub, uint8_t *status); - -int32_t bt_mesh_cfg_cli_timeout_get(void); -void bt_mesh_cfg_cli_timeout_set(int32_t timeout); - -#ifdef __cplusplus -} -#endif -/** - * @} - */ - -#endif /* __BT_MESH_CFG_CLI_H */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/cfg_srv.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/cfg_srv.h deleted file mode 100644 index 5bf3f4399..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/cfg_srv.h +++ /dev/null @@ -1,40 +0,0 @@ -/** @file - * @brief Bluetooth Mesh Configuration Server Model APIs. - */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __BT_MESH_CFG_SRV_H -#define __BT_MESH_CFG_SRV_H - -/** - * @brief Bluetooth Mesh - * @defgroup bt_mesh_cfg_srv Bluetooth Mesh Configuration Server Model - * @ingroup bt_mesh - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - - -extern const struct bt_mesh_model_op bt_mesh_cfg_srv_op[]; -extern const struct bt_mesh_model_cb bt_mesh_cfg_srv_cb; - -#define BT_MESH_MODEL_CFG_SRV \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_CFG_SRV, bt_mesh_cfg_srv_op, NULL, \ - NULL, &bt_mesh_cfg_srv_cb) - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif /* __BT_MESH_CFG_SRV_H */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/glue.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/glue.h deleted file mode 100644 index d27e7ebbe..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/glue.h +++ /dev/null @@ -1,591 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef _MESH_GLUE_ -#define _MESH_GLUE_ - -#include -#include - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/logcfg/logcfg.h" -#include "nimble/porting/nimble/include/modlog/modlog.h" -#include "nimble/nimble/include/nimble/nimble_npl.h" - -#include "nimble/porting/nimble/include/os/os_mbuf.h" -#include "nimble/porting/nimble/include/os/queue.h" - -#include "nimble/nimble/include/nimble/ble.h" -#include "nimble/nimble/host/include/host/ble_hs.h" -#include "nimble/nimble/host/include/host/ble_uuid.h" -#include "nimble/nimble/host/src/ble_sm_priv.h" -#include "nimble/nimble/host/src/ble_hs_hci_priv.h" - -#if MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS) -#include "mbedtls/aes.h" -#include "mbedtls/cipher.h" -#include "mbedtls/entropy.h" -#include "mbedtls/ctr_drbg.h" -#include "mbedtls/cmac.h" -#include "mbedtls/ecdh.h" -#include "mbedtls/ecp.h" - -#else -#include "nimble/ext/tinycrypt/include/tinycrypt/aes.h" -#include "nimble/ext/tinycrypt/include/tinycrypt/constants.h" -#include "nimble/ext/tinycrypt/include/tinycrypt/utils.h" -#include "nimble/ext/tinycrypt/include/tinycrypt/cmac_mode.h" -#include "nimble/ext/tinycrypt/include/tinycrypt/ecc_dh.h" -#endif - -#if MYNEWT_VAL(BLE_MESH_SETTINGS) -#include "config/config.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** @brief Helper to declare elements of bt_data arrays - * - * This macro is mainly for creating an array of struct bt_data - * elements which is then passed to bt_le_adv_start(). - * - * @param _type Type of advertising data field - * @param _data Pointer to the data field payload - * @param _data_len Number of bytes behind the _data pointer - */ -#define BT_DATA(_type, _data, _data_len) \ - { \ - .type = (_type), \ - .data_len = (_data_len), \ - .data = (const uint8_t *)(_data), \ - } - -/** @brief Helper to declare elements of bt_data arrays - * - * This macro is mainly for creating an array of struct bt_data - * elements which is then passed to bt_le_adv_start(). - * - * @param _type Type of advertising data field - * @param _bytes Variable number of single-byte parameters - */ -#define BT_DATA_BYTES(_type, _bytes...) \ - BT_DATA(_type, ((uint8_t []) { _bytes }), \ - sizeof((uint8_t []) { _bytes })) - -/* EIR/AD data type definitions */ -#define BT_DATA_FLAGS 0x01 /* AD flags */ -#define BT_DATA_UUID16_SOME 0x02 /* 16-bit UUID, more available */ -#define BT_DATA_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ -#define BT_DATA_UUID32_SOME 0x04 /* 32-bit UUID, more available */ -#define BT_DATA_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ -#define BT_DATA_UUID128_SOME 0x06 /* 128-bit UUID, more available */ -#define BT_DATA_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ -#define BT_DATA_NAME_SHORTENED 0x08 /* Shortened name */ -#define BT_DATA_NAME_COMPLETE 0x09 /* Complete name */ -#define BT_DATA_TX_POWER 0x0a /* Tx Power */ -#define BT_DATA_SOLICIT16 0x14 /* Solicit UUIDs, 16-bit */ -#define BT_DATA_SOLICIT128 0x15 /* Solicit UUIDs, 128-bit */ -#define BT_DATA_SVC_DATA16 0x16 /* Service data, 16-bit UUID */ -#define BT_DATA_GAP_APPEARANCE 0x19 /* GAP appearance */ -#define BT_DATA_SOLICIT32 0x1f /* Solicit UUIDs, 32-bit */ -#define BT_DATA_SVC_DATA32 0x20 /* Service data, 32-bit UUID */ -#define BT_DATA_SVC_DATA128 0x21 /* Service data, 128-bit UUID */ -#define BT_DATA_URI 0x24 /* URI */ -#define BT_DATA_MESH_PROV 0x29 /* Mesh Provisioning PDU */ -#define BT_DATA_MESH_MESSAGE 0x2a /* Mesh Networking PDU */ -#define BT_DATA_MESH_BEACON 0x2b /* Mesh Beacon */ - -#define BT_DATA_MANUFACTURER_DATA 0xff /* Manufacturer Specific Data */ - -#define BT_LE_AD_LIMITED 0x01 /* Limited Discoverable */ -#define BT_LE_AD_GENERAL 0x02 /* General Discoverable */ -#define BT_LE_AD_NO_BREDR 0x04 /* BR/EDR not supported */ - -#define sys_put_be16(a,b) put_be16(b, a) -#define sys_put_le16(a,b) put_le16(b, a) -#define sys_put_le24(a,b) put_le24(b, a) -#define sys_put_be24(a,b) put_be24(b, a) -#define sys_put_be32(a,b) put_be32(b, a) -#define sys_get_be16(a) get_be16(a) -#define sys_get_be24(a) get_be24(a) -#define sys_get_le16(a) get_le16(a) -#define sys_get_le24(a) get_le24(a) -#define sys_get_be32(a) get_be32(a) -#define sys_cpu_to_be16(a) htobe16(a) -#define sys_cpu_to_be32(a) htobe32(a) -#define sys_be32_to_cpu(a) be32toh(a) -#define sys_be16_to_cpu(a) be16toh(a) -#define sys_le16_to_cpu(a) le16toh(a) - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - -#define CODE_UNREACHABLE __builtin_unreachable() -#define __ASSERT(code, str) \ - do { \ - if (!(code)) BT_ERR(str); \ - assert(code); \ - } while (0); - -#define __ASSERT_NO_MSG(test) __ASSERT(test, "") - -/* Mesh is designed to not use mbuf chains */ -#if BT_DBG_ENABLED -#define ASSERT_NOT_CHAIN(om) assert(SLIST_NEXT(om, om_next) == NULL) -#else -#define ASSERT_NOT_CHAIN(om) (void)(om) -#endif - -#define __packed __attribute__((__packed__)) - -#define MSEC_PER_SEC (1000) -#define K_MSEC(ms) (ms) -#define K_SECONDS(s) K_MSEC((s) * MSEC_PER_SEC) -#define K_MINUTES(m) K_SECONDS((m) * 60) -#define K_HOURS(h) K_MINUTES((h) * 60) - -#ifndef BIT -#define BIT(n) (1UL << (n)) -#endif - -#define BIT_MASK(n) (BIT(n) - 1) - -#define BT_GAP_ADV_FAST_INT_MIN_1 0x0030 /* 30 ms */ -#define BT_GAP_ADV_FAST_INT_MAX_1 0x0060 /* 60 ms */ -#define BT_GAP_ADV_FAST_INT_MIN_2 0x00a0 /* 100 ms */ -#define BT_GAP_ADV_FAST_INT_MAX_2 0x00f0 /* 150 ms */ -#define BT_GAP_ADV_SLOW_INT_MIN 0x0640 /* 1 s */ -#define BT_GAP_ADV_SLOW_INT_MAX 0x0780 /* 1.2 s */ - -#ifndef MESH_LOG_MODULE -#define MESH_LOG_MODULE BLE_MESH_LOG -#endif - -#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) -#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ - -#define BLE_MESH_LOG(lvl, ...) CAT(MESH_LOG_MODULE, CAT(_, lvl))(__VA_ARGS__) - -#define BT_DBG(fmt, ...) BLE_MESH_LOG(DEBUG, "%s: " fmt "\n", __func__, ## __VA_ARGS__); -#define BT_INFO(fmt, ...) BLE_MESH_LOG(INFO, "%s: " fmt "\n", __func__, ## __VA_ARGS__); -#define BT_WARN(fmt, ...) BLE_MESH_LOG(WARN, "%s: " fmt "\n", __func__, ## __VA_ARGS__); -#define BT_ERR(fmt, ...) BLE_MESH_LOG(ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__); -#define BT_GATT_ERR(_att_err) (-(_att_err)) - -typedef ble_addr_t bt_addr_le_t; - -#define k_fifo_init(queue) ble_npl_eventq_init(queue) -#define net_buf_simple_tailroom(buf) OS_MBUF_TRAILINGSPACE(buf) -#define net_buf_tailroom(buf) net_buf_simple_tailroom(buf) -#define net_buf_headroom(buf) ((buf)->om_data - &(buf)->om_databuf[buf->om_pkthdr_len]) -#define net_buf_simple_headroom(buf) net_buf_headroom(buf) -#define net_buf_simple_tail(buf) ((buf)->om_data + (buf)->om_len) - -struct net_buf_simple_state { - /** Offset of the data pointer from the beginning of the storage */ - uint16_t offset; - /** Length of data */ - uint16_t len; -}; - -static inline struct os_mbuf * NET_BUF_SIMPLE(uint16_t size) -{ - struct os_mbuf *buf; - - buf = os_msys_get(size, 0); - assert(buf); - - return buf; -} - -#define K_NO_WAIT (0) -#define K_FOREVER (-1) - -#if MYNEWT_VAL(BLE_EXT_ADV) -#define BT_MESH_ADV_INST (MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES)) - -#if MYNEWT_VAL(BLE_MESH_PROXY) -/* Note that BLE_MULTI_ADV_INSTANCES contains number of additional instances. - * Instance 0 is always there - */ -#if MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) < 1 -#error "Mesh needs at least BLE_MULTI_ADV_INSTANCES set to 1" -#endif -#define BT_MESH_ADV_GATT_INST (MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) - 1) -#endif /* BLE_MESH_PROXY */ -#endif /* BLE_EXT_ADV */ - -/* This is by purpose */ -static inline void net_buf_simple_init(struct os_mbuf *buf, - size_t reserve_head) -{ - /* This is called in Zephyr after init. - * Note in Mynewt case we don't care abour reserved head*/ - buf->om_data = &buf->om_databuf[buf->om_pkthdr_len] + reserve_head; - buf->om_len = 0; -} - -#define net_buf_simple_init_with_data(buf, data, size) \ - os_mbuf_copyinto(buf, 0, data, size); - -static inline void net_buf_simple_reset(struct os_mbuf *om) -{ - net_buf_simple_init(om, 0); -} - -void net_buf_put(struct ble_npl_eventq *fifo, struct os_mbuf *buf); -void * net_buf_ref(struct os_mbuf *om); -void net_buf_unref(struct os_mbuf *om); -uint16_t net_buf_simple_pull_le16(struct os_mbuf *om); -uint16_t net_buf_simple_pull_be16(struct os_mbuf *om); -uint32_t net_buf_simple_pull_be32(struct os_mbuf *om); -uint32_t net_buf_simple_pull_le32(struct os_mbuf *om); -uint8_t net_buf_simple_pull_u8(struct os_mbuf *om); -void net_buf_simple_add_le16(struct os_mbuf *om, uint16_t val); -void net_buf_simple_add_be16(struct os_mbuf *om, uint16_t val); -void net_buf_simple_add_le24(struct os_mbuf *om, uint32_t val); -void net_buf_simple_add_u8(struct os_mbuf *om, uint8_t val); -void net_buf_simple_add_be32(struct os_mbuf *om, uint32_t val); -void net_buf_simple_add_le32(struct os_mbuf *om, uint32_t val); -void net_buf_add_zeros(struct os_mbuf *om, uint8_t len); -void net_buf_simple_push_le16(struct os_mbuf *om, uint16_t val); -void net_buf_simple_push_be16(struct os_mbuf *om, uint16_t val); -void net_buf_simple_push_be24(struct os_mbuf *om, uint32_t val); -void net_buf_simple_push_u8(struct os_mbuf *om, uint8_t val); -void *net_buf_simple_pull(struct os_mbuf *om, uint8_t len); -void *net_buf_simple_pull_mem(struct os_mbuf *om, uint8_t len); -void *net_buf_simple_add(struct os_mbuf *om, uint8_t len); -bool k_fifo_is_empty(struct ble_npl_eventq *q); -void *net_buf_get(struct ble_npl_eventq *fifo,int32_t t); -uint8_t *net_buf_simple_push(struct os_mbuf *om, uint8_t len); -void net_buf_reserve(struct os_mbuf *om, size_t reserve); - -#define net_buf_add_mem(a,b,c) os_mbuf_append(a,b,c) -#define net_buf_simple_add_mem(a,b,c) os_mbuf_append(a,b,c) -#define net_buf_add_u8(a,b) net_buf_simple_add_u8(a,b) -#define net_buf_add(a,b) net_buf_simple_add(a,b) - -#define net_buf_clone(a, b) os_mbuf_dup(a) -#define net_buf_add_be32(a, b) net_buf_simple_add_be32(a, b) -#define net_buf_add_be16(a, b) net_buf_simple_add_be16(a, b) -#define net_buf_pull(a, b) net_buf_simple_pull_mem(a, b) -#define net_buf_pull_mem(a, b) net_buf_simple_pull_mem(a, b) -#define net_buf_pull_u8(a) net_buf_simple_pull_u8(a) -#define net_buf_pull_be16(a) net_buf_simple_pull_be16(a) -#define net_buf_skip(a, b) net_buf_simple_pull_mem(a, b) - -#define BT_GATT_CCC_NOTIFY BLE_GATT_CHR_PROP_NOTIFY - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif - -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif - -/** Description of different data types that can be encoded into - * advertising data. Used to form arrays that are passed to the - * bt_le_adv_start() function. - */ -struct bt_data { - uint8_t type; - uint8_t data_len; - const uint8_t *data; -}; - -struct bt_pub_key_cb { - /** @brief Callback type for Public Key generation. - * - * Used to notify of the local public key or that the local key is not - * available (either because of a failure to read it or because it is - * being regenerated). - * - * @param key The local public key, or NULL in case of no key. - */ - void (*func)(const uint8_t key[64]); - - struct bt_pub_key_cb *_next; -}; - -typedef void (*bt_dh_key_cb_t)(const uint8_t key[32]); -int bt_dh_key_gen(const uint8_t remote_pk[64], bt_dh_key_cb_t cb); -int bt_pub_key_gen(struct bt_pub_key_cb *new_cb); -uint8_t *bt_pub_key_get(void); -int bt_rand(void *buf, size_t len); -const char * bt_hex(const void *buf, size_t len); -int bt_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data); -int bt_ccm_decrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t *enc_data, - size_t len, const uint8_t *aad, size_t aad_len, - uint8_t *plaintext, size_t mic_size); -int bt_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t *enc_data, - size_t len, const uint8_t *aad, size_t aad_len, - uint8_t *plaintext, size_t mic_size); -void bt_mesh_register_gatt(void); -int bt_le_adv_start(const struct ble_gap_adv_params *param, - const struct bt_data *ad, size_t ad_len, - const struct bt_data *sd, size_t sd_len); -int bt_le_adv_stop(bool proxy); - -struct k_delayed_work { - struct ble_npl_callout work; -}; - -void k_work_init(struct ble_npl_callout *work, ble_npl_event_fn handler); -void k_delayed_work_init(struct k_delayed_work *w, ble_npl_event_fn *f); -void k_delayed_work_cancel(struct k_delayed_work *w); -bool k_delayed_work_pending(struct k_delayed_work *w); -void k_delayed_work_submit(struct k_delayed_work *w, uint32_t ms); -int64_t k_uptime_get(void); -uint32_t k_uptime_get_32(void); -void k_sleep(int32_t duration); -void k_work_submit(struct ble_npl_callout *w); -void k_work_add_arg(struct ble_npl_callout *w, void *arg); -void k_delayed_work_add_arg(struct k_delayed_work *w, void *arg); -uint32_t k_delayed_work_remaining_get(struct k_delayed_work *w); - -static inline void net_buf_simple_save(struct os_mbuf *buf, - struct net_buf_simple_state *state) -{ - state->offset = net_buf_simple_headroom(buf); - state->len = buf->om_len; -} - -static inline void net_buf_simple_restore(struct os_mbuf *buf, - struct net_buf_simple_state *state) -{ - buf->om_data = &buf->om_databuf[buf->om_pkthdr_len] + state->offset; - buf->om_len = state->len; -} - -static inline void sys_memcpy_swap(void *dst, const void *src, size_t length) -{ - __ASSERT(((src < dst && (src + length) <= dst) || - (src > dst && (dst + length) <= src)), - "Source and destination buffers must not overlap"); - - src += length - 1; - - for (; length > 0; length--) { - *((uint8_t *)dst++) = *((uint8_t *)src--); - } -} - -#define popcount(x) __builtin_popcount(x) - -static inline unsigned int find_lsb_set(uint32_t op) -{ - return __builtin_ffs(op); -} - -static inline unsigned int find_msb_set(uint32_t op) -{ - if (!op) - return 0; - - return 32 - __builtin_clz(op); -} - -#define CONFIG_BT_MESH_FRIEND BLE_MESH_FRIEND -#define CONFIG_BT_MESH_GATT_PROXY BLE_MESH_GATT_PROXY -#define CONFIG_BT_MESH_IV_UPDATE_TEST BLE_MESH_IV_UPDATE_TEST -#define CONFIG_BT_MESH_LOW_POWER BLE_MESH_LOW_POWER -#define CONFIG_BT_MESH_LPN_SUB_ALL_NODES_ADDR BLE_MESH_LPN_SUB_ALL_NODES_ADDR -#define CONFIG_BT_MESH_LPN_AUTO BLE_MESH_LPN_AUTO -#define CONFIG_BT_MESH_LPN_ESTABLISHMENT BLE_MESH_LPN_ESTABLISHMENT -#define CONFIG_BT_MESH_PB_ADV BLE_MESH_PB_ADV -#define CONFIG_BT_MESH_PB_GATT BLE_MESH_PB_GATT -#define CONFIG_BT_MESH_PROV BLE_MESH_PROV -#define CONFIG_BT_MESH_PROXY BLE_MESH_PROXY -#define CONFIG_BT_TESTING BLE_MESH_TESTING -#define CONFIG_BT_SETTINGS BLE_MESH_SETTINGS -#define CONFIG_SETTINGS BLE_MESH_SETTINGS -#define CONFIG_BT_MESH_PROVISIONER BLE_MESH_PROVISIONER -#define CONFIG_BT_MESH_PROV_DEVICE BLE_MESH_PROV_DEVICE -#define CONFIG_BT_MESH_CDB BLE_MESH_CDB - -/* Above flags are used with IS_ENABLED macro */ -#define IS_ENABLED(config) MYNEWT_VAL(config) - -#define CONFIG_BT_MESH_LPN_GROUPS MYNEWT_VAL(BLE_MESH_LPN_GROUPS) -#define CONFIG_BT_MESH_ADV_BUF_COUNT MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT) -#define CONFIG_BT_MESH_SEG_BUFS MYNEWT_VAL(BLE_MESH_SEG_BUFS ) -#define CONFIG_BT_MESH_FRIEND_QUEUE_SIZE MYNEWT_VAL(BLE_MESH_FRIEND_QUEUE_SIZE) -#define CONFIG_BT_MESH_FRIEND_RECV_WIN MYNEWT_VAL(BLE_MESH_FRIEND_RECV_WIN) -#define CONFIG_BT_MESH_LPN_POLL_TIMEOUT MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT) -#define CONFIG_BT_MESH_MODEL_GROUP_COUNT MYNEWT_VAL(BLE_MESH_MODEL_GROUP_COUNT) -#define CONFIG_BT_MESH_MODEL_KEY_COUNT MYNEWT_VAL(BLE_MESH_MODEL_KEY_COUNT) -#define CONFIG_BT_MESH_NODE_ID_TIMEOUT MYNEWT_VAL(BLE_MESH_NODE_ID_TIMEOUT) -#define CONFIG_BT_MAX_CONN MYNEWT_VAL(BLE_MAX_CONNECTIONS) -#define CONFIG_BT_MESH_SEQ_STORE_RATE MYNEWT_VAL(BLE_MESH_SEQ_STORE_RATE) -#define CONFIG_BT_MESH_RPL_STORE_TIMEOUT MYNEWT_VAL(BLE_MESH_RPL_STORE_TIMEOUT) -#define CONFIG_BT_MESH_APP_KEY_COUNT MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT) -#define CONFIG_BT_MESH_SUBNET_COUNT MYNEWT_VAL(BLE_MESH_SUBNET_COUNT) -#define CONFIG_BT_MESH_STORE_TIMEOUT MYNEWT_VAL(BLE_MESH_STORE_TIMEOUT) -#define CONFIG_BT_MESH_IVU_DIVIDER MYNEWT_VAL(BLE_MESH_IVU_DIVIDER) -#define CONFIG_BT_DEVICE_NAME MYNEWT_VAL(BLE_MESH_DEVICE_NAME) -#define CONFIG_BT_RX_SEG_MAX MYNEWT_VAL(BLE_MESH_RX_SEG_MAX) -#define CONFIG_BT_MESH_TX_SEG_MAX MYNEWT_VAL(BLE_MESH_TX_SEG_MAX) -#define CONFIG_BT_MESH_RX_SEG_MAX MYNEWT_VAL(BLE_MESH_RX_SEG_MAX) -#define CONFIG_BT_MESH_RX_SEG_MSG_COUNT MYNEWT_VAL(BLE_MESH_RX_SEG_MSG_COUNT) -#define CONFIG_BT_MESH_LABEL_COUNT MYNEWT_VAL(BLE_MESH_LABEL_COUNT) -#define CONFIG_BT_MESH_NODE_COUNT MYNEWT_VAL(BLE_MESH_CDB_NODE_COUNT) -#define CONFIG_BT_GATT_PROXY_ENABLED MYNEWT_VAL(BLE_MESH_GATT_PROXY_ENABLED) -#define CONFIG_BT_MESH_DEFAULT_TTL MYNEWT_VAL(BLE_MESH_DEFAULT_TTL) -#define CONFIG_BT_MESH_NETWORK_TRANSMIT_COUNT MYNEWT_VAL(BLE_MESH_NETWORK_TRANSMIT_COUNT) -#define CONFIG_BT_MESH_NETWORK_TRANSMIT_INTERVAL MYNEWT_VAL(BLE_MESH_NETWORK_TRANSMIT_INTERVAL) -#define CONFIG_BT_MESH_RELAY_ENABLED MYNEWT_VAL(BLE_MESH_RELAY_ENABLED) -#define CONFIG_BT_MESH_RELAY_RETRANSMIT_INTERVAL MYNEWT_VAL(BLE_MESH_RELAY_RETRANSMIT_INTERVAL) -#define CONFIG_BT_MESH_BEACON_ENABLED MYNEWT_VAL(BLE_MESH_BEACON_ENABLED) -#define CONFIG_BT_MESH_FRIEND_ENABLED MYNEWT_VAL(BLE_MESH_FRIEND_ENABLED) -#define CONFIG_BT_MESH_RELAY MYNEWT_VAL(BLE_MESH_RELAY) -#define CONFIG_BT_MESH_RELAY_RETRANSMIT_COUNT MYNEWT_VAL(BLE_MESH_RELAY_RETRANSMIT_COUNT) -#define CONFIG_BT_MESH_GATT_PROXY_ENABLED MYNEWT_VAL(BLE_MESH_GATT_PROXY_ENABLED) - -#define printk console_printf - -#define CONTAINER_OF(ptr, type, field) \ - ((type *)(((char *)(ptr)) - offsetof(type, field))) - - -#define k_sem ble_npl_sem - -static inline void k_sem_init(struct k_sem *sem, unsigned int initial_count, - unsigned int limit) -{ - ble_npl_sem_init(sem, initial_count); -} - -static inline int k_sem_take(struct k_sem *sem, int32_t timeout) -{ - uint32_t ticks; - - ble_npl_time_ms_to_ticks(timeout, &ticks); - return - ble_npl_sem_pend(sem, ticks); -} - -static inline void k_sem_give(struct k_sem *sem) -{ - ble_npl_sem_release(sem); -} - -/* Helpers to access the storage array, since we don't have access to its - * type at this point anymore. - */ - -#define BUF_SIZE(pool) (pool->omp_pool->mp_block_size) - -static inline int net_buf_id(struct os_mbuf *buf) -{ - struct os_mbuf_pool *pool = buf->om_omp; - uint8_t *pool_start = (uint8_t *)pool->omp_pool->mp_membuf_addr; - uint8_t *buf_ptr = (uint8_t *)buf; - - return (buf_ptr - pool_start) / BUF_SIZE(pool); -} - -/* XXX: We should not use os_mbuf_pkthdr chains to represent a list of - * packets, this is a hack. For now this is not an issue, because mesh - * does not use os_mbuf chains. We should change this in the future. - */ -STAILQ_HEAD(net_buf_slist_t, os_mbuf_pkthdr); - -void net_buf_slist_init(struct net_buf_slist_t *list); -bool net_buf_slist_is_empty(struct net_buf_slist_t *list); -struct os_mbuf *net_buf_slist_peek_head(struct net_buf_slist_t *list); -struct os_mbuf *net_buf_slist_peek_next(struct os_mbuf *buf); -struct os_mbuf *net_buf_slist_get(struct net_buf_slist_t *list); -void net_buf_slist_put(struct net_buf_slist_t *list, struct os_mbuf *buf); -void net_buf_slist_remove(struct net_buf_slist_t *list, struct os_mbuf *prev, - struct os_mbuf *cur); -void net_buf_slist_merge_slist(struct net_buf_slist_t *list, - struct net_buf_slist_t *list_to_append); -#define NET_BUF_SLIST_FOR_EACH_NODE(head, var) STAILQ_FOREACH(var, head, omp_next) - -#if MYNEWT_VAL(BLE_MESH_SETTINGS) - -#define settings_load conf_load -int settings_bytes_from_str(char *val_str, void *vp, int *len); -char *settings_str_from_bytes(const void *vp, int vp_len, - char *buf, int buf_len); - -#define snprintk snprintf -#define BT_SETTINGS_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1) -#define settings_save_one conf_save_one - -#else - -static inline int -settings_load(void) -{ - return 0; -} - -#endif /* MYNEWT_VAL(MYNEWT_VAL_BLE_MESH_SETTINGS) */ - -#define BUILD_ASSERT(cond) _Static_assert(cond, "") - - -/* Memory slabs/blocks */ - -/** Memory slab structure */ -struct k_mem_slab { - /** - * _wait_q_t is not required now, as we don't implement zephyr timeouts - - * if slab couldn't be allocated, we simply return error - */ - uint32_t num_blocks; /** number of memory blocks available for allocation */ - size_t block_size; /** size of single block */ - /** - * buffer for blocks - must be alligned to N-byte, where N is a power of 2. - * Minimal size of buffer is num_blocks * block_size - */ - char *buffer; - char *free_list; /** list of free memory blocks */ - uint32_t num_used; /** count of used memory blocks */ -}; - -struct k_mem_block_id { - uint32_t pool : 8; - uint32_t level : 4; - uint32_t block : 20; -}; - -struct k_mem_block { - void *data; - struct k_mem_block_id id; -}; - -extern void k_mem_slab_free(struct k_mem_slab *slab, void **mem); -extern int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem); -static inline uint32_t k_mem_slab_num_free_get(struct k_mem_slab *slab) -{ - return slab->num_blocks - slab->num_used; -} - -int create_free_list(struct k_mem_slab *slab); - -#ifdef __cplusplus -} -#endif - -#endif /* _MESH_GLUE_ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/health_cli.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/health_cli.h deleted file mode 100644 index e9efe4b1f..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/health_cli.h +++ /dev/null @@ -1,79 +0,0 @@ -/** @file - * @brief Bluetooth Mesh Health Client Model APIs. - */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __BT_MESH_HEALTH_CLI_H -#define __BT_MESH_HEALTH_CLI_H - -/** - * @brief Bluetooth Mesh - * @defgroup bt_mesh_health_cli Bluetooth Mesh Health Client Model - * @ingroup bt_mesh - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** Mesh Health Client Model Context */ -struct bt_mesh_health_cli { - struct bt_mesh_model *model; - - void (*current_status)(struct bt_mesh_health_cli *cli, uint16_t addr, - uint8_t test_id, uint16_t cid, uint8_t *faults, - size_t fault_count); - - struct k_sem op_sync; - uint32_t op_pending; - void *op_param; -}; - -extern const struct bt_mesh_model_op bt_mesh_health_cli_op[]; -extern const struct bt_mesh_model_cb bt_mesh_health_cli_cb; - -#define BT_MESH_MODEL_HEALTH_CLI(cli_data) \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_HEALTH_CLI, bt_mesh_health_cli_op, \ - NULL, cli_data, &bt_mesh_health_cli_cb) - -int bt_mesh_health_cli_set(struct bt_mesh_model *model); - -int bt_mesh_health_fault_get(uint16_t addr, uint16_t app_idx, uint16_t cid, - uint8_t *test_id, uint8_t *faults, - size_t *fault_count); - -int bt_mesh_health_fault_clear(uint16_t addr, uint16_t app_idx, uint16_t cid, - uint8_t *test_id, uint8_t *faults, - size_t *fault_count); - -int bt_mesh_health_fault_test(uint16_t addr, uint16_t app_idx, uint16_t cid, - uint8_t test_id, uint8_t *faults, - size_t *fault_count); - -int bt_mesh_health_period_get(uint16_t addr, uint16_t app_idx, uint8_t *divisor); - -int bt_mesh_health_period_set(uint16_t addr, uint16_t app_idx, uint8_t divisor, - uint8_t *updated_divisor); - -int bt_mesh_health_attention_get(uint16_t addr, uint16_t app_idx, uint8_t *attention); - -int bt_mesh_health_attention_set(uint16_t addr, uint16_t app_idx, uint8_t attention, - uint8_t *updated_attention); - -int32_t bt_mesh_health_cli_timeout_get(void); -void bt_mesh_health_cli_timeout_set(int32_t timeout); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif /* __BT_MESH_HEALTH_CLI_H */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/health_srv.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/health_srv.h deleted file mode 100644 index ad79e368d..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/health_srv.h +++ /dev/null @@ -1,100 +0,0 @@ -/** @file - * @brief Bluetooth Mesh Health Server Model APIs. - */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __BT_MESH_HEALTH_SRV_H -#define __BT_MESH_HEALTH_SRV_H - -/** - * @brief Mesh Bluetooth Mesh Health Server Model - * @defgroup bt_mesh_health_srv - * @ingroup bt_mesh - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -struct bt_mesh_health_srv_cb { - /* Fetch current faults */ - int (*fault_get_cur)(struct bt_mesh_model *model, uint8_t *test_id, - uint16_t *company_id, uint8_t *faults, - uint8_t *fault_count); - - /* Fetch registered faults */ - int (*fault_get_reg)(struct bt_mesh_model *model, uint16_t company_id, - uint8_t *test_id, uint8_t *faults, - uint8_t *fault_count); - - /* Clear registered faults */ - int (*fault_clear)(struct bt_mesh_model *model, uint16_t company_id); - - /* Run a specific test */ - int (*fault_test)(struct bt_mesh_model *model, uint8_t test_id, - uint16_t company_id); - - /* Attention on */ - void (*attn_on)(struct bt_mesh_model *model); - - /* Attention off */ - void (*attn_off)(struct bt_mesh_model *model); -}; - -/** @def BT_MESH_HEALTH_FAULT_MSG - * - * A helper to define a health fault message. - * - * @param max_faults Maximum number of faults the element can have. - * - * @return a New os_mbuf of the needed size. - */ -#define BT_MESH_HEALTH_FAULT_MSG(max_faults) \ - NET_BUF_SIMPLE(1 + 3 + (max_faults)) - -/** Mesh Health Server Model Context */ -struct bt_mesh_health_srv { - struct bt_mesh_model *model; - - /* Optional callback struct */ - const struct bt_mesh_health_srv_cb *cb; - - /* Attention Timer state */ - struct k_delayed_work attn_timer; -}; - -int bt_mesh_fault_update(struct bt_mesh_elem *elem); - -extern const struct bt_mesh_model_op bt_mesh_health_srv_op[]; -extern const struct bt_mesh_model_cb bt_mesh_health_srv_cb; - -/** @def BT_MESH_MODEL_HEALTH_SRV - * - * Define a new health server model. Note that this API needs to be - * repeated for each element that the application wants to have a - * health server model on. Each instance also needs a unique - * bt_mesh_health_srv and bt_mesh_model_pub context. - * - * @param srv Pointer to a unique struct bt_mesh_health_srv. - * @param pub Pointer to a unique struct bt_mesh_model_pub. - * - * @return New mesh model instance. - */ -#define BT_MESH_MODEL_HEALTH_SRV(srv, pub) \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_op, \ - pub, srv, &bt_mesh_health_srv_cb) - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif /* __BT_MESH_HEALTH_SRV_H */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/heartbeat.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/heartbeat.h deleted file mode 100644 index b9990f6fd..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/heartbeat.h +++ /dev/null @@ -1,123 +0,0 @@ -/** @file - * @brief Bluetooth Mesh Heartbeat API. - */ - -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef _BLUETOOTH_MESH_HEARTBEAT_H_ -#define _BLUETOOTH_MESH_HEARTBEAT_H_ - -/** - * @brief Bluetooth Mesh - * @defgroup bt_mesh_heartbeat Bluetooth Mesh Heartbeat - * @ingroup bt_mesh - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** Heartbeat Publication parameters */ -struct bt_mesh_hb_pub { - /** Destination address. */ - uint16_t dst; - /** Remaining publish count. */ - uint16_t count; - /** Time To Live value. */ - uint8_t ttl; - /** - * Bitmap of features that trigger a Heartbeat publication if - * they change. Legal values are @ref BT_MESH_FEAT_RELAY, - * @ref BT_MESH_FEAT_PROXY, @ref BT_MESH_FEAT_FRIEND and - * @ref BT_MESH_FEAT_LOW_POWER. - */ - uint16_t feat; - /** Network index used for publishing. */ - uint16_t net_idx; - /** Publication period in seconds. */ - uint32_t period; -}; - -/** Heartbeat Subscription parameters. */ -struct bt_mesh_hb_sub { - /** Subscription period in seconds. */ - uint32_t period; - /** Remaining subscription time in seconds. */ - uint32_t remaining; - /** Source address to receive Heartbeats from. */ - uint16_t src; - /** Destination address to received Heartbeats on. */ - uint16_t dst; - /** The number of received Heartbeat messages so far. */ - uint16_t count; - /** - * Minimum hops in received messages, ie the shortest registered - * path from the publishing node to the subscribing node. A - * Heartbeat received from an immediate neighbor has hop - * count = 1. - */ - uint8_t min_hops; - /** - * Maximum hops in received messages, ie the longest registered - * path from the publishing node to the subscribing node. A - * Heartbeat received from an immediate neighbor has hop - * count = 1. - */ - uint8_t max_hops; -}; - -/** Heartbeat callback structure */ -struct bt_mesh_hb_cb { - /** @brief Receive callback for heartbeats. - * - * Gets called on every received Heartbeat that matches the current - * Heartbeat subscription parameters. - * - * @param sub Current Heartbeat subscription parameters. - * @param hops The number of hops the Heartbeat was received - * with. - * @param feat The feature set of the publishing node. The - * value is a bitmap of @ref BT_MESH_FEAT_RELAY, - * @ref BT_MESH_FEAT_PROXY, - * @ref BT_MESH_FEAT_FRIEND and - * @ref BT_MESH_FEAT_LOW_POWER. - */ - void (*recv)(const struct bt_mesh_hb_sub *sub, uint8_t hops, - uint16_t feat); - - /** @brief Subscription end callback for heartbeats. - * - * Gets called when the subscription period ends, providing a summary - * of the received heartbeat messages. - * - * @param sub Current Heartbeat subscription parameters. - */ - void (*sub_end)(const struct bt_mesh_hb_sub *sub); -}; - -/** @brief Get the current Heartbeat publication parameters. - * - * @param get Heartbeat publication parameters return buffer. - */ -void bt_mesh_hb_pub_get(struct bt_mesh_hb_pub *get); - -/** @brief Get the current Heartbeat subscription parameters. - * - * @param get Heartbeat subscription parameters return buffer. - */ -void bt_mesh_hb_sub_get(struct bt_mesh_hb_sub *get); - -extern struct bt_mesh_hb_cb hb_cb; - -#ifdef __cplusplus -} -#endif -/** - * @} - */ - -#endif /* _BLUETOOTH_MESH_HEARTBEAT_H_ */ \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/main.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/main.h deleted file mode 100644 index 2bcb05c83..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/main.h +++ /dev/null @@ -1,559 +0,0 @@ -/** @file - * @brief Bluetooth Mesh Profile APIs. - */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __BT_MESH_MAIN_H -#define __BT_MESH_MAIN_H - -/** - * @brief Bluetooth Mesh Provisioning - * @defgroup bt_mesh_prov Bluetooth Mesh Provisioning - * @ingroup bt_mesh - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - BT_MESH_NO_OUTPUT = 0, - BT_MESH_BLINK = BIT(0), - BT_MESH_BEEP = BIT(1), - BT_MESH_VIBRATE = BIT(2), - BT_MESH_DISPLAY_NUMBER = BIT(3), - BT_MESH_DISPLAY_STRING = BIT(4), -} bt_mesh_output_action_t; - -typedef enum { - BT_MESH_NO_INPUT = 0, - BT_MESH_PUSH = BIT(0), - BT_MESH_TWIST = BIT(1), - BT_MESH_ENTER_NUMBER = BIT(2), - BT_MESH_ENTER_STRING = BIT(3), -} bt_mesh_input_action_t; - -typedef enum { - BT_MESH_PROV_ADV = BIT(0), - BT_MESH_PROV_GATT = BIT(1), -} bt_mesh_prov_bearer_t; - -typedef enum { - BT_MESH_PROV_OOB_OTHER = BIT(0), - BT_MESH_PROV_OOB_URI = BIT(1), - BT_MESH_PROV_OOB_2D_CODE = BIT(2), - BT_MESH_PROV_OOB_BAR_CODE = BIT(3), - BT_MESH_PROV_OOB_NFC = BIT(4), - BT_MESH_PROV_OOB_NUMBER = BIT(5), - BT_MESH_PROV_OOB_STRING = BIT(6), - /* 7 - 10 are reserved */ - BT_MESH_PROV_OOB_ON_BOX = BIT(11), - BT_MESH_PROV_OOB_IN_BOX = BIT(12), - BT_MESH_PROV_OOB_ON_PAPER = BIT(13), - BT_MESH_PROV_OOB_IN_MANUAL = BIT(14), - BT_MESH_PROV_OOB_ON_DEV = BIT(15), -} bt_mesh_prov_oob_info_t; - -/** Device Capabilities. */ -struct bt_mesh_dev_capabilities { - /** Number of elements supported by the device */ - uint8_t elem_count; - - /** Supported algorithms and other capabilities */ - uint16_t algorithms; - - /** Supported public key types */ - uint8_t pub_key_type; - - /** Supported static OOB Types */ - uint8_t static_oob; - - /** Supported Output OOB Actions */ - bt_mesh_output_action_t output_actions; - - /** Supported Input OOB Actions */ - bt_mesh_input_action_t input_actions; - - /** Maximum size of Output OOB supported */ - uint8_t output_size; - - /** Maximum size in octets of Input OOB supported */ - uint8_t input_size; -}; - -/** Provisioning properties & capabilities. */ -struct bt_mesh_prov { - /** The UUID that's used when advertising as unprovisioned */ - const uint8_t *uuid; - - /** Optional URI. This will be advertised separately from the - * unprovisioned beacon, however the unprovisioned beacon will - * contain a hash of it so the two can be associated by the - * provisioner. - */ - const char *uri; - - /** Out of Band information field. */ - bt_mesh_prov_oob_info_t oob_info; - - /** Static OOB value */ - const uint8_t *static_val; - /** Static OOB value length */ - uint8_t static_val_len; - - /** Maximum size of Output OOB supported */ - uint8_t output_size; - /** Supported Output OOB Actions */ - uint16_t output_actions; - - /* Maximum size of Input OOB supported */ - uint8_t input_size; - /** Supported Input OOB Actions */ - uint16_t input_actions; - - /** @brief Provisioning Capabilities. - * - * This callback notifies the application that the provisioning capabilities - * of the unprovisioned device has been received. - * - * The application can consequently call bt_mesh_auth_method_set_<*> to - * select suitable provisioning oob authentication method. - * - * When this callback returns, the provisioner will start authentication with - * the chosen method. - * - * @param cap capabilities supported by device. - */ - void (*capabilities)(const struct bt_mesh_dev_capabilities *cap); - - /** @brief Output of a number is requested. - * - * This callback notifies the application that it should - * output the given number using the given action. - * - * @param act Action for outputting the number. - * @param num Number to be outputted. - * - * @return Zero on success or negative error code otherwise - */ - int (*output_number)(bt_mesh_output_action_t act, uint32_t num); - - /** @brief Output of a string is requested. - * - * This callback notifies the application that it should - * display the given string to the user. - * - * @param str String to be displayed. - * - * @return Zero on success or negative error code otherwise - */ - int (*output_string)(const char *str); - - /** @brief Input is requested. - * - * This callback notifies the application that it should - * request input from the user using the given action. The - * requested input will either be a string or a number, and - * the application needs to consequently call the - * bt_mesh_input_string() or bt_mesh_input_number() functions - * once the data has been acquired from the user. - * - * @param act Action for inputting data. - * @param num Maximum size of the inputted data. - * - * @return Zero on success or negative error code otherwise - */ - int (*input)(bt_mesh_input_action_t act, uint8_t size); - - /** @brief The other device finished their OOB input. - * - * This callback notifies the application that it should stop - * displaying its output OOB value, as the other party finished their - * OOB input. - */ - void (*input_complete)(void); - - /** @brief Unprovisioned beacon has been received. - * - * This callback notifies the application that an unprovisioned - * beacon has been received. - * - * @param uuid UUID - * @param oob_info OOB Information - * @param uri_hash Pointer to URI Hash value. NULL if no hash was - * present in the beacon. - */ - void (*unprovisioned_beacon)(uint8_t uuid[16], - bt_mesh_prov_oob_info_t oob_info, - uint32_t *uri_hash); - - /** @brief Provisioning link has been opened. - * - * This callback notifies the application that a provisioning - * link has been opened on the given provisioning bearer. - * - * @param bearer Provisioning bearer. - */ - void (*link_open)(bt_mesh_prov_bearer_t bearer); - - /** @brief Provisioning link has been closed. - * - * This callback notifies the application that a provisioning - * link has been closed on the given provisioning bearer. - * - * @param bearer Provisioning bearer. - */ - void (*link_close)(bt_mesh_prov_bearer_t bearer); - - /** @brief Provisioning is complete. - * - * This callback notifies the application that provisioning has - * been successfully completed, and that the local node has been - * assigned the specified NetKeyIndex and primary element address. - * - * @param net_idx NetKeyIndex given during provisioning. - * @param addr Primary element address. - */ - void (*complete)(uint16_t net_idx, uint16_t addr); - - /** @brief A new node has been added to the provisioning database. - * - * This callback notifies the application that provisioning has - * been successfully completed, and that a node has been assigned - * the specified NetKeyIndex and primary element address. - * - * @param net_idx NetKeyIndex given during provisioning. - * @param uuid UUID of the added node - * @param addr Primary element address. - * @param num_elem Number of elements that this node has. - */ - void (*node_added)(uint16_t net_idx, uint8_t uuid[16], uint16_t addr, - uint8_t num_elem); - - /** @brief Node has been reset. - * - * This callback notifies the application that the local node - * has been reset and needs to be reprovisioned. The node will - * not automatically advertise as unprovisioned, rather the - * bt_mesh_prov_enable() API needs to be called to enable - * unprovisioned advertising on one or more provisioning bearers. - */ - void (*reset)(void); -}; - -/** @brief Provide provisioning input OOB string. - * - * This is intended to be called after the bt_mesh_prov input callback - * has been called with BT_MESH_ENTER_STRING as the action. - * - * @param str String. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_input_string(const char *str); - -/** @brief Provide provisioning input OOB number. - * - * This is intended to be called after the bt_mesh_prov input callback - * has been called with BT_MESH_ENTER_NUMBER as the action. - * - * @param num Number. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_input_number(uint32_t num); - -/** @brief Provide Device public key. - * - * @param public_key Device public key. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[64]); - -/** @brief Use Input OOB authentication. - * - * Provisioner only. - * - * Instruct the unprovisioned device to use the specified Input OOB - * authentication action. When using @ref BT_MESH_PUSH, @ref BT_MESH_TWIST or - * @ref BT_MESH_ENTER_NUMBER, the @ref bt_mesh_prov::output_number callback is - * called with a random number that has to be entered on the unprovisioned - * device. - * - * When using @ref BT_MESH_ENTER_STRING, the @ref bt_mesh_prov::output_string - * callback is called with a random string that has to be entered on the - * unprovisioned device. - * - * @param action Authentication action used by the unprovisioned device. - * @param size Authentication size. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_auth_method_set_input(bt_mesh_input_action_t action, uint8_t size); - -/** @brief Use Output OOB authentication. - * - * Provisioner only. - * - * Instruct the unprovisioned device to use the specified Output OOB - * authentication action. The @ref bt_mesh_prov::input callback will - * be called. - * - * When using @ref BT_MESH_BLINK, @ref BT_MESH_BEEP, @ref BT_MESH_VIBRATE - * or @ref BT_MESH_DISPLAY_NUMBER, and the application has to call - * @ref bt_mesh_input_number with the random number indicated by - * the unprovisioned device. - * - * When using @ref BT_MESH_DISPLAY_STRING, the application has to call - * @ref bt_mesh_input_string with the random string displayed by the - * unprovisioned device. - * - * @param action Authentication action used by the unprovisioned device. - * @param size Authentication size. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_auth_method_set_output(bt_mesh_output_action_t action, uint8_t size); - -/** @brief Use static OOB authentication. - * - * Provisioner only. - * - * Instruct the unprovisioned device to use static OOB authentication, and use - * the given static authentication value when provisioning. - * - * @param static_val Static OOB value. - * @param size Static OOB value size. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_auth_method_set_static(const uint8_t *static_val, uint8_t size); - -/** @brief Don't use OOB authentication. - * - * Provisioner only. - * - * Don't use any authentication when provisioning new devices. This is the - * default behavior. - * - * @warning Not using any authentication exposes the mesh network to - * impersonation attacks, where attackers can pretend to be the - * unprovisioned device to gain access to the network. Authentication - * is strongly encouraged. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_auth_method_set_none(void); - -/** @brief Enable specific provisioning bearers - * - * Enable one or more provisioning bearers. - * - * @param bearers Bit-wise or of provisioning bearers. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers); - -/** @brief Disable specific provisioning bearers - * - * Disable one or more provisioning bearers. - * - * @param bearers Bit-wise or of provisioning bearers. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers); - -/** - * @} - */ - -/** - * @brief Bluetooth Mesh - * @defgroup bt_mesh Bluetooth Mesh - * @ingroup bluetooth - * @{ - */ - -/* Primary Network Key index */ -#define BT_MESH_NET_PRIMARY 0x000 - -/* Features */ -#define BT_MESH_FEAT_RELAY BIT(0) -#define BT_MESH_FEAT_PROXY BIT(1) -#define BT_MESH_FEAT_FRIEND BIT(2) -#define BT_MESH_FEAT_LOW_POWER BIT(3) -#define BT_MESH_FEAT_SUPPORTED (BT_MESH_FEAT_RELAY | \ - BT_MESH_FEAT_PROXY | \ - BT_MESH_FEAT_FRIEND | \ - BT_MESH_FEAT_LOW_POWER) - -/** @brief Initialize Mesh support - * - * After calling this API, the node will not automatically advertise as - * unprovisioned, rather the bt_mesh_prov_enable() API needs to be called - * to enable unprovisioned advertising on one or more provisioning bearers. - * - * @param own_addr_type Node address type - * @param prov Node provisioning information. - * @param comp Node Composition. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_init(uint8_t own_addr_type, - const struct bt_mesh_prov *prov, - const struct bt_mesh_comp *comp); - -/** @brief Reset the state of the local Mesh node. - * - * Resets the state of the node, which means that it needs to be - * reprovisioned to become an active node in a Mesh network again. - * - * After calling this API, the node will not automatically advertise as - * unprovisioned, rather the bt_mesh_prov_enable() API needs to be called - * to enable unprovisioned advertising on one or more provisioning bearers. - * - */ -void bt_mesh_reset(void); - -/** @brief Suspend the Mesh network temporarily. - * - * This API can be used for power saving purposes, but the user should be - * aware that leaving the local node suspended for a long period of time - * may cause it to become permanently disconnected from the Mesh network. - * If at all possible, the Friendship feature should be used instead, to - * make the node into a Low Power Node. - * - * @return 0 on success, or (negative) error code on failure. - */ -int bt_mesh_suspend(void); - -/** @brief Resume a suspended Mesh network. - * - * This API resumes the local node, after it has been suspended using the - * bt_mesh_suspend() API. - * - * @return 0 on success, or (negative) error code on failure. - */ -int bt_mesh_resume(void); - -/** @brief Provision the local Mesh Node. - * - * This API should normally not be used directly by the application. The - * only exception is for testing purposes where manual provisioning is - * desired without an actual external provisioner. - * - * @param net_key Network Key - * @param net_idx Network Key Index - * @param flags Provisioning Flags - * @param iv_index IV Index - * @param addr Primary element address - * @param dev_key Device Key - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, - uint8_t flags, uint32_t iv_index, uint16_t addr, - const uint8_t dev_key[16]); - -/** @brief Provision a Mesh Node using PB-ADV - * - * @param uuid UUID - * @param net_idx Network Key Index - * @param addr Address to assign to remote device. If addr is 0, the lowest - * available address will be chosen. - * @param attention_duration The attention duration to be send to remote device - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_provision_adv(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr, - uint8_t attention_duration); - -/** @brief Check if the local node has been provisioned. - * - * This API can be used to check if the local node has been provisioned - * or not. It can e.g. be helpful to determine if there was a stored - * network in flash, i.e. if the network was restored after calling - * settings_load(). - * - * @return True if the node is provisioned. False otherwise. - */ -bool bt_mesh_is_provisioned(void); - -/** @brief Toggle the IV Update test mode - * - * This API is only available if the IV Update test mode has been enabled - * in Kconfig. It is needed for passing most of the IV Update qualification - * test cases. - * - * @param enable true to enable IV Update test mode, false to disable it. - */ -void bt_mesh_iv_update_test(bool enable); - -/** @brief Toggle the IV Update state - * - * This API is only available if the IV Update test mode has been enabled - * in Kconfig. It is needed for passing most of the IV Update qualification - * test cases. - * - * @return true if IV Update In Progress state was entered, false otherwise. - */ -bool bt_mesh_iv_update(void); - -/** @brief Toggle the Low Power feature of the local device - * - * Enables or disables the Low Power feature of the local device. This is - * exposed as a run-time feature, since the device might want to change - * this e.g. based on being plugged into a stable power source or running - * from a battery power source. - * - * @param enable true to enable LPN functionality, false to disable it. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_lpn_set(bool enable); - -/** @brief Send out a Friend Poll message. - * - * Send a Friend Poll message to the Friend of this node. If there is no - * established Friendship the function will return an error. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_lpn_poll(void); - -/** @brief Register a callback for Friendship changes. - * - * Registers a callback that will be called whenever Friendship gets - * established or is lost. - * - * @param cb Function to call when the Friendship status changes. - */ -void bt_mesh_lpn_set_cb(void (*cb)(uint16_t friend_addr, bool established)); - -/** @brief Terminate Friendship. - * - * Terminated Friendship for given LPN. - * - * @param lpn_addr Low Power Node address. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_mesh_friend_terminate(uint16_t lpn_addr); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif /* __BT_MESH_MAIN_H */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/mesh.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/mesh.h deleted file mode 100644 index 4fce128b4..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/mesh.h +++ /dev/null @@ -1,31 +0,0 @@ -/** @file - * @brief Bluetooth Mesh Profile APIs. - */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __BT_MESH_H -#define __BT_MESH_H - -#include -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "nimble/porting/nimble/include/os/os_mbuf.h" - -#include "glue.h" -#include "access.h" -#include "main.h" -#include "cfg.h" -#include "cfg_srv.h" -#include "health_srv.h" -#include "cfg_cli.h" -#include "health_cli.h" -#include "proxy.h" -#include "cdb.h" -#include "cfg.h" -#include "heartbeat.h" -#include "../../src/app_keys.h" - -#endif /* __BT_MESH_H */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/model_cli.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/model_cli.h deleted file mode 100644 index 87e2dd2be..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/model_cli.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __MODEL_CLI_H__ -#define __MODEL_CLI_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -struct bt_mesh_gen_model_cli { - struct bt_mesh_model *model; - - struct k_sem op_sync; - uint32_t op_pending; - void *op_param; -}; - -extern const struct bt_mesh_model_op gen_onoff_cli_op[]; -extern const struct bt_mesh_model_cb bt_mesh_gen_onoff_cli_cb; - -#define BT_MESH_MODEL_GEN_ONOFF_CLI(cli_data, pub) \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op, pub,\ - cli_data, &bt_mesh_gen_onoff_cli_cb) - -extern const struct bt_mesh_model_op gen_level_cli_op[]; -extern const struct bt_mesh_model_cb bt_mesh_gen_level_cli_cb; - -#define BT_MESH_MODEL_GEN_LEVEL_CLI(cli_data, pub) \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_GEN_LEVEL_CLI, gen_level_cli_op, pub,\ - cli_data, &bt_mesh_gen_level_cli_cb) - -int bt_mesh_gen_onoff_get(uint16_t net_idx, uint16_t addr, uint16_t app_idx, - uint8_t *state); -int bt_mesh_gen_onoff_set(uint16_t net_idx, uint16_t addr, uint16_t app_idx, - uint8_t val, uint8_t *state); -int bt_mesh_gen_level_get(uint16_t net_idx, uint16_t addr, uint16_t app_idx, - int16_t *level); -int bt_mesh_gen_level_set(uint16_t net_idx, uint16_t addr, uint16_t app_idx, - int16_t val, int16_t *state); - -#ifdef __cplusplus -} -#endif - -#endif /* __MODEL_CLI_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/model_srv.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/model_srv.h deleted file mode 100644 index a23296b83..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/model_srv.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __MODEL_SRV_H__ -#define __MODEL_SRV_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -struct bt_mesh_gen_onoff_srv { - struct bt_mesh_model *model; - - int (*get)(struct bt_mesh_model *model, uint8_t *state); - int (*set)(struct bt_mesh_model *model, uint8_t state); -}; - -extern const struct bt_mesh_model_op gen_onoff_srv_op[]; -extern const struct bt_mesh_model_cb gen_onoff_srv_cb; - -#define BT_MESH_MODEL_GEN_ONOFF_SRV(srv, pub) \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, \ - gen_onoff_srv_op, pub, srv, &gen_onoff_srv_cb) - -struct bt_mesh_gen_level_srv { - struct bt_mesh_model *model; - - int (*get)(struct bt_mesh_model *model, int16_t *level); - int (*set)(struct bt_mesh_model *model, int16_t level); -}; - -extern const struct bt_mesh_model_op gen_level_srv_op[]; -extern const struct bt_mesh_model_cb gen_level_srv_cb; - -#define BT_MESH_MODEL_GEN_LEVEL_SRV(srv, pub) \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, \ - gen_level_srv_op, pub, srv, &gen_level_srv_cb) - -struct bt_mesh_light_lightness_srv { - struct bt_mesh_model *model; - - int (*get)(struct bt_mesh_model *model, int16_t *level); - int (*set)(struct bt_mesh_model *model, int16_t level); -}; - -extern const struct bt_mesh_model_op light_lightness_srv_op[]; -extern const struct bt_mesh_model_cb light_lightness_srv_cb; - -#define BT_MESH_MODEL_LIGHT_LIGHTNESS_SRV(srv, pub) \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV, \ - light_lightness_srv_op, pub, srv, &light_lightness_srv_cb) - -void bt_mesh_set_gen_onoff_srv_cb(int (*get)(struct bt_mesh_model *model, uint8_t *state), - int (*set)(struct bt_mesh_model *model, uint8_t state)); -void bt_mesh_set_gen_level_srv_cb(int (*get)(struct bt_mesh_model *model, int16_t *level), - int (*set)(struct bt_mesh_model *model, int16_t level)); -void bt_mesh_set_light_lightness_srv_cb(int (*get)(struct bt_mesh_model *model, int16_t *level), - int (*set)(struct bt_mesh_model *model, int16_t level)); - -#ifdef __cplusplus -} -#endif - -#endif /* __MODEL_SRV_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/porting.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/porting.h deleted file mode 100644 index 1667a8a04..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/porting.h +++ /dev/null @@ -1,27 +0,0 @@ -/** @file - * @brief Bluetooth Mesh Porting APIs. - */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __BT_MESH_PORTING_H -#define __BT_MESH_PORTING_H - -#ifdef __cplusplus -extern "C" { -#endif - -void mesh_adv_thread(void *args); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif /* __BT_MESH_PORTING_H */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/proxy.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/proxy.h deleted file mode 100644 index 63bbfa3e5..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/proxy.h +++ /dev/null @@ -1,43 +0,0 @@ -/** @file - * @brief Bluetooth Mesh Proxy APIs. - */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __BT_MESH_PROXY_H -#define __BT_MESH_PROXY_H - -/** - * @brief Bluetooth Mesh Proxy - * @defgroup bt_mesh_proxy Bluetooth Mesh Proxy - * @ingroup bt_mesh - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Enable advertising with Node Identity. - * - * This API requires that GATT Proxy support has been enabled. Once called - * each subnet will start advertising using Node Identity for the next - * 60 seconds. - * - * @return 0 on success, or (negative) error code on failure. - */ -int bt_mesh_proxy_identity_enable(void); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif /* __BT_MESH_PROXY_H */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/slist.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/slist.h deleted file mode 100644 index 8a858f83b..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/slist.h +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * - * @brief Single-linked list implementation - * - * Single-linked list implementation using inline macros/functions. - * This API is not thread safe, and thus if a list is used across threads, - * calls to functions must be protected with synchronization primitives. - */ - -#ifndef __SLIST_H__ -#define __SLIST_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -struct _snode { - struct _snode *next; -}; - -typedef struct _snode sys_snode_t; - -struct _slist { - sys_snode_t *head; - sys_snode_t *tail; -}; - -typedef struct _slist sys_slist_t; - -/** - * @brief Provide the primitive to iterate on a list - * Note: the loop is unsafe and thus __sn should not be removed - * - * User _MUST_ add the loop statement curly braces enclosing its own code: - * - * SYS_SLIST_FOR_EACH_NODE(l, n) { - * - * } - * - * This and other SYS_SLIST_*() macros are not thread safe. - * - * @param __sl A pointer on a sys_slist_t to iterate on - * @param __sn A sys_snode_t pointer to peek each node of the list - */ -#define SYS_SLIST_FOR_EACH_NODE(__sl, __sn) \ - for (__sn = sys_slist_peek_head(__sl); __sn; \ - __sn = sys_slist_peek_next(__sn)) - -/** - * @brief Provide the primitive to iterate on a list, from a node in the list - * Note: the loop is unsafe and thus __sn should not be removed - * - * User _MUST_ add the loop statement curly braces enclosing its own code: - * - * SYS_SLIST_ITERATE_FROM_NODE(l, n) { - * - * } - * - * Like SYS_SLIST_FOR_EACH_NODE(), but __dn already contains a node in the list - * where to start searching for the next entry from. If NULL, it starts from - * the head. - * - * This and other SYS_SLIST_*() macros are not thread safe. - * - * @param __sl A pointer on a sys_slist_t to iterate on - * @param __sn A sys_snode_t pointer to peek each node of the list - * it contains the starting node, or NULL to start from the head - */ -#define SYS_SLIST_ITERATE_FROM_NODE(__sl, __sn) \ - for (__sn = __sn ? sys_slist_peek_next_no_check(__sn) \ - : sys_slist_peek_head(__sl); \ - __sn; \ - __sn = sys_slist_peek_next(__sn)) - -/** - * @brief Provide the primitive to safely iterate on a list - * Note: __sn can be removed, it will not break the loop. - * - * User _MUST_ add the loop statement curly braces enclosing its own code: - * - * SYS_SLIST_FOR_EACH_NODE_SAFE(l, n, s) { - * - * } - * - * This and other SYS_SLIST_*() macros are not thread safe. - * - * @param __sl A pointer on a sys_slist_t to iterate on - * @param __sn A sys_snode_t pointer to peek each node of the list - * @param __sns A sys_snode_t pointer for the loop to run safely - */ -#define SYS_SLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \ - for (__sn = sys_slist_peek_head(__sl), \ - __sns = sys_slist_peek_next(__sn); \ - __sn; __sn = __sns, \ - __sns = sys_slist_peek_next(__sn)) - -/* - * @brief Provide the primitive to resolve the container of a list node - * Note: it is safe to use with NULL pointer nodes - * - * @param __ln A pointer on a sys_node_t to get its container - * @param __cn Container struct type pointer - * @param __n The field name of sys_node_t within the container struct - */ -#define SYS_SLIST_CONTAINER(__ln, __cn, __n) \ - ((__ln) ? CONTAINER_OF((__ln), __typeof__(*(__cn)), __n) : NULL) -/* - * @brief Provide the primitive to peek container of the list head - * - * @param __sl A pointer on a sys_slist_t to peek - * @param __cn Container struct type pointer - * @param __n The field name of sys_node_t within the container struct - */ -#define SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n) \ - SYS_SLIST_CONTAINER(sys_slist_peek_head(__sl), __cn, __n) - -/* - * @brief Provide the primitive to peek container of the list tail - * - * @param __sl A pointer on a sys_slist_t to peek - * @param __cn Container struct type pointer - * @param __n The field name of sys_node_t within the container struct - */ -#define SYS_SLIST_PEEK_TAIL_CONTAINER(__sl, __cn, __n) \ - SYS_SLIST_CONTAINER(sys_slist_peek_tail(__sl), __cn, __n) - -/* - * @brief Provide the primitive to peek the next container - * - * @param __cn Container struct type pointer - * @param __n The field name of sys_node_t within the container struct - */ - -#define SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n) \ - ((__cn) ? SYS_SLIST_CONTAINER(sys_slist_peek_next(&((__cn)->__n)), \ - __cn, __n) : NULL) - -/** - * @brief Provide the primitive to iterate on a list under a container - * Note: the loop is unsafe and thus __cn should not be detached - * - * User _MUST_ add the loop statement curly braces enclosing its own code: - * - * SYS_SLIST_FOR_EACH_CONTAINER(l, c, n) { - * - * } - * - * @param __sl A pointer on a sys_slist_t to iterate on - * @param __cn A pointer to peek each entry of the list - * @param __n The field name of sys_node_t within the container struct - */ -#define SYS_SLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \ - for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n); __cn; \ - __cn = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n)) - -/** - * @brief Provide the primitive to safely iterate on a list under a container - * Note: __cn can be detached, it will not break the loop. - * - * User _MUST_ add the loop statement curly braces enclosing its own code: - * - * SYS_SLIST_FOR_EACH_NODE_SAFE(l, c, cn, n) { - * - * } - * - * @param __sl A pointer on a sys_slist_t to iterate on - * @param __cn A pointer to peek each entry of the list - * @param __cns A pointer for the loop to run safely - * @param __n The field name of sys_node_t within the container struct - */ -#define SYS_SLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \ - for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n), \ - __cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n); __cn; \ - __cn = __cns, __cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n)) - -/** - * @brief Initialize a list - * - * @param list A pointer on the list to initialize - */ -static inline void sys_slist_init(sys_slist_t *list) -{ - list->head = NULL; - list->tail = NULL; -} - -#define SYS_SLIST_STATIC_INIT(ptr_to_list) {NULL, NULL} - -/** - * @brief Test if the given list is empty - * - * @param list A pointer on the list to test - * - * @return a boolean, true if it's empty, false otherwise - */ -static inline bool sys_slist_is_empty(sys_slist_t *list) -{ - return (!list->head); -} - -/** - * @brief Peek the first node from the list - * - * @param list A point on the list to peek the first node from - * - * @return A pointer on the first node of the list (or NULL if none) - */ -static inline sys_snode_t *sys_slist_peek_head(sys_slist_t *list) -{ - return list->head; -} - -/** - * @brief Peek the last node from the list - * - * @param list A point on the list to peek the last node from - * - * @return A pointer on the last node of the list (or NULL if none) - */ -static inline sys_snode_t *sys_slist_peek_tail(sys_slist_t *list) -{ - return list->tail; -} - -/** - * @brief Peek the next node from current node, node is not NULL - * - * Faster then sys_slist_peek_next() if node is known not to be NULL. - * - * @param node A pointer on the node where to peek the next node - * - * @return a pointer on the next node (or NULL if none) - */ -static inline sys_snode_t *sys_slist_peek_next_no_check(sys_snode_t *node) -{ - return node->next; -} - -/** - * @brief Peek the next node from current node - * - * @param node A pointer on the node where to peek the next node - * - * @return a pointer on the next node (or NULL if none) - */ -static inline sys_snode_t *sys_slist_peek_next(sys_snode_t *node) -{ - return node ? sys_slist_peek_next_no_check(node) : NULL; -} - -/** - * @brief Prepend a node to the given list - * - * This and other sys_slist_*() functions are not thread safe. - * - * @param list A pointer on the list to affect - * @param node A pointer on the node to prepend - */ -static inline void sys_slist_prepend(sys_slist_t *list, - sys_snode_t *node) -{ - node->next = list->head; - list->head = node; - - if (!list->tail) { - list->tail = list->head; - } -} - -/** - * @brief Append a node to the given list - * - * This and other sys_slist_*() functions are not thread safe. - * - * @param list A pointer on the list to affect - * @param node A pointer on the node to append - */ -static inline void sys_slist_append(sys_slist_t *list, - sys_snode_t *node) -{ - node->next = NULL; - - if (!list->tail) { - list->tail = node; - list->head = node; - } else { - list->tail->next = node; - list->tail = node; - } -} - -/** - * @brief Append a list to the given list - * - * Append a singly-linked, NULL-terminated list consisting of nodes containing - * the pointer to the next node as the first element of a node, to @a list. - * This and other sys_slist_*() functions are not thread safe. - * - * @param list A pointer on the list to affect - * @param head A pointer to the first element of the list to append - * @param tail A pointer to the last element of the list to append - */ -static inline void sys_slist_append_list(sys_slist_t *list, - void *head, void *tail) -{ - if (!list->tail) { - list->head = (sys_snode_t *)head; - list->tail = (sys_snode_t *)tail; - } else { - list->tail->next = (sys_snode_t *)head; - list->tail = (sys_snode_t *)tail; - } -} - -/** - * @brief merge two slists, appending the second one to the first - * - * When the operation is completed, the appending list is empty. - * This and other sys_slist_*() functions are not thread safe. - * - * @param list A pointer on the list to affect - * @param list_to_append A pointer to the list to append. - */ -static inline void sys_slist_merge_slist(sys_slist_t *list, - sys_slist_t *list_to_append) -{ - sys_slist_append_list(list, list_to_append->head, - list_to_append->tail); - sys_slist_init(list_to_append); -} - -/** - * @brief Insert a node to the given list - * - * This and other sys_slist_*() functions are not thread safe. - * - * @param list A pointer on the list to affect - * @param prev A pointer on the previous node - * @param node A pointer on the node to insert - */ -static inline void sys_slist_insert(sys_slist_t *list, - sys_snode_t *prev, - sys_snode_t *node) -{ - if (!prev) { - sys_slist_prepend(list, node); - } else if (!prev->next) { - sys_slist_append(list, node); - } else { - node->next = prev->next; - prev->next = node; - } -} - -/** - * @brief Fetch and remove the first node of the given list - * - * List must be known to be non-empty. - * This and other sys_slist_*() functions are not thread safe. - * - * @param list A pointer on the list to affect - * - * @return A pointer to the first node of the list - */ -static inline sys_snode_t *sys_slist_get_not_empty(sys_slist_t *list) -{ - sys_snode_t *node = list->head; - - list->head = node->next; - if (list->tail == node) { - list->tail = list->head; - } - - return node; -} - -/** - * @brief Fetch and remove the first node of the given list - * - * This and other sys_slist_*() functions are not thread safe. - * - * @param list A pointer on the list to affect - * - * @return A pointer to the first node of the list (or NULL if empty) - */ -static inline sys_snode_t *sys_slist_get(sys_slist_t *list) -{ - return sys_slist_is_empty(list) ? NULL : sys_slist_get_not_empty(list); -} - -/** - * @brief Remove a node - * - * This and other sys_slist_*() functions are not thread safe. - * - * @param list A pointer on the list to affect - * @param prev_node A pointer on the previous node - * (can be NULL, which means the node is the list's head) - * @param node A pointer on the node to remove - */ -static inline void sys_slist_remove(sys_slist_t *list, - sys_snode_t *prev_node, - sys_snode_t *node) -{ - if (!prev_node) { - list->head = node->next; - - /* Was node also the tail? */ - if (list->tail == node) { - list->tail = list->head; - } - } else { - prev_node->next = node->next; - - /* Was node the tail? */ - if (list->tail == node) { - list->tail = prev_node; - } - } - - node->next = NULL; -} - -/** - * @brief Find and remove a node from a list - * - * This and other sys_slist_*() functions are not thread safe. - * - * @param list A pointer on the list to affect - * @param node A pointer on the node to remove from the list - * - * @return true if node was removed - */ -static inline bool sys_slist_find_and_remove(sys_slist_t *list, - sys_snode_t *node) -{ - sys_snode_t *prev = NULL; - sys_snode_t *test; - - SYS_SLIST_FOR_EACH_NODE(list, test) { - if (test == node) { - sys_slist_remove(list, prev, node); - return true; - } - - prev = test; - } - - return false; -} - - -#ifdef __cplusplus -} -#endif - -#endif /* __SLIST_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/testing.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/testing.h deleted file mode 100644 index 580aafe41..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/include/mesh/testing.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @file testing.h - * @brief Internal API for Bluetooth testing. - */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __BT_TESTING_H -#define __BT_TESTING_H - -#include "slist.h" -#include "glue.h" -#include "access.h" - -/** - * @brief Bluetooth testing - * @defgroup bt_test_cb Bluetooth testing callbacks - * @ingroup bluetooth - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** @brief Bluetooth Testing callbacks structure. - * - * Callback structure to be used for Bluetooth testing purposes. - * Allows access to Bluetooth stack internals, not exposed by public API. - */ -struct bt_test_cb { - void (*mesh_net_recv)(uint8_t ttl, uint8_t ctl, uint16_t src, uint16_t dst, - const void *payload, size_t payload_len); - void (*mesh_model_bound)(uint16_t addr, struct bt_mesh_model *model, - uint16_t key_idx); - void (*mesh_model_unbound)(uint16_t addr, struct bt_mesh_model *model, - uint16_t key_idx); - void (*mesh_prov_invalid_bearer)(uint8_t opcode); - void (*mesh_trans_incomp_timer_exp)(void); - - sys_snode_t node; -}; - -/** Register callbacks for Bluetooth testing purposes - * - * @param cb bt_test_cb callback structure - */ -void bt_test_cb_register(struct bt_test_cb *cb); - -/** Unregister callbacks for Bluetooth testing purposes - * - * @param cb bt_test_cb callback structure - */ -void bt_test_cb_unregister(struct bt_test_cb *cb); - -/** Send Friend Subscription List Add message. - * - * Used by Low Power node to send the group address for which messages are to - * be stored by Friend node. - * - * @param group Group address - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_test_mesh_lpn_group_add(uint16_t group); - -/** Send Friend Subscription List Remove message. - * - * Used by Low Power node to remove the group addresses from Friend node - * subscription list. Messages sent to those addresses will not be stored - * by Friend node. - * - * @param groups Group addresses - * @param groups_count Group addresses count - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_test_mesh_lpn_group_remove(uint16_t *groups, size_t groups_count); - -/** Clear replay protection list cache. - * - * @return Zero on success or (negative) error code otherwise. - */ -int bt_test_mesh_rpl_clear(void); - -uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx); -uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool store); -int cmd_mesh_init(int argc, char *argv[]); - -int bt_test_shell_init(void); -int bt_test_bind_app_key_to_model(struct bt_mesh_model *model, uint16_t key_idx, uint16_t id); - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* __BT_TESTING_H */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/access.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/access.c deleted file mode 100644 index 306ff8c2f..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/access.c +++ /dev/null @@ -1,851 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_ACCESS_LOG - -#include -#include "nimble/porting/nimble/include/os/os_mbuf.h" - -#include "../include/mesh/mesh.h" - -#include "mesh_priv.h" -#include "adv.h" -#include "net.h" -#include "lpn.h" -#include "transport.h" -#include "access.h" -#include "foundation.h" -#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS) -#include "../include/mesh/model_cli.h" -#endif - -static const struct bt_mesh_comp *dev_comp; -static uint16_t dev_primary_addr; - -void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, - struct bt_mesh_elem *elem, - bool vnd, bool primary, - void *user_data), - void *user_data) -{ - int i, j; - - for (i = 0; i < dev_comp->elem_count; i++) { - struct bt_mesh_elem *elem = &dev_comp->elem[i]; - - for (j = 0; j < elem->model_count; j++) { - struct bt_mesh_model *model = &elem->models[j]; - - func(model, elem, false, i == 0, user_data); - } - - for (j = 0; j < elem->vnd_model_count; j++) { - struct bt_mesh_model *model = &elem->vnd_models[j]; - - func(model, elem, true, i == 0, user_data); - } - } -} - -int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod) -{ - int period; - - if (!mod->pub) { - return 0; - } - - switch (mod->pub->period >> 6) { - case 0x00: - /* 1 step is 100 ms */ - period = K_MSEC((mod->pub->period & BIT_MASK(6)) * 100); - break; - case 0x01: - /* 1 step is 1 second */ - period = K_SECONDS(mod->pub->period & BIT_MASK(6)); - break; - case 0x02: - /* 1 step is 10 seconds */ - period = K_SECONDS((mod->pub->period & BIT_MASK(6)) * 10); - break; - case 0x03: - /* 1 step is 10 minutes */ - period = K_MINUTES((mod->pub->period & BIT_MASK(6)) * 10); - break; - default: - CODE_UNREACHABLE; - } - - if (mod->pub->fast_period) { - return period >> mod->pub->period_div; - } else { - return period; - } -} - -static int32_t next_period(struct bt_mesh_model *mod) -{ - struct bt_mesh_model_pub *pub = mod->pub; - uint32_t elapsed, period; - - period = bt_mesh_model_pub_period_get(mod); - if (!period) { - return 0; - } - - elapsed = k_uptime_get_32() - pub->period_start; - - BT_DBG("Publishing took %ums", (unsigned) elapsed); - - if (elapsed > period) { - BT_WARN("Publication sending took longer than the period"); - /* Return smallest positive number since 0 means disabled */ - return K_MSEC(1); - } - - return period - elapsed; -} - -static void publish_sent(int err, void *user_data) -{ - struct bt_mesh_model *mod = user_data; - int32_t delay; - - BT_DBG("err %d", err); - - if (mod->pub->count) { - delay = BT_MESH_PUB_TRANSMIT_INT(mod->pub->retransmit); - } else { - delay = next_period(mod); - } - - if (delay) { - BT_DBG("Publishing next time in %dms", (int) delay); - k_delayed_work_submit(&mod->pub->timer, delay); - } -} - -static void publish_start(uint16_t duration, int err, void *user_data) -{ - struct bt_mesh_model *mod = user_data; - struct bt_mesh_model_pub *pub = mod->pub; - - if (err) { - BT_ERR("Failed to publish: err %d", err); - return; - } - - /* Initialize the timestamp for the beginning of a new period */ - if (pub->count == BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit)) { - pub->period_start = k_uptime_get_32(); - } -} - -static const struct bt_mesh_send_cb pub_sent_cb = { - .start = publish_start, - .end = publish_sent, -}; - -static int publish_retransmit(struct bt_mesh_model *mod) -{ - struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); - struct bt_mesh_model_pub *pub = mod->pub; - struct bt_mesh_msg_ctx ctx = { - .addr = pub->addr, - .send_ttl = pub->ttl, - .app_idx = pub->key, - }; - struct bt_mesh_net_tx tx = { - .ctx = &ctx, - .src = bt_mesh_model_elem(mod)->addr, - .friend_cred = pub->cred, - }; - int err; - - net_buf_simple_init(sdu, 0); - net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_len); - - pub->count--; - - err = bt_mesh_trans_send(&tx, sdu, &pub_sent_cb, mod); - - os_mbuf_free_chain(sdu); - return err; -} - -static void publish_retransmit_end(int err, struct bt_mesh_model_pub *pub) -{ - /* Cancel all retransmits for this publish attempt */ - pub->count = 0U; - /* Make sure the publish timer gets reset */ - publish_sent(err, pub->mod); -} - -static void mod_publish(struct ble_npl_event *work) -{ - struct bt_mesh_model_pub *pub = ble_npl_event_get_arg(work); - int32_t period_ms; - int err; - - BT_DBG(""); - - period_ms = bt_mesh_model_pub_period_get(pub->mod); - BT_DBG("period %u ms", (unsigned) period_ms); - - if (pub->count) { - err = publish_retransmit(pub->mod); - if (err) { - BT_ERR("Failed to retransmit (err %d)", err); - - pub->count = 0; - - /* Continue with normal publication */ - if (period_ms) { - k_delayed_work_submit(&pub->timer, period_ms); - } - } - - return; - } - - if (!period_ms) { - return; - } - - __ASSERT_NO_MSG(pub->update != NULL); - - err = pub->update(pub->mod); - if (err) { - /* Cancel this publish attempt. */ - BT_DBG("Update failed, skipping publish (err: %d)", err); - pub->period_start = k_uptime_get_32(); - publish_retransmit_end(err, pub); - return; - } - - err = bt_mesh_model_publish(pub->mod); - if (err) { - BT_ERR("Publishing failed (err %d)", err); - } -} - -struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod) -{ - return &dev_comp->elem[mod->elem_idx]; -} - -struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_idx) -{ - struct bt_mesh_elem *elem; - - if (elem_idx >= dev_comp->elem_count) { - BT_ERR("Invalid element index %u", elem_idx); - return NULL; - } - - elem = &dev_comp->elem[elem_idx]; - - if (vnd) { - if (mod_idx >= elem->vnd_model_count) { - BT_ERR("Invalid vendor model index %u", mod_idx); - return NULL; - } - - return &elem->vnd_models[mod_idx]; - } else { - if (mod_idx >= elem->model_count) { - BT_ERR("Invalid SIG model index %u", mod_idx); - return NULL; - } - - return &elem->models[mod_idx]; - } -} - -static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, - bool vnd, bool primary, void *user_data) -{ - int i; - int *err = user_data; - - if (*err) { - return; - } - - if (mod->pub) { - mod->pub->mod = mod; - k_delayed_work_init(&mod->pub->timer, mod_publish); - k_delayed_work_add_arg(&mod->pub->timer, mod->pub); - } - - for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { - mod->keys[i] = BT_MESH_KEY_UNUSED; - } - - mod->elem_idx = elem - dev_comp->elem; - if (vnd) { - mod->mod_idx = mod - elem->vnd_models; - } else { - mod->mod_idx = mod - elem->models; - } - - if (mod->cb && mod->cb->init) { - *err = mod->cb->init(mod); - } -} - -int bt_mesh_comp_register(const struct bt_mesh_comp *comp) -{ - int err; - - /* There must be at least one element */ - if (!comp->elem_count) { - return -EINVAL; - } - - dev_comp = comp; - - err = 0; - bt_mesh_model_foreach(mod_init, &err); - - return err; -} - -void bt_mesh_comp_provision(uint16_t addr) -{ - int i; - - dev_primary_addr = addr; - - BT_DBG("addr 0x%04x elem_count %zu", addr, dev_comp->elem_count); - - for (i = 0; i < dev_comp->elem_count; i++) { - struct bt_mesh_elem *elem = &dev_comp->elem[i]; - - elem->addr = addr++; - - BT_DBG("addr 0x%04x mod_count %u vnd_mod_count %u", - elem->addr, elem->model_count, elem->vnd_model_count); - } -} - -void bt_mesh_comp_unprovision(void) -{ - BT_DBG(""); - - dev_primary_addr = BT_MESH_ADDR_UNASSIGNED; -} - -uint16_t bt_mesh_primary_addr(void) -{ - return dev_primary_addr; -} - -static uint16_t *model_group_get(struct bt_mesh_model *mod, uint16_t addr) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(mod->groups); i++) { - if (mod->groups[i] == addr) { - return &mod->groups[i]; - } - } - - return NULL; -} - -struct find_group_visitor_ctx { - uint16_t *entry; - struct bt_mesh_model *mod; - uint16_t addr; -}; - -static enum bt_mesh_walk find_group_mod_visitor(struct bt_mesh_model *mod, - uint32_t depth, void *user_data) -{ - struct find_group_visitor_ctx *ctx = user_data; - - if (mod->elem_idx != ctx->mod->elem_idx) { - return BT_MESH_WALK_CONTINUE; - } - - ctx->entry = model_group_get(mod, ctx->addr); - if (ctx->entry) { - ctx->mod = mod; - return BT_MESH_WALK_STOP; - } - - return BT_MESH_WALK_CONTINUE; -} - -uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr) -{ - struct find_group_visitor_ctx ctx = { - .mod = *mod, - .entry = NULL, - .addr = addr, - }; - - bt_mesh_model_tree_walk(bt_mesh_model_root(*mod), - find_group_mod_visitor, &ctx); - - *mod = ctx.mod; - return ctx.entry; -} - -static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem, - uint16_t group_addr) -{ - struct bt_mesh_model *model; - uint16_t *match; - int i; - - for (i = 0; i < elem->model_count; i++) { - model = &elem->models[i]; - - match = model_group_get(model, group_addr); - if (match) { - return model; - } - } - - for (i = 0; i < elem->vnd_model_count; i++) { - model = &elem->vnd_models[i]; - - match = model_group_get(model, group_addr); - if (match) { - return model; - } - } - - return NULL; -} - -struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr) -{ - uint16_t index; - - if (BT_MESH_ADDR_IS_UNICAST(addr)) { - index = (addr - dev_comp->elem[0].addr); - if (index < dev_comp->elem_count) { - return &dev_comp->elem[index]; - } else { - return NULL; - } - } - - for (index = 0; index < dev_comp->elem_count; index++) { - struct bt_mesh_elem *elem = &dev_comp->elem[index]; - - if (bt_mesh_elem_find_group(elem, addr)) { - return elem; - } - } - - return NULL; -} - -uint8_t bt_mesh_elem_count(void) -{ - return dev_comp->elem_count; -} - -static bool model_has_key(struct bt_mesh_model *mod, uint16_t key) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { - if (mod->keys[i] == key || - (mod->keys[i] == BT_MESH_KEY_DEV_ANY && - BT_MESH_IS_DEV_KEY(key))) { - return true; - } - } - - return false; -} - -static bool model_has_dst(struct bt_mesh_model *mod, uint16_t dst) -{ - if (BT_MESH_ADDR_IS_UNICAST(dst)) { - return (dev_comp->elem[mod->elem_idx].addr == dst); - } else if (BT_MESH_ADDR_IS_GROUP(dst) || BT_MESH_ADDR_IS_VIRTUAL(dst)) { - return !!bt_mesh_model_find_group(&mod, dst); - } - - /* If a message with a fixed group address is sent to the access layer, - * the lower layers have already confirmed that we are subscribing to - * it. All models on the primary element should receive the message. - */ - return mod->elem_idx == 0; -} - -static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models, - uint8_t model_count, uint32_t opcode, - struct bt_mesh_model **model) -{ - uint8_t i; - - for (i = 0; i < model_count; i++) { - const struct bt_mesh_model_op *op; - - *model = &models[i]; - - for (op = (*model)->op; op->func; op++) { - if (op->opcode == opcode) { - return op; - } - } - } - - *model = NULL; - return NULL; -} - -static int get_opcode(struct os_mbuf *buf, uint32_t *opcode) -{ - switch (buf->om_data[0] >> 6) { - case 0x00: - case 0x01: - if (buf->om_data[0] == 0x7f) { - BT_ERR("Ignoring RFU OpCode"); - return -EINVAL; - } - - *opcode = net_buf_simple_pull_u8(buf); - return 0; - case 0x02: - if (buf->om_len < 2) { - BT_ERR("Too short payload for 2-octet OpCode"); - return -EINVAL; - } - - *opcode = net_buf_simple_pull_be16(buf); - return 0; - case 0x03: - if (buf->om_len < 3) { - BT_ERR("Too short payload for 3-octet OpCode"); - return -EINVAL; - } - - *opcode = net_buf_simple_pull_u8(buf) << 16; - /* Using LE for the CID since the model layer is defined as - * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 - * will declare the opcode in this way. - */ - *opcode |= net_buf_simple_pull_le16(buf); - return 0; - } - - CODE_UNREACHABLE; -} - -void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) -{ - struct bt_mesh_model *models, *model; - const struct bt_mesh_model_op *op; - uint32_t opcode; - uint8_t count; - int i; - - BT_DBG("app_idx 0x%04x src 0x%04x dst 0x%04x", rx->ctx.app_idx, - rx->ctx.addr, rx->ctx.recv_dst); - BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - - if (get_opcode(buf, &opcode) < 0) { - BT_WARN("Unable to decode OpCode"); - return; - } - - BT_DBG("OpCode 0x%08x", (unsigned) opcode); - - for (i = 0; i < dev_comp->elem_count; i++) { - struct bt_mesh_elem *elem = &dev_comp->elem[i]; - struct net_buf_simple_state state; - - /* SIG models cannot contain 3-byte (vendor) OpCodes, and - * vendor models cannot contain SIG (1- or 2-byte) OpCodes, so - * we only need to do the lookup in one of the model lists. - */ - if (BT_MESH_MODEL_OP_LEN(opcode) < 3) { - models = elem->models; - count = elem->model_count; - } else { - models = elem->vnd_models; - count = elem->vnd_model_count; - } - - op = find_op(models, count, opcode, &model); - if (!op) { - BT_DBG("No OpCode 0x%08x for elem %d", opcode, i); - continue; - } - - if (!model_has_key(model, rx->ctx.app_idx)) { - continue; - } - - if (!model_has_dst(model, rx->ctx.recv_dst)) { - continue; - } - - if (buf->om_len < op->min_len) { - BT_ERR("Too short message for OpCode 0x%08x", opcode); - continue; - } - - /* The callback will likely parse the buffer, so - * store the parsing state in case multiple models - * receive the message. - */ - net_buf_simple_save(buf, &state); - op->func(model, &rx->ctx, buf); - net_buf_simple_restore(buf, &state); - } -} - -void bt_mesh_model_msg_init(struct os_mbuf *msg, uint32_t opcode) -{ - net_buf_simple_init(msg, 0); - - switch (BT_MESH_MODEL_OP_LEN(opcode)) { - case 1: - net_buf_simple_add_u8(msg, opcode); - break; - case 2: - net_buf_simple_add_be16(msg, opcode); - break; - case 3: - net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff)); - /* Using LE for the CID since the model layer is defined as - * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 - * will declare the opcode in this way. - */ - net_buf_simple_add_le16(msg, opcode & 0xffff); - break; - default: - BT_WARN("Unknown opcode format"); - break; - } -} - -static int model_send(struct bt_mesh_model *model, - struct bt_mesh_net_tx *tx, bool implicit_bind, - struct os_mbuf *msg, - const struct bt_mesh_send_cb *cb, void *cb_data) -{ - BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->ctx->net_idx, - tx->ctx->app_idx, tx->ctx->addr); - BT_DBG("len %u: %s", msg->om_len, bt_hex(msg->om_data, msg->om_len)); - - if (!bt_mesh_is_provisioned()) { - BT_ERR("Local node is not yet provisioned"); - return -EAGAIN; - } - - if (net_buf_simple_tailroom(msg) < 4) { - BT_ERR("Not enough tailroom for TransMIC"); - return -EINVAL; - } - - if (msg->om_len > BT_MESH_TX_SDU_MAX - 4) { - BT_ERR("Too big message"); - return -EMSGSIZE; - } - - if (!implicit_bind && !model_has_key(model, tx->ctx->app_idx)) { - BT_ERR("Model not bound to AppKey 0x%04x", tx->ctx->app_idx); - return -EINVAL; - } - - return bt_mesh_trans_send(tx, msg, cb, cb_data); -} - -int bt_mesh_model_send(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *msg, - const struct bt_mesh_send_cb *cb, void *cb_data) -{ - struct bt_mesh_net_tx tx = { - .ctx = ctx, - .src = bt_mesh_model_elem(model)->addr, - }; - - return model_send(model, &tx, false, msg, cb, cb_data); -} - -int bt_mesh_model_publish(struct bt_mesh_model *model) -{ - struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); - struct bt_mesh_model_pub *pub = model->pub; - struct bt_mesh_msg_ctx ctx = { - .addr = pub->addr, - .send_ttl = pub->ttl, - .send_rel = pub->send_rel, - .app_idx = pub->key, - }; - struct bt_mesh_net_tx tx = { - .ctx = &ctx, - .src = bt_mesh_model_elem(model)->addr, - }; - int err; - - BT_DBG(""); - - if (!pub) { - err = -ENOTSUP; - goto done; - } - - if (pub->addr == BT_MESH_ADDR_UNASSIGNED) { - err = -EADDRNOTAVAIL; - goto done; - } - - if (pub->msg->om_len + 4 > BT_MESH_TX_SDU_MAX) { - BT_ERR("Message does not fit maximum SDU size"); - err = -EMSGSIZE; - goto done; - } - - if (pub->count) { - BT_WARN("Clearing publish retransmit timer"); - k_delayed_work_cancel(&pub->timer); - } - - net_buf_simple_init(sdu, 0); - net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_len); - - tx.friend_cred = pub->cred; - - pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit); - - BT_DBG("Publish Retransmit Count %u Interval %ums", pub->count, - BT_MESH_PUB_TRANSMIT_INT(pub->retransmit)); - - err = model_send(model, &tx, true, sdu, &pub_sent_cb, model); - if (err) { - publish_retransmit_end(err, pub); - } - -done: - os_mbuf_free_chain(sdu); - return err; -} - -struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, - uint16_t company, uint16_t id) -{ - uint8_t i; - - for (i = 0; i < elem->vnd_model_count; i++) { - if (elem->vnd_models[i].vnd.company == company && - elem->vnd_models[i].vnd.id == id) { - return &elem->vnd_models[i]; - } - } - - return NULL; -} - -struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, - uint16_t id) -{ - uint8_t i; - - for (i = 0; i < elem->model_count; i++) { - if (elem->models[i].id == id) { - return &elem->models[i]; - } - } - - return NULL; -} - -const struct bt_mesh_comp *bt_mesh_comp_get(void) -{ - return dev_comp; -} - -struct bt_mesh_model *bt_mesh_model_root(struct bt_mesh_model *mod) -{ -#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS - while (mod->next) { - mod = mod->next; - } -#endif - return mod; -} - -void bt_mesh_model_tree_walk(struct bt_mesh_model *root, - enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod, - uint32_t depth, - void *user_data), - void *user_data) -{ - struct bt_mesh_model *m = root; - int depth = 0; - /* 'skip' is set to true when we ascend from child to parent node. - * In that case, we want to skip calling the callback on the parent - * node and we don't want to descend onto a child node as those - * nodes have already been visited. - */ - bool skip = false; - - do { - if (!skip && - cb(m, (uint32_t)depth, user_data) == BT_MESH_WALK_STOP) { - return; - } -#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS) - if (!skip && m->extends) { - m = m->extends; - depth++; - } else if (m->flags & BT_MESH_MOD_NEXT_IS_PARENT) { - m = m->next; - depth--; - skip = true; - } else { - m = m->next; - skip = false; - } -#endif - } while (m && depth > 0); -} - -#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS) -int bt_mesh_model_extend(struct bt_mesh_model *mod, - struct bt_mesh_model *base_mod) -{ - /* Form a cyclical LCRS tree: - * The extends-pointer points to the first child, and the next-pointer - * points to the next sibling. The last sibling is marked by the - * BT_MESH_MOD_NEXT_IS_PARENT flag, and its next-pointer points back to - * the parent. This way, the whole tree is accessible from any node. - * - * We add children (extend them) by inserting them as the first child. - */ - if (base_mod->next) { - return -EALREADY; - } - - if (mod->extends) { - base_mod->next = mod->extends; - } else { - base_mod->next = mod; - base_mod->flags |= BT_MESH_MOD_NEXT_IS_PARENT; - } - - mod->extends = base_mod; - return 0; -} -#endif -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/access.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/access.h deleted file mode 100644 index 6d2e31e88..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/access.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __ACCESS_H__ -#define __ACCESS_H__ - -#include "../include/mesh/mesh.h" - -/* bt_mesh_model.flags */ -enum { - BT_MESH_MOD_BIND_PENDING = BIT(0), - BT_MESH_MOD_SUB_PENDING = BIT(1), - BT_MESH_MOD_PUB_PENDING = BIT(2), - BT_MESH_MOD_NEXT_IS_PARENT = BIT(3), -}; - -/* Tree walk return codes */ -enum bt_mesh_walk { - BT_MESH_WALK_STOP, - BT_MESH_WALK_CONTINUE, -}; - -void bt_mesh_elem_register(struct bt_mesh_elem *elem, uint8_t count); - -uint8_t bt_mesh_elem_count(void); - -/* Find local element based on unicast or group address */ -struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr); - -struct bt_mesh_model *bt_mesh_model_root(struct bt_mesh_model *mod); -void bt_mesh_model_tree_walk(struct bt_mesh_model *root, - enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod, - uint32_t depth, - void *user_data), - void *user_data); - -uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr); - -void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, - struct bt_mesh_elem *elem, - bool vnd, bool primary, - void *user_data), - void *user_data); - -int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod); - -void bt_mesh_comp_provision(uint16_t addr); -void bt_mesh_comp_unprovision(void); - -uint16_t bt_mesh_primary_addr(void); - -const struct bt_mesh_comp *bt_mesh_comp_get(void); - -struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_idx); - -void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf); - -int bt_mesh_comp_register(const struct bt_mesh_comp *comp); -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/adv.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/adv.c deleted file mode 100644 index 95960ddb2..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/adv.c +++ /dev/null @@ -1,448 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2018 Nordic Semiconductor ASA - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_ADV_LOG - -#include "../include/mesh/mesh.h" -#include "nimble/nimble/host/include/host/ble_hs_adv.h" -#include "nimble/nimble/host/include/host/ble_gap.h" -#include "nimble/nimble/include/nimble/hci_common.h" -#include "../include/mesh/porting.h" -#include "nimble/porting/nimble/include/nimble/nimble_port.h" -#include "adv.h" -#include "net.h" -#include "foundation.h" -#include "beacon.h" -#include "prov.h" -#include "proxy.h" - -/* Convert from ms to 0.625ms units */ -#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) - -/* Window and Interval are equal for continuous scanning */ -#define MESH_SCAN_INTERVAL_MS 30 -#define MESH_SCAN_WINDOW_MS 30 -#define MESH_SCAN_INTERVAL ADV_SCAN_UNIT(MESH_SCAN_INTERVAL_MS) -#define MESH_SCAN_WINDOW ADV_SCAN_UNIT(MESH_SCAN_WINDOW_MS) - -/* Pre-5.0 controllers enforce a minimum interval of 100ms - * whereas 5.0+ controllers can go down to 20ms. - */ -#define ADV_INT_DEFAULT_MS 100 -#define ADV_INT_FAST_MS 20 - -static int32_t adv_int_min = ADV_INT_DEFAULT_MS; - -/* TinyCrypt PRNG consumes a lot of stack space, so we need to have - * an increased call stack whenever it's used. - */ -#if MYNEWT -OS_TASK_STACK_DEFINE(g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE)); -struct os_task adv_task; -#else -static TaskHandle_t adv_task_h; -#endif - -static struct ble_npl_eventq adv_queue; -extern uint8_t g_mesh_addr_type; -static int adv_initialized = false; - -static os_membuf_t adv_buf_mem[OS_MEMPOOL_SIZE( - MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT), - BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE)]; - -struct os_mbuf_pool adv_os_mbuf_pool; -static struct os_mempool adv_buf_mempool; - -static struct bt_mesh_adv adv_pool[CONFIG_BT_MESH_ADV_BUF_COUNT]; - -static struct bt_mesh_adv *adv_alloc(int id) -{ - return &adv_pool[id]; -} - -static inline void adv_send_start(uint16_t duration, int err, - const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->start) { - cb->start(duration, err, cb_data); - } -} - -static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->end) { - cb->end(err, cb_data); - } -} - -static inline void adv_send(struct os_mbuf *buf) -{ - static const uint8_t adv_type[] = { - [BT_MESH_ADV_PROV] = BLE_HS_ADV_TYPE_MESH_PROV, - [BT_MESH_ADV_DATA] = BLE_HS_ADV_TYPE_MESH_MESSAGE, - [BT_MESH_ADV_BEACON] = BLE_HS_ADV_TYPE_MESH_BEACON, - [BT_MESH_ADV_URI] = BLE_HS_ADV_TYPE_URI, -} ; - - const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb; - void *cb_data = BT_MESH_ADV(buf)->cb_data; - struct ble_gap_adv_params param = { 0 }; - uint16_t duration, adv_int; - struct bt_data ad; - int err; - - adv_int = max(adv_int_min, - BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit)); -#if MYNEWT_VAL(BLE_CONTROLLER) - duration = ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) * - (adv_int + 10)); -#else - duration = (MESH_SCAN_WINDOW_MS + - ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) * - (adv_int + 10))); -#endif - - BT_DBG("type %u om_len %u: %s", BT_MESH_ADV(buf)->type, - buf->om_len, bt_hex(buf->om_data, buf->om_len)); - BT_DBG("count %u interval %ums duration %ums", - BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int, - duration); - - ad.type = adv_type[BT_MESH_ADV(buf)->type]; - ad.data_len = buf->om_len; - ad.data = buf->om_data; - - param.itvl_min = ADV_SCAN_UNIT(adv_int); - param.itvl_max = param.itvl_min; - param.conn_mode = BLE_GAP_CONN_MODE_NON; - - err = bt_le_adv_start(¶m, &ad, 1, NULL, 0); - net_buf_unref(buf); - adv_send_start(duration, err, cb, cb_data); - if (err) { - BT_ERR("Advertising failed: err %d", err); - return; - } - - BT_DBG("Advertising started. Sleeping %u ms", duration); - - k_sleep(K_MSEC(duration)); - - err = bt_le_adv_stop(false); - adv_send_end(err, cb, cb_data); - if (err) { - BT_ERR("Stopping advertising failed: err %d", err); - return; - } - - BT_DBG("Advertising stopped"); -} - -void -mesh_adv_thread(void *args) -{ - static struct ble_npl_event *ev; - struct os_mbuf *buf; -#if (MYNEWT_VAL(BLE_MESH_PROXY)) - int32_t timeout; -#endif - - BT_DBG("started"); - - while (1) { -#if (MYNEWT_VAL(BLE_MESH_PROXY)) - ev = ble_npl_eventq_get(&adv_queue, 0); - while (!ev) { - timeout = bt_mesh_proxy_adv_start(); - BT_DBG("Proxy Advertising up to %d ms", (int) timeout); - - // FIXME: should we redefine K_SECONDS macro instead in glue? - if (timeout != K_FOREVER) { - timeout = ble_npl_time_ms_to_ticks32(timeout); - } - - ev = ble_npl_eventq_get(&adv_queue, timeout); - bt_mesh_proxy_adv_stop(); - } -#else - ev = ble_npl_eventq_get(&adv_queue, BLE_NPL_TIME_FOREVER); -#endif - - if (!ev || !ble_npl_event_get_arg(ev)) { - continue; - } - - buf = ble_npl_event_get_arg(ev); - - /* busy == 0 means this was canceled */ - if (BT_MESH_ADV(buf)->busy) { - BT_MESH_ADV(buf)->busy = 0; - adv_send(buf); - } else { - net_buf_unref(buf); - } - - /* os_sched(NULL); */ - } -} - -void bt_mesh_adv_update(void) -{ - static struct ble_npl_event ev = { }; - - BT_DBG(""); - - ble_npl_eventq_put(&adv_queue, &ev); -} - -struct os_mbuf *bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool, - bt_mesh_adv_alloc_t get_id, - enum bt_mesh_adv_type type, - uint8_t xmit, int32_t timeout) -{ - struct bt_mesh_adv *adv; - struct os_mbuf *buf; - - if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { - BT_WARN("Refusing to allocate buffer while suspended"); - return NULL; - } - - buf = os_mbuf_get_pkthdr(pool, BT_MESH_ADV_USER_DATA_SIZE); - if (!buf) { - return NULL; - } - - adv = get_id(net_buf_id(buf)); - BT_MESH_ADV(buf) = adv; - - memset(adv, 0, sizeof(*adv)); - - adv->type = type; - adv->xmit = xmit; - - adv->ref_cnt = 1; - ble_npl_event_set_arg(&adv->ev, buf); - - return buf; -} - -struct os_mbuf *bt_mesh_adv_create(enum bt_mesh_adv_type type, uint8_t xmit, - int32_t timeout) -{ - return bt_mesh_adv_create_from_pool(&adv_os_mbuf_pool, adv_alloc, type, - xmit, timeout); -} - -void bt_mesh_adv_send(struct os_mbuf *buf, const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - BT_DBG("buf %p, type 0x%02x len %u: %s", buf, BT_MESH_ADV(buf)->type, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - BT_MESH_ADV(buf)->cb = cb; - BT_MESH_ADV(buf)->cb_data = cb_data; - BT_MESH_ADV(buf)->busy = 1; - - net_buf_put(&adv_queue, net_buf_ref(buf)); -} - -static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi, - uint8_t adv_type, struct os_mbuf *buf) -{ - if (adv_type != BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) { - return; - } - -#if BT_MESH_EXTENDED_DEBUG - BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); -#endif - - while (buf->om_len > 1) { - struct net_buf_simple_state state; - uint8_t len, type; - - len = net_buf_simple_pull_u8(buf); - /* Check for early termination */ - if (len == 0) { - return; - } - - if (len > buf->om_len) { - BT_WARN("AD malformed"); - return; - } - - net_buf_simple_save(buf, &state); - - type = net_buf_simple_pull_u8(buf); - - switch (type) { - case BLE_HS_ADV_TYPE_MESH_MESSAGE: - bt_mesh_net_recv(buf, rssi, BT_MESH_NET_IF_ADV); - break; -#if MYNEWT_VAL(BLE_MESH_PB_ADV) - case BLE_HS_ADV_TYPE_MESH_PROV: - bt_mesh_pb_adv_recv(buf); - break; -#endif - case BLE_HS_ADV_TYPE_MESH_BEACON: - bt_mesh_beacon_recv(buf); - break; - default: - break; - } - - net_buf_simple_restore(buf, &state); - net_buf_simple_pull_mem(buf, len); - } -} - -void bt_mesh_adv_init(void) -{ - int rc; - - /* Advertising should only be initialized once. Calling - * os_task init the second time will result in an assert. */ - if (adv_initialized) { - return; - } - - rc = os_mempool_init(&adv_buf_mempool, MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT), - BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, - adv_buf_mem, "adv_buf_pool"); - assert(rc == 0); - - rc = os_mbuf_pool_init(&adv_os_mbuf_pool, &adv_buf_mempool, - BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, - MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT)); - assert(rc == 0); - - ble_npl_eventq_init(&adv_queue); - -#if MYNEWT - os_task_init(&adv_task, "mesh_adv", mesh_adv_thread, NULL, - MYNEWT_VAL(BLE_MESH_ADV_TASK_PRIO), OS_WAIT_FOREVER, - g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE)); -#elif ESP_PLATFORM - xTaskCreatePinnedToCore(mesh_adv_thread, "mesh_adv", 2768, - NULL, (configMAX_PRIORITIES - 5), &adv_task_h, NIMBLE_CORE); -#else - xTaskCreate(mesh_adv_thread, "mesh_adv", MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE), - NULL, MYNEWT_VAL(BLE_MESH_ADV_TASK_PRIO), &adv_task_h); -#endif - - /* For BT5 controllers we can have fast advertising interval */ - if (ble_hs_hci_get_hci_version() >= BLE_HCI_VER_BCS_5_0) { - adv_int_min = ADV_INT_FAST_MS; - } - - adv_initialized = true; -} - -int -ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg) -{ -#if MYNEWT_VAL(BLE_EXT_ADV) - struct ble_gap_ext_disc_desc *ext_desc; -#endif - struct ble_gap_disc_desc *desc; - struct os_mbuf *buf = NULL; - -#if BT_MESH_EXTENDED_DEBUG - BT_DBG("event->type %d", event->type); -#endif - - switch (event->type) { -#if MYNEWT_VAL(BLE_EXT_ADV) - case BLE_GAP_EVENT_EXT_DISC: - ext_desc = &event->ext_disc; - buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0); - if (!buf || os_mbuf_append(buf, ext_desc->data, ext_desc->length_data)) { - BT_ERR("Could not append data"); - goto done; - } - bt_mesh_scan_cb(&ext_desc->addr, ext_desc->rssi, - ext_desc->legacy_event_type, buf); - break; -#endif - case BLE_GAP_EVENT_DISC: - desc = &event->disc; - buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0); - if (!buf || os_mbuf_append(buf, desc->data, desc->length_data)) { - BT_ERR("Could not append data"); - goto done; - } - - bt_mesh_scan_cb(&desc->addr, desc->rssi, desc->event_type, buf); - break; - default: - break; - } - -done: - if (buf) { - os_mbuf_free_chain(buf); - } - - return 0; -} - -int bt_mesh_scan_enable(void) -{ - int err; - -#if MYNEWT_VAL(BLE_EXT_ADV) - struct ble_gap_ext_disc_params uncoded_params = - { .itvl = MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW, - .passive = 1 }; - - BT_DBG(""); - - err = ble_gap_ext_disc(g_mesh_addr_type, 0, 0, 0, 0, 0, - &uncoded_params, NULL, NULL, NULL); -#else - struct ble_gap_disc_params scan_param = - { .passive = 1, .filter_duplicates = 0, .itvl = - MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW }; - - BT_DBG(""); - - err = ble_gap_disc(g_mesh_addr_type, BLE_HS_FOREVER, &scan_param, - NULL, NULL); -#endif - if (err && err != BLE_HS_EALREADY) { - BT_ERR("starting scan failed (err %d)", err); - return err; - } - - return 0; -} - -int bt_mesh_scan_disable(void) -{ - int err; - - BT_DBG(""); - - err = ble_gap_disc_cancel(); - if (err && err != BLE_HS_EALREADY) { - BT_ERR("stopping scan failed (err %d)", err); - return err; - } - - return 0; -} -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/adv.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/adv.h deleted file mode 100644 index fe74438c3..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/adv.h +++ /dev/null @@ -1,74 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __ADV_H__ -#define __ADV_H__ - -/* Maximum advertising data payload for a single data type */ -#include "../include/mesh/mesh.h" - -#define BT_MESH_ADV(om) (*(struct bt_mesh_adv **) OS_MBUF_USRHDR(om)) - -#define BT_MESH_ADV_DATA_SIZE 31 - -/* The user data is a pointer (4 bytes) to struct bt_mesh_adv */ -#define BT_MESH_ADV_USER_DATA_SIZE (sizeof(struct bt_mesh_adv *)) - -#define BT_MESH_MBUF_HEADER_SIZE (sizeof(struct os_mbuf_pkthdr) + \ - BT_MESH_ADV_USER_DATA_SIZE +\ - sizeof(struct os_mbuf)) - -enum bt_mesh_adv_type -{ - BT_MESH_ADV_PROV, - BT_MESH_ADV_DATA, - BT_MESH_ADV_BEACON, - BT_MESH_ADV_URI, -}; - -typedef void (*bt_mesh_adv_func_t)(struct os_mbuf *buf, uint16_t duration, - int err, void *user_data); - -struct bt_mesh_adv { - const struct bt_mesh_send_cb *cb; - void *cb_data; - - uint8_t type:2, - busy:1; - uint8_t xmit; - - uint8_t flags; - - int ref_cnt; - struct ble_npl_event ev; -}; - -typedef struct bt_mesh_adv *(*bt_mesh_adv_alloc_t)(int id); - -/* xmit_count: Number of retransmissions, i.e. 0 == 1 transmission */ -struct os_mbuf *bt_mesh_adv_create(enum bt_mesh_adv_type type, uint8_t xmit, - int32_t timeout); - -struct os_mbuf *bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool, - bt_mesh_adv_alloc_t get_id, - enum bt_mesh_adv_type type, - uint8_t xmit, int32_t timeout); - -void bt_mesh_adv_send(struct os_mbuf *buf, const struct bt_mesh_send_cb *cb, - void *cb_data); - -void bt_mesh_adv_update(void); - -void bt_mesh_adv_init(void); - -int bt_mesh_scan_enable(void); - -int bt_mesh_scan_disable(void); - -int ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg); -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/aes-ccm.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/aes-ccm.c deleted file mode 100644 index 2bc7e1ac7..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/aes-ccm.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#include "crypto.h" -#define MESH_LOG_MODULE BLE_MESH_LOG - -static inline void xor16(uint8_t *dst, const uint8_t *a, const uint8_t *b) -{ - dst[0] = a[0] ^ b[0]; - dst[1] = a[1] ^ b[1]; - dst[2] = a[2] ^ b[2]; - dst[3] = a[3] ^ b[3]; - dst[4] = a[4] ^ b[4]; - dst[5] = a[5] ^ b[5]; - dst[6] = a[6] ^ b[6]; - dst[7] = a[7] ^ b[7]; - dst[8] = a[8] ^ b[8]; - dst[9] = a[9] ^ b[9]; - dst[10] = a[10] ^ b[10]; - dst[11] = a[11] ^ b[11]; - dst[12] = a[12] ^ b[12]; - dst[13] = a[13] ^ b[13]; - dst[14] = a[14] ^ b[14]; - dst[15] = a[15] ^ b[15]; -} - -/* pmsg is assumed to have the nonce already present in bytes 1-13 */ -static int ccm_calculate_X0(const uint8_t key[16], const uint8_t *aad, uint8_t aad_len, - size_t mic_size, uint8_t msg_len, uint8_t b[16], - uint8_t X0[16]) -{ - int i, j, err; - - /* X_0 = e(AppKey, flags || nonce || length) */ - b[0] = (((mic_size - 2) / 2) << 3) | ((!!aad_len) << 6) | 0x01; - - sys_put_be16(msg_len, b + 14); - - err = bt_encrypt_be(key, b, X0); - if (err) { - return err; - } - - /* If AAD is being used to authenticate, include it here */ - if (aad_len) { - sys_put_be16(aad_len, b); - - for (i = 0; i < sizeof(uint16_t); i++) { - b[i] = X0[i] ^ b[i]; - } - - j = 0; - aad_len += sizeof(uint16_t); - while (aad_len > 16) { - do { - b[i] = X0[i] ^ aad[j]; - i++, j++; - } while (i < 16); - - aad_len -= 16; - i = 0; - - err = bt_encrypt_be(key, b, X0); - if (err) { - return err; - } - } - - for (; i < aad_len; i++, j++) { - b[i] = X0[i] ^ aad[j]; - } - - for (i = aad_len; i < 16; i++) { - b[i] = X0[i]; - } - - err = bt_encrypt_be(key, b, X0); - if (err) { - return err; - } - } - - return 0; -} - -static int ccm_auth(const uint8_t key[16], uint8_t nonce[13], - const uint8_t *cleartext_msg, size_t msg_len, const uint8_t *aad, - size_t aad_len, uint8_t *mic, size_t mic_size) -{ - uint8_t b[16], Xn[16], s0[16]; - uint16_t blk_cnt, last_blk; - int err, j, i; - - last_blk = msg_len % 16; - blk_cnt = (msg_len + 15) / 16; - if (!last_blk) { - last_blk = 16U; - } - - b[0] = 0x01; - memcpy(b + 1, nonce, 13); - - /* S[0] = e(AppKey, 0x01 || nonce || 0x0000) */ - sys_put_be16(0x0000, &b[14]); - - err = bt_encrypt_be(key, b, s0); - if (err) { - return err; - } - - ccm_calculate_X0(key, aad, aad_len, mic_size, msg_len, b, Xn); - - for (j = 0; j < blk_cnt; j++) { - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - if (j + 1 == blk_cnt) { - for (i = 0; i < last_blk; i++) { - b[i] = Xn[i] ^ cleartext_msg[(j * 16) + i]; - } - - memcpy(&b[i], &Xn[i], 16 - i); - } else { - xor16(b, Xn, &cleartext_msg[j * 16]); - } - - err = bt_encrypt_be(key, b, Xn); - if (err) { - return err; - } - } - - /* MIC = C_mic ^ X_1 */ - for (i = 0; i < mic_size; i++) { - mic[i] = s0[i] ^ Xn[i]; - } - - return 0; -} - -static int ccm_crypt(const uint8_t key[16], const uint8_t nonce[13], - const uint8_t *in_msg, uint8_t *out_msg, size_t msg_len) -{ - uint8_t a_i[16], s_i[16]; - uint16_t last_blk, blk_cnt; - size_t i, j; - int err; - - last_blk = msg_len % 16; - blk_cnt = (msg_len + 15) / 16; - if (!last_blk) { - last_blk = 16U; - } - - a_i[0] = 0x01; - memcpy(&a_i[1], nonce, 13); - - for (j = 0; j < blk_cnt; j++) { - /* S_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - sys_put_be16(j + 1, &a_i[14]); - - err = bt_encrypt_be(key, a_i, s_i); - if (err) { - return err; - } - - /* Encrypted = Payload[0-15] ^ C_1 */ - if (j < blk_cnt - 1) { - xor16(&out_msg[j * 16], s_i, &in_msg[j * 16]); - } else { - for (i = 0; i < last_blk; i++) { - out_msg[(j * 16) + i] = - in_msg[(j * 16) + i] ^ s_i[i]; - } - } - } - return 0; -} - -int bt_ccm_decrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t *enc_msg, - size_t msg_len, const uint8_t *aad, size_t aad_len, - uint8_t *out_msg, size_t mic_size) -{ - uint8_t mic[16]; - - if (aad_len >= 0xff00 || mic_size > sizeof(mic)) { - return -EINVAL; - } - - ccm_crypt(key, nonce, enc_msg, out_msg, msg_len); - - ccm_auth(key, nonce, out_msg, msg_len, aad, aad_len, mic, mic_size); - - if (memcmp(mic, enc_msg + msg_len, mic_size)) { - return -EBADMSG; - } - - return 0; -} - -int bt_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t *msg, - size_t msg_len, const uint8_t *aad, size_t aad_len, - uint8_t *out_msg, size_t mic_size) -{ - uint8_t *mic = out_msg + msg_len; - - BT_DBG("key %s", bt_hex(key, 16)); - BT_DBG("nonce %s", bt_hex(nonce, 13)); - BT_DBG("msg (len %zu) %s", msg_len, bt_hex(msg, msg_len)); - BT_DBG("aad_len %zu mic_size %zu", aad_len, mic_size); - - /* Unsupported AAD size */ - if (aad_len >= 0xff00 || mic_size > 16) { - return -EINVAL; - } - - ccm_auth(key, nonce, out_msg, msg_len, aad, aad_len, mic, mic_size); - - ccm_crypt(key, nonce, msg, out_msg, msg_len); - - return 0; -} - -#endif /* MYNEWT_VAL(BLE_MESH) */ \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/app_keys.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/app_keys.c deleted file mode 100644 index e64b9be98..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/app_keys.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#include -#include -#include "../include/mesh/mesh.h" -#include "mesh_priv.h" -#include "net.h" -#include "app_keys.h" -#include "rpl.h" -#include "settings.h" -#include "crypto.h" -#include "adv.h" -#include "proxy.h" -#include "friend.h" -#include "foundation.h" -#include "access.h" -#include "subnet.h" - -#define MESH_LOG_MODULE BLE_MESH_LOG -#include "nimble/porting/nimble/include/log/log.h" - -static struct bt_mesh_app_key apps[CONFIG_BT_MESH_APP_KEY_COUNT] = { - [0 ... (CONFIG_BT_MESH_APP_KEY_COUNT - 1)] = { - .app_idx = BT_MESH_KEY_UNUSED, - .net_idx = BT_MESH_KEY_UNUSED, - } -}; - -static void app_key_evt(struct bt_mesh_app_key *app, enum bt_mesh_key_evt evt) -{ - int i; - - for (i = 0; i < (sizeof(bt_mesh_app_key_cb_list)/sizeof(void *)); i++) { - if (bt_mesh_app_key_cb_list[i]) { - BT_DBG("app_key_evt %d", i); - bt_mesh_app_key_cb_list[i] (app->app_idx, app->net_idx, evt); - } - } -} - -struct bt_mesh_app_key *app_get(uint16_t app_idx) -{ - for (int i = 0; i < ARRAY_SIZE(apps); i++) { - if (apps[i].app_idx == app_idx) { - return &apps[i]; - } - } - - return NULL; -} - -static struct bt_mesh_app_key *app_key_alloc(uint16_t app_idx) -{ - struct bt_mesh_app_key *app = NULL; - - for (int i = 0; i < ARRAY_SIZE(apps); i++) { - /* Check for already existing app_key */ - if (apps[i].app_idx == app_idx) { - return &apps[i]; - } - - if (!app && apps[i].app_idx == BT_MESH_KEY_UNUSED) { - app = &apps[i]; - } - } - - return app; -} - -static void app_key_del(struct bt_mesh_app_key *app) -{ - BT_DBG("AppIdx 0x%03x", app->app_idx); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_clear_app_key(app->app_idx); - } - - app_key_evt(app, BT_MESH_KEY_DELETED); - - app->net_idx = BT_MESH_KEY_UNUSED; - app->app_idx = BT_MESH_KEY_UNUSED; - (void)memset(app->keys, 0, sizeof(app->keys)); -} - -static void app_key_revoke(struct bt_mesh_app_key *app) -{ - if (!app->updated) { - return; - } - - memcpy(&app->keys[0], &app->keys[1], sizeof(app->keys[0])); - memset(&app->keys[1], 0, sizeof(app->keys[1])); - app->updated = false; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_app_key(app->app_idx); - } - - app_key_evt(app, BT_MESH_KEY_REVOKED); -} - - -static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) -{ - if (evt == BT_MESH_KEY_UPDATED || evt == BT_MESH_KEY_ADDED) { - return; - } - - for (int i = 0; i < ARRAY_SIZE(apps); i++) { - struct bt_mesh_app_key *app = &apps[i]; - - if (app->app_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - if (app->net_idx != sub->net_idx) { - continue; - } - - if (evt == BT_MESH_KEY_DELETED) { - app_key_del(app); - } else if (evt == BT_MESH_KEY_REVOKED) { - app_key_revoke(app); - } else if (evt == BT_MESH_KEY_SWAPPED && app->updated) { - app_key_evt(app, BT_MESH_KEY_SWAPPED); - } - } -} - - -uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, - const uint8_t key[16]) -{ - if (!bt_mesh_subnet_cb_list[0]) { - bt_mesh_subnet_cb_list[0] = subnet_evt; - } - - struct bt_mesh_app_key *app; - - BT_DBG("net_idx 0x%04x app_idx %04x val %s", net_idx, app_idx, - bt_hex(key, 16)); - - if (!bt_mesh_subnet_get(net_idx)) { - return STATUS_INVALID_NETKEY; - } - - app = app_key_alloc(app_idx); - if (!app) { - return STATUS_INSUFF_RESOURCES; - } - - if (app->app_idx == app_idx) { - if (app->net_idx != net_idx) { - return STATUS_INVALID_BINDING; - } - - if (memcmp(key, app->keys[0].val, 16)) { - return STATUS_IDX_ALREADY_STORED; - } - - return STATUS_SUCCESS; - } - - if (bt_mesh_app_id(key, &app->keys[0].id)) { - return STATUS_CANNOT_SET; - } - - BT_DBG("AppIdx 0x%04x AID 0x%02x", app_idx, app->keys[0].id); - - app->net_idx = net_idx; - app->app_idx = app_idx; - app->updated = false; - memcpy(app->keys[0].val, key, 16); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - BT_DBG("Storing AppKey persistently"); - bt_mesh_store_app_key(app->app_idx); - } - - app_key_evt(app, BT_MESH_KEY_ADDED); - - return STATUS_SUCCESS; -} - -struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx) -{ - struct bt_mesh_app_key *app; - - app = app_get(app_idx); - if (app) { - return app; - } - - return NULL; -} - -uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx, - const uint8_t key[16]) -{ - struct bt_mesh_app_key *app; - struct bt_mesh_subnet *sub; - - BT_DBG("net_idx 0x%04x app_idx %04x val %s", net_idx, app_idx, - bt_hex(key, 16)); - - app = app_get(app_idx); - if (!app) { - return STATUS_INVALID_APPKEY; - } - - if (net_idx != BT_MESH_KEY_UNUSED && app->net_idx != net_idx) { - return STATUS_INVALID_BINDING; - } - - sub = bt_mesh_subnet_get(app->net_idx); - if (!sub) { - return STATUS_INVALID_NETKEY; - } - - /* The AppKey Update message shall generate an error when node - * is in normal operation, Phase 2, or Phase 3 or in Phase 1 - * when the AppKey Update message on a valid AppKeyIndex when - * the AppKey value is different. - */ - if (sub->kr_phase != BT_MESH_KR_PHASE_1) { - return STATUS_CANNOT_UPDATE; - } - - if (app->updated) { - if (memcmp(app->keys[1].val, key, 16)) { - return STATUS_IDX_ALREADY_STORED; - } - - return STATUS_SUCCESS; - } - - if (bt_mesh_app_id(key, &app->keys[1].id)) { - return STATUS_CANNOT_UPDATE; - } - - BT_DBG("app_idx 0x%04x AID 0x%02x", app_idx, app->keys[1].id); - - app->updated = true; - memcpy(app->keys[1].val, key, 16); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - BT_DBG("Storing AppKey persistently"); - bt_mesh_store_app_key(app->app_idx); - } - - app_key_evt(app, BT_MESH_KEY_UPDATED); - - return STATUS_SUCCESS; -} - -uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx) -{ - struct bt_mesh_app_key *app; - - BT_DBG("AppIdx 0x%03x", app_idx); - - if (net_idx != BT_MESH_KEY_UNUSED && !bt_mesh_subnet_get(net_idx)) { - return STATUS_INVALID_NETKEY; - } - - app = app_get(app_idx); - if (!app) { - /* This could be a retry of a previous attempt that had its - * response lost, so pretend that it was a success. - */ - return STATUS_SUCCESS; - } - - if (net_idx != BT_MESH_KEY_UNUSED && net_idx != app->net_idx) { - return STATUS_INVALID_BINDING; - } - - app_key_del(app); - - return STATUS_SUCCESS; -} - -int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx, - const uint8_t old_key[16], const uint8_t new_key[16]) -{ - struct bt_mesh_app_key *app; - - app = app_key_alloc(app_idx); - if (!app) { - return -ENOMEM; - } - - if (app->app_idx == app_idx) { - return 0; - } - - BT_DBG("AppIdx 0x%04x AID 0x%02x", app_idx, app->keys[0].id); - - memcpy(app->keys[0].val, old_key, 16); - if (bt_mesh_app_id(old_key, &app->keys[0].id)) { - return -EIO; - } - - if (new_key) { - memcpy(app->keys[1].val, new_key, 16); - if (bt_mesh_app_id(new_key, &app->keys[1].id)) { - return -EIO; - } - } - - app->net_idx = net_idx; - app->app_idx = app_idx; - app->updated = !!new_key; - - return 0; -} - -bool bt_mesh_app_key_exists(uint16_t app_idx) -{ - for (int i = 0; i < ARRAY_SIZE(apps); i++) { - if (apps[i].app_idx == app_idx) { - return true; - } - } - - return false; -} - -ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max, - off_t skip) -{ - size_t count = 0; - - for (int i = 0; i < ARRAY_SIZE(apps); i++) { - struct bt_mesh_app_key *app = &apps[i]; - - if (app->app_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - if (net_idx != BT_MESH_KEY_ANY && app->net_idx != net_idx) { - continue; - } - - if (skip) { - skip--; - continue; - } - - if (count >= max) { - return -ENOMEM; - } - - app_idxs[count++] = app->app_idx; - } - - return count; -} - -int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, - struct bt_mesh_subnet **sub, - const uint8_t **app_key, uint8_t *aid) -{ - struct bt_mesh_app_key *app = NULL; - - if (BT_MESH_IS_DEV_KEY(ctx->app_idx)) { - /* With device keys, the application has to decide which subnet - * to send on. - */ - *sub = bt_mesh_subnet_get(ctx->net_idx); - if (!*sub) { - BT_WARN("Unknown NetKey 0x%03x", ctx->net_idx); - return -EINVAL; - } - - if (ctx->app_idx == BT_MESH_KEY_DEV_REMOTE && - !bt_mesh_elem_find(ctx->addr)) { - struct bt_mesh_cdb_node *node; - - if (!IS_ENABLED(CONFIG_BT_MESH_CDB)) { - BT_WARN("No DevKey for 0x%04x", ctx->addr); - return -EINVAL; - } - - node = bt_mesh_cdb_node_get(ctx->addr); - if (!node) { - BT_WARN("No DevKey for 0x%04x", ctx->addr); - return -EINVAL; - } - - *app_key = node->dev_key; - } else { - *app_key = bt_mesh.dev_key; - } - - *aid = 0; - return 0; - } - - app = app_get(ctx->app_idx); - if (!app) { - BT_WARN("Unknown AppKey 0x%03x", ctx->app_idx); - return -EINVAL; - } - - *sub = bt_mesh_subnet_get(app->net_idx); - if (!*sub) { - BT_WARN("Unknown NetKey 0x%03x", app->net_idx); - return -EINVAL; - } - - if ((*sub)->kr_phase == BT_MESH_KR_PHASE_2 && app->updated) { - *aid = app->keys[1].id; - *app_key = app->keys[1].val; - } else { - *aid = app->keys[0].id; - *app_key = app->keys[0].val; - } - - return 0; -} - -uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, - struct bt_mesh_net_rx *rx, - int (*cb)(struct bt_mesh_net_rx *rx, - const uint8_t key[16], void *cb_data), - void *cb_data) -{ - int err, i; - - if (dev_key) { - /* Attempt remote dev key first, as that is only available for - * provisioner devices, which normally don't interact with nodes - * that know their local dev key. - */ - if (IS_ENABLED(CONFIG_BT_MESH_CDB) && - rx->net_if != BT_MESH_NET_IF_LOCAL) { - struct bt_mesh_cdb_node *node; - - node = bt_mesh_cdb_node_get(rx->ctx.addr); - if (node && !cb(rx, node->dev_key, cb_data)) { - return BT_MESH_KEY_DEV_REMOTE; - } - } - - /** Bluetooth Mesh Specification v1.0.1, section 3.4.3: - * The Device key is only valid for unicast addresses. - */ - if (BT_MESH_ADDR_IS_UNICAST(rx->ctx.recv_dst)) { - err = cb(rx, bt_mesh.dev_key, cb_data); - if (!err) { - return BT_MESH_KEY_DEV_LOCAL; - } - } - - return BT_MESH_KEY_UNUSED; - } - - for (i = 0; i < ARRAY_SIZE(apps); i++) { - const struct bt_mesh_app_key *app = &apps[i]; - const struct bt_mesh_app_cred *cred; - - if (app->app_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - if (app->net_idx != rx->sub->net_idx) { - continue; - } - - if (rx->new_key && app->updated) { - cred = &app->keys[1]; - } else { - cred = &app->keys[0]; - } - - if (cred->id != aid) { - continue; - } - - err = cb(rx, cred->val, cb_data); - if (err) { - continue; - } - - return app->app_idx; - } - - return BT_MESH_KEY_UNUSED; -} - - -void bt_mesh_app_keys_reset(void) -{ - for (int i = 0; i < ARRAY_SIZE(apps); i++) { - struct bt_mesh_app_key *app = &apps[i]; - - if (app->app_idx != BT_MESH_KEY_UNUSED) { - app_key_del(app); - } - } -} - -#endif /* MYNEWT_VAL(BLE_MESH) */ \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/app_keys.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/app_keys.h deleted file mode 100644 index 2a4e51f53..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/app_keys.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _BT_MESH_APP_KEYS_H_ -#define _BT_MESH_APP_KEYS_H_ - -#include "../include/mesh/mesh.h" -#include "subnet.h" - -/** Mesh Application. */ -struct bt_mesh_app_key { - uint16_t net_idx; - uint16_t app_idx; - bool updated; - struct bt_mesh_app_cred { - uint8_t id; - uint8_t val[16]; - } keys[2]; -}; - -/** @brief Reset the app keys module. */ -void bt_mesh_app_keys_reset(void); - -/** @brief Get the application key with the given AppIdx. - * - * @param app_idx App index. - * - * @return The matching application, or NULL if the application isn't known. - */ -struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx); - -/** @brief Initialize a new application key with the given parameters. - * - * @param app_idx AppIndex. - * @param net_idx NetIndex the application is bound to. - * @param old_key Current application key. - * @param new_key Updated application key, or NULL if not known. - * - * @return 0 on success, or (negative) error code on failure. - */ -int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx, - const uint8_t old_key[16], const uint8_t new_key[16]); - -/** @brief Resolve the message encryption keys, given a message context. - * - * Will use the @c ctx::app_idx and @c ctx::net_idx fields to find a pair of - * message encryption keys. If @c ctx::app_idx represents a device key, the - * @c ctx::net_idx will be used to determine the net key. Otherwise, the - * @c ctx::net_idx parameter will be ignored. - * - * @param ctx Message context. - * @param sub Subnet return parameter. - * @param app_key Application return parameter. - * @param aid Application ID return parameter. - * - * @return 0 on success, or (negative) error code on failure. - */ -int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, - struct bt_mesh_subnet **sub, - const uint8_t **app_key, uint8_t *aid); - -/** @brief Iterate through all matching application keys and call @c cb on each. - * - * @param dev_key Whether to return device keys. - * @param aid 7 bit application ID to match. - * @param rx RX structure to match against. - * @param cb Callback to call for every valid app key. - * @param cb_data Callback data to pass to the callback. - * - * @return The AppIdx that yielded a 0-return from the callback. - */ -uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, - struct bt_mesh_net_rx *rx, - int (*cb)(struct bt_mesh_net_rx *rx, - const uint8_t key[16], void *cb_data), - void *cb_data); - -struct bt_mesh_app_key *app_get(uint16_t app_idx); - -extern void (*bt_mesh_app_key_cb_list[1]) (uint16_t app_idx, uint16_t net_idx, - enum bt_mesh_key_evt evt); - -#endif /* _BT_MESH_APP_KEYS_H_ */ \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/atomic.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/atomic.h deleted file mode 100644 index 2c7317948..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/atomic.h +++ /dev/null @@ -1,409 +0,0 @@ -/* atomic operations */ - -/* - * Copyright (c) 1997-2015, Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __ATOMIC_H__ -#define __ATOMIC_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef int atomic_t; -typedef atomic_t atomic_val_t; - -/** - * @defgroup atomic_apis Atomic Services APIs - * @ingroup kernel_apis - * @{ - */ - -/** - * @brief Atomic compare-and-set. - * - * This routine performs an atomic compare-and-set on @a target. If the current - * value of @a target equals @a old_value, @a target is set to @a new_value. - * If the current value of @a target does not equal @a old_value, @a target - * is left unchanged. - * - * @param target Address of atomic variable. - * @param old_value Original value to compare against. - * @param new_value New value to store. - * @return 1 if @a new_value is written, 0 otherwise. - */ -static inline int atomic_cas(atomic_t *target, atomic_val_t old_value, - atomic_val_t new_value) -{ - return __atomic_compare_exchange_n(target, &old_value, new_value, - 0, __ATOMIC_SEQ_CST, - __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic addition. - * - * This routine performs an atomic addition on @a target. - * - * @param target Address of atomic variable. - * @param value Value to add. - * - * @return Previous value of @a target. - */ -static inline atomic_val_t atomic_add(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_add(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic subtraction. - * - * This routine performs an atomic subtraction on @a target. - * - * @param target Address of atomic variable. - * @param value Value to subtract. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic increment. - * - * This routine performs an atomic increment by 1 on @a target. - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_inc(atomic_t *target) -{ - return atomic_add(target, 1); -} - -/** - * - * @brief Atomic decrement. - * - * This routine performs an atomic decrement by 1 on @a target. - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_dec(atomic_t *target) -{ - return atomic_sub(target, 1); -} - -/** - * - * @brief Atomic get. - * - * This routine performs an atomic read on @a target. - * - * @param target Address of atomic variable. - * - * @return Value of @a target. - */ - -static inline atomic_val_t atomic_get(const atomic_t *target) -{ - return __atomic_load_n(target, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic get-and-set. - * - * This routine atomically sets @a target to @a value and returns - * the previous value of @a target. - * - * @param target Address of atomic variable. - * @param value Value to write to @a target. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value) -{ - /* This builtin, as described by Intel, is not a traditional - * test-and-set operation, but rather an atomic exchange operation. It - * writes value into *ptr, and returns the previous contents of *ptr. - */ - return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic clear. - * - * This routine atomically sets @a target to zero and returns its previous - * value. (Hence, it is equivalent to atomic_set(target, 0).) - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_clear(atomic_t *target) -{ - return atomic_set(target, 0); -} - -/** - * - * @brief Atomic bitwise inclusive OR. - * - * This routine atomically sets @a target to the bitwise inclusive OR of - * @a target and @a value. - * - * @param target Address of atomic variable. - * @param value Value to OR. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic bitwise exclusive OR (XOR). - * - * This routine atomically sets @a target to the bitwise exclusive OR (XOR) of - * @a target and @a value. - * - * @param target Address of atomic variable. - * @param value Value to XOR - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_xor(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic bitwise AND. - * - * This routine atomically sets @a target to the bitwise AND of @a target - * and @a value. - * - * @param target Address of atomic variable. - * @param value Value to AND. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic bitwise NAND. - * - * This routine atomically sets @a target to the bitwise NAND of @a target - * and @a value. (This operation is equivalent to target = ~(target & value).) - * - * @param target Address of atomic variable. - * @param value Value to NAND. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_nand(target, value, __ATOMIC_SEQ_CST); -} - - /** - * @brief Initialize an atomic variable. - * - * This macro can be used to initialize an atomic variable. For example, - * @code atomic_t my_var = ATOMIC_INIT(75); @endcode - * - * @param i Value to assign to atomic variable. - */ -#define ATOMIC_INIT(i) (i) - - /** - * @cond INTERNAL_HIDDEN - */ - -#define ATOMIC_BITS (sizeof(atomic_val_t) * 8) -#define ATOMIC_MASK(bit) (1 << ((bit) & (ATOMIC_BITS - 1))) -#define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS)) - - /** - * INTERNAL_HIDDEN @endcond - */ - - /** - * @brief Define an array of atomic variables. - * - * This macro defines an array of atomic variables containing at least - * @a num_bits bits. - * - * @note - * If used from file scope, the bits of the array are initialized to zero; - * if used from within a function, the bits are left uninitialized. - * - * @param name Name of array of atomic variables. - * @param num_bits Number of bits needed. - */ -#define ATOMIC_DEFINE(name, num_bits) \ - atomic_t name[1 + ((num_bits) - 1) / ATOMIC_BITS] - - /** - * @brief Atomically test a bit. - * - * This routine tests whether bit number @a bit of @a target is set or not. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return 1 if the bit was set, 0 if it wasn't. - */ - static inline int - atomic_test_bit(const atomic_t *target, int bit) - { - atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit)); - - return (1 & (val >> (bit & (ATOMIC_BITS - 1)))); - } - - /** - * @brief Atomically test and clear a bit. - * - * Atomically clear bit number @a bit of @a target and return its old value. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return 1 if the bit was set, 0 if it wasn't. - */ - static inline int - atomic_test_and_clear_bit(atomic_t *target, int bit) - { - atomic_val_t mask = ATOMIC_MASK(bit); - atomic_val_t old; - - old = atomic_and(ATOMIC_ELEM(target, bit), ~mask); - - return (old & mask) != 0; - } - - /** - * @brief Atomically set a bit. - * - * Atomically set bit number @a bit of @a target and return its old value. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return 1 if the bit was set, 0 if it wasn't. - */ - static inline int - atomic_test_and_set_bit(atomic_t *target, int bit) - { - atomic_val_t mask = ATOMIC_MASK(bit); - atomic_val_t old; - - old = atomic_or(ATOMIC_ELEM(target, bit), mask); - - return (old & mask) != 0; - } - - /** - * @brief Atomically clear a bit. - * - * Atomically clear bit number @a bit of @a target. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return N/A - */ - static inline void - atomic_clear_bit(atomic_t *target, int bit) - { - atomic_val_t mask = ATOMIC_MASK(bit); - - atomic_and(ATOMIC_ELEM(target, bit), ~mask); - } - - /** - * @brief Atomically set a bit. - * - * Atomically set bit number @a bit of @a target. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return N/A - */ - static inline void - atomic_set_bit(atomic_t *target, int bit) - { - atomic_val_t mask = ATOMIC_MASK(bit); - - atomic_or(ATOMIC_ELEM(target, bit), mask); - } - -/** -* @brief Atomically set a bit to a given value. -* -* Atomically set bit number @a bit of @a target to value @a val. -* The target may be a single atomic variable or an array of them. -* -* @param target Address of atomic variable or array. -* @param bit Bit number (starting from 0). -* @param val true for 1, false for 0. -* -* @return N/A -*/ -static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val) -{ - atomic_val_t mask = ATOMIC_MASK(bit); - - if (val) { - (void)atomic_or(ATOMIC_ELEM(target, bit), mask); - } else { - (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask); - } -} - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ATOMIC_H__ */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/beacon.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/beacon.c deleted file mode 100644 index b7115c606..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/beacon.c +++ /dev/null @@ -1,475 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_BEACON_LOG - -#include -#include -#include "nimble/porting/nimble/include/os/os_mbuf.h" -#include "../include/mesh/mesh.h" - -#include "adv.h" -#include "mesh_priv.h" -#include "net.h" -#include "prov.h" -#include "crypto.h" -#include "beacon.h" -#include "foundation.h" -#include "atomic.h" - -#define PROVISIONED_INTERVAL (K_SECONDS(10)) - -#define BEACON_TYPE_UNPROVISIONED 0x00 -#define BEACON_TYPE_SECURE 0x01 - -/* 3 transmissions, 20ms interval */ -#define UNPROV_XMIT BT_MESH_TRANSMIT(2, 20) - -/* 1 transmission, 20ms interval */ -#define PROV_XMIT BT_MESH_TRANSMIT(0, 20) - -static struct k_delayed_work beacon_timer; - -static int cache_check(struct bt_mesh_subnet *sub, void *beacon_data) -{ - return !memcmp(sub->beacon_cache, beacon_data, 21); -} - -static void cache_add(uint8_t data[21], struct bt_mesh_subnet *sub) -{ - memcpy(sub->beacon_cache, data, 21); -} - -static void beacon_complete(int err, void *user_data) -{ - struct bt_mesh_subnet *sub = user_data; - - BT_DBG("err %d", err); - - sub->beacon_sent = k_uptime_get_32(); -} - -void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, - struct os_mbuf *buf) -{ - uint8_t flags = bt_mesh_net_flags(sub); - struct bt_mesh_subnet_keys *keys; - - net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE); - - keys = &sub->keys[SUBNET_KEY_TX_IDX(sub)]; - - net_buf_simple_add_u8(buf, flags); - - /* Network ID */ - net_buf_simple_add_mem(buf, keys->net_id, 8); - - /* IV Index */ - net_buf_simple_add_be32(buf, bt_mesh.iv_index); - - net_buf_simple_add_mem(buf, sub->auth, 8); - - BT_DBG("net_idx 0x%04x flags 0x%02x NetID %s", sub->net_idx, - flags, bt_hex(keys->net_id, 8)); - BT_DBG("IV Index 0x%08x Auth %s", (unsigned) bt_mesh.iv_index, - bt_hex(sub->auth, 8)); -} - -/* If the interval has passed or is within 5 seconds from now send a beacon */ -#define BEACON_THRESHOLD(sub) (K_SECONDS(10 * ((sub)->beacons_last + 1)) - \ - K_SECONDS(5)) - -static int secure_beacon_send(struct bt_mesh_subnet *sub, void *cb_data) -{ - static const struct bt_mesh_send_cb send_cb = { - .end = beacon_complete, - }; - uint32_t now = k_uptime_get_32(); - struct os_mbuf *buf; - uint32_t time_diff; - - BT_DBG(""); - - time_diff = now - sub->beacon_sent; - if (time_diff < (600 * MSEC_PER_SEC) && - time_diff < BEACON_THRESHOLD(sub)) { - return 0; - } - - buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, PROV_XMIT, K_NO_WAIT); - if (!buf) { - BT_ERR("Unable to allocate beacon buffer"); - return -ENOMEM; - } - - bt_mesh_beacon_create(sub, buf); - - bt_mesh_adv_send(buf, &send_cb, sub); - net_buf_unref(buf); - - return 0; -} - -static int unprovisioned_beacon_send(void) -{ - const struct bt_mesh_prov *prov; - uint8_t uri_hash[16] = { 0 }; - struct os_mbuf *buf; - uint16_t oob_info; - - BT_DBG("unprovisioned_beacon_send"); - - buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, UNPROV_XMIT, K_NO_WAIT); - if (!buf) { - BT_ERR("Unable to allocate beacon buffer"); - return -ENOBUFS; - } - - prov = bt_mesh_prov_get(); - - net_buf_add_u8(buf, BEACON_TYPE_UNPROVISIONED); - net_buf_add_mem(buf, prov->uuid, 16); - - if (prov->uri && bt_mesh_s1(prov->uri, uri_hash) == 0) { - oob_info = prov->oob_info | BT_MESH_PROV_OOB_URI; - } else { - oob_info = prov->oob_info; - } - - net_buf_add_be16(buf, oob_info); - net_buf_add_mem(buf, uri_hash, 4); - - bt_mesh_adv_send(buf, NULL, NULL); - net_buf_unref(buf); - - if (prov->uri) { - size_t len; - - buf = bt_mesh_adv_create(BT_MESH_ADV_URI, UNPROV_XMIT, - K_NO_WAIT); - if (!buf) { - BT_ERR("Unable to allocate URI buffer"); - return -ENOBUFS; - } - - len = strlen(prov->uri); - if (net_buf_tailroom(buf) < len) { - BT_WARN("Too long URI to fit advertising data"); - } else { - net_buf_add_mem(buf, prov->uri, len); - bt_mesh_adv_send(buf, NULL, NULL); - } - - net_buf_unref(buf); - } - - return 0; -} - -static void unprovisioned_beacon_recv(struct os_mbuf *buf) -{ - const struct bt_mesh_prov *prov; - uint8_t *uuid; - uint16_t oob_info; - uint32_t uri_hash_val; - uint32_t *uri_hash = NULL; - - if (buf->om_len != 18 && buf->om_len != 22) { - BT_ERR("Invalid unprovisioned beacon length (%u)", buf->om_len); - return; - } - - uuid = net_buf_simple_pull_mem(buf, 16); - oob_info = net_buf_simple_pull_be16(buf); - - if (buf->om_len == 4) { - uri_hash_val = net_buf_simple_pull_be32(buf); - uri_hash = &uri_hash_val; - } - - BT_DBG("uuid %s", bt_hex(uuid, 16)); - - prov = bt_mesh_prov_get(); - - if (prov->unprovisioned_beacon) { - prov->unprovisioned_beacon(uuid, - (bt_mesh_prov_oob_info_t)oob_info, - uri_hash); - } -} - -static void sub_update_beacon_observation(struct bt_mesh_subnet *sub) -{ - sub->beacons_last = sub->beacons_cur; - sub->beacons_cur = 0U; -} - -static void update_beacon_observation(void) -{ - static bool first_half; - - /* Observation period is 20 seconds, whereas the beacon timer - * runs every 10 seconds. We process what's happened during the - * window only after the seconnd half. - */ - first_half = !first_half; - if (first_half) { - return; - } - - bt_mesh_subnet_foreach(sub_update_beacon_observation); -} - -static void beacon_send(struct ble_npl_event *work) -{ - /* Don't send anything if we have an active provisioning link */ - if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) && bt_mesh_prov_active()) { - k_delayed_work_submit(&beacon_timer, - K_SECONDS(MYNEWT_VAL(BLE_MESH_UNPROV_BEACON_INT))); - return; - } - - BT_DBG(""); - - if (bt_mesh_is_provisioned()) { - update_beacon_observation(); - (void)bt_mesh_subnet_find(secure_beacon_send, NULL); - - /* Only resubmit if beaconing is still enabled */ - if (bt_mesh_beacon_enabled() || - atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) { - k_delayed_work_submit(&beacon_timer, - PROVISIONED_INTERVAL); - } - - return; - } - - if (IS_ENABLED(BLE_MESH_PB_ADV)) { - unprovisioned_beacon_send(); - k_delayed_work_submit(&beacon_timer, - K_SECONDS(MYNEWT_VAL(BLE_MESH_UNPROV_BEACON_INT))); - } -} - -struct beacon_params { - const uint8_t *net_id; - const uint8_t *auth; - uint32_t iv_index; - uint8_t flags; - - bool new_key; -}; - -static bool auth_match(struct bt_mesh_subnet_keys *keys, - const struct beacon_params *params) -{ - uint8_t net_auth[8]; - - if (memcmp(params->net_id, keys->net_id, 8)) { - return false; - } - - bt_mesh_beacon_auth(keys->beacon, params->flags, keys->net_id, - params->iv_index, net_auth); - - if (memcmp(params->auth, net_auth, 8)) { - BT_WARN("Authentication Value %s != %s", - bt_hex(params->auth, 8), bt_hex(net_auth, 8)); - return false; - } - - return true; -} - -static int subnet_by_id(struct bt_mesh_subnet *sub, void *cb_data) -{ - struct beacon_params *params = cb_data; - - for (int i = 0; i < ARRAY_SIZE(sub->keys); i++) { - if (sub->keys[i].valid && auth_match(&sub->keys[i], params)) { - params->new_key = (i > 0); - return true; - } - } - - return false; -} - -static void secure_beacon_recv(struct os_mbuf *buf) -{ - struct beacon_params params; - struct bt_mesh_subnet *sub; - uint8_t *data; - - if (buf->om_len < 21) { - BT_ERR("Too short secure beacon (len %u)", buf->om_len); - return; - } - - sub = bt_mesh_subnet_find(cache_check, buf->om_data); - if (sub) { - /* We've seen this beacon before - just update the stats */ - goto update_stats; - } - - /* So we can add to the cache if auth matches */ - data = buf->om_data; - - params.flags = net_buf_simple_pull_u8(buf); - params.net_id = net_buf_simple_pull_mem(buf, 8); - params.iv_index = net_buf_simple_pull_be32(buf); - params.auth = buf->om_data; - - BT_DBG("flags 0x%02x id %s iv_index 0x%08x", - params.flags, bt_hex(params.net_id, 8), params.iv_index); - - sub = bt_mesh_subnet_find(subnet_by_id, ¶ms); - if (!sub) { - BT_DBG("No subnet that matched beacon"); - return; - } - - if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !params.new_key) { - BT_WARN("Ignoring Phase 2 KR Update secured using old key"); - return; - } - - cache_add(data, sub); - - bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(params.flags), - params.new_key); - - /* If we have NetKey0 accept initiation only from it */ - if (bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY) && - sub->net_idx != BT_MESH_KEY_PRIMARY) { - BT_WARN("Ignoring secure beacon on non-primary subnet"); - goto update_stats; - } - - BT_DBG("net_idx 0x%04x iv_index 0x%08x, current iv_index 0x%08x", - sub->net_idx, params.iv_index, bt_mesh.iv_index); - - if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) && - (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) == - BT_MESH_IV_UPDATE(params.flags))) { - bt_mesh_beacon_ivu_initiator(false); - } - - bt_mesh_net_iv_update(params.iv_index, BT_MESH_IV_UPDATE(params.flags)); - -update_stats: - if (bt_mesh_beacon_enabled() && - sub->beacons_cur < 0xff) { - sub->beacons_cur++; - } -} - -void bt_mesh_beacon_recv(struct os_mbuf *buf) -{ - uint8_t type; - - BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - - if (buf->om_len < 1) { - BT_ERR("Too short beacon"); - return; - } - - type = net_buf_simple_pull_u8(buf); - switch (type) { - case BEACON_TYPE_UNPROVISIONED: - if (IS_ENABLED(BLE_MESH_PB_ADV)) { - unprovisioned_beacon_recv(buf); - } - break; - case BEACON_TYPE_SECURE: - secure_beacon_recv(buf); - break; - default: - BT_WARN("Unknown beacon type 0x%02x", type); - break; - } -} - -void bt_mesh_beacon_update(struct bt_mesh_subnet *sub) -{ - uint8_t flags = bt_mesh_net_flags(sub); - struct bt_mesh_subnet_keys *keys; - int err; - - keys = &sub->keys[SUBNET_KEY_TX_IDX(sub)]; - - BT_DBG("NetIndex 0x%03x Using %s key", sub->net_idx, - SUBNET_KEY_TX_IDX(sub) ? "new" : "current"); - BT_DBG("flags 0x%02x, IVI 0x%08x", flags, bt_mesh.iv_index); - - err = bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id, - bt_mesh.iv_index, sub->auth); - if (err) { - BT_ERR("Failed updating net beacon for 0x%03x", sub->net_idx); - } -} - -static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) -{ - if (evt != BT_MESH_KEY_DELETED) { - bt_mesh_beacon_update(sub); - } -} - -void bt_mesh_beacon_init(void) -{ - if (!bt_mesh_subnet_cb_list[1]) { - bt_mesh_subnet_cb_list[1] = subnet_evt; - } - - k_delayed_work_init(&beacon_timer, beacon_send); -} - -void bt_mesh_beacon_ivu_initiator(bool enable) -{ - atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_INITIATOR, enable); - - if (enable) { - k_delayed_work_submit(&beacon_timer, K_NO_WAIT); - } else if (!bt_mesh_beacon_enabled()) { - k_delayed_work_cancel(&beacon_timer); - } -} - -static void subnet_beacon_enable(struct bt_mesh_subnet *sub) -{ - sub->beacons_last = 0U; - sub->beacons_cur = 0U; - - bt_mesh_beacon_update(sub); -} - -void bt_mesh_beacon_enable(void) -{ - if (!bt_mesh_is_provisioned()) { - k_delayed_work_submit(&beacon_timer, K_NO_WAIT); - return; - } - - bt_mesh_subnet_foreach(subnet_beacon_enable); - - k_delayed_work_submit(&beacon_timer, K_NO_WAIT); -} - -void bt_mesh_beacon_disable(void) -{ - if (!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) { - k_delayed_work_cancel(&beacon_timer); - } -} -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/beacon.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/beacon.h deleted file mode 100644 index 50f27cff9..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/beacon.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __BEACON_H__ -#define __BEACON_H__ - -#include "nimble/porting/nimble/include/os/os_mbuf.h" - -void bt_mesh_beacon_enable(void); -void bt_mesh_beacon_disable(void); - -void bt_mesh_beacon_ivu_initiator(bool enable); - -void bt_mesh_beacon_recv(struct os_mbuf *buf); - -void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, - struct os_mbuf *buf); - -void bt_mesh_beacon_init(void); -void bt_mesh_beacon_update(struct bt_mesh_subnet *sub); - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cdb.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cdb.c deleted file mode 100644 index f9b5469d0..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cdb.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright (c) 2019 Tobias Svehagen - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define BT_DBG_ENABLED MYNEWT_VAL(BLE_MESH_DEBUG_CDB) -#define LOG_MODULE_NAME bt_mesh_cdb -#include "nimble/porting/nimble/include/log/log.h" - -#include "../include/mesh/mesh.h" -#include "net.h" -#include "rpl.h" -#include "settings.h" -#include "mesh_priv.h" -#include "../include/mesh/glue.h" - -#if MYNEWT_VAL(BLE_MESH_CDB) -struct bt_mesh_cdb bt_mesh_cdb = { - .nodes = { - [0 ... (CONFIG_BT_MESH_NODE_COUNT - 1)] = { - .addr = BT_MESH_ADDR_UNASSIGNED, - } - }, - .subnets = { - [0 ... (CONFIG_BT_MESH_SUBNET_COUNT - 1)] = { - .net_idx = BT_MESH_KEY_UNUSED, - } - }, - .app_keys = { - [0 ... (CONFIG_BT_MESH_APP_KEY_COUNT - 1)] = { - .net_idx = BT_MESH_KEY_UNUSED, - } - }, -}; - -/* - * Check if an address range from addr_start for addr_start + num_elem - 1 is - * free for use. When a conflict is found, next will be set to the next address - * available after the conflicting range and -EAGAIN will be returned. - */ -static int addr_is_free(uint16_t addr_start, uint8_t num_elem, uint16_t *next) -{ - uint16_t addr_end = addr_start + num_elem - 1; - uint16_t other_start, other_end; - int i; - - if (!BT_MESH_ADDR_IS_UNICAST(addr_start) || - !BT_MESH_ADDR_IS_UNICAST(addr_end) || - num_elem == 0) { - return -EINVAL; - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); i++) { - struct bt_mesh_cdb_node *node = &bt_mesh_cdb.nodes[i]; - - if (node->addr == BT_MESH_ADDR_UNASSIGNED) { - continue; - } - - other_start = node->addr; - other_end = other_start + node->num_elem - 1; - - if (!(addr_end < other_start || addr_start > other_end)) { - if (next) { - *next = other_end + 1; - } - - return -EAGAIN; - } - } - - return 0; -} - -/* - * Find the lowest possible starting address that can fit num_elem elements. If - * a free address range cannot be found, BT_MESH_ADDR_UNASSIGNED will be - * returned. Otherwise the first address in the range is returned. - * - * NOTE: This is quite an ineffective algorithm as it might need to look - * through the array of nodes N+2 times. A more effective algorithm - * could be used if the nodes were stored in a sorted list. - */ -static uint16_t find_lowest_free_addr(uint8_t num_elem) -{ - uint16_t addr = 1, next = 0; - int err, i; - - /* - * It takes a maximum of node count + 2 to find a free address if there - * is any. +1 for our own address and +1 for making sure that the - * address range is valid. - */ - for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes) + 2; ++i) { - err = addr_is_free(addr, num_elem, &next); - if (err == 0) { - break; - } else if (err != -EAGAIN) { - addr = BT_MESH_ADDR_UNASSIGNED; - break; - } - - addr = next; - } - - return addr; -} - -int bt_mesh_cdb_create(const uint8_t key[16]) -{ - struct bt_mesh_cdb_subnet *sub; - - if (atomic_test_and_set_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_VALID)) { - return -EALREADY; - } - - sub = bt_mesh_cdb_subnet_alloc(BT_MESH_KEY_PRIMARY); - if (sub == NULL) { - return -ENOMEM; - } - - memcpy(sub->keys[0].net_key, key, 16); - bt_mesh_cdb.iv_index = 0; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb(); - bt_mesh_store_cdb_subnet(sub); - } - - return 0; -} - -void bt_mesh_cdb_clear(void) -{ - int i; - - atomic_clear_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID); - - for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); ++i) { - if (bt_mesh_cdb.nodes[i].addr != BT_MESH_ADDR_UNASSIGNED) { - bt_mesh_cdb_node_del(&bt_mesh_cdb.nodes[i], true); - } - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) { - if (bt_mesh_cdb.subnets[i].net_idx != BT_MESH_KEY_UNUSED) { - bt_mesh_cdb_subnet_del(&bt_mesh_cdb.subnets[i], true); - } - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) { - if (bt_mesh_cdb.app_keys[i].net_idx != BT_MESH_KEY_UNUSED) { - bt_mesh_cdb_app_key_del(&bt_mesh_cdb.app_keys[i], true); - } - } - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb(); - } -} - -void bt_mesh_cdb_iv_update(uint32_t iv_index, bool iv_update) -{ - BT_DBG("Updating IV index to %d\n", iv_index); - - bt_mesh_cdb.iv_index = iv_index; - - atomic_set_bit_to(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS, - iv_update); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb(); - } -} - -struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_alloc(uint16_t net_idx) -{ - struct bt_mesh_cdb_subnet *sub; - int i; - - if (bt_mesh_cdb_subnet_get(net_idx) != NULL) { - return NULL; - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) { - sub = &bt_mesh_cdb.subnets[i]; - - if (sub->net_idx != BT_MESH_KEY_UNUSED) { - continue; - } - - sub->net_idx = net_idx; - - return sub; - } - - return NULL; -} - -void bt_mesh_cdb_subnet_del(struct bt_mesh_cdb_subnet *sub, bool store) -{ - BT_DBG("NetIdx 0x%03x store %u", sub->net_idx, store); - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_clear_cdb_subnet(sub); - } - - sub->net_idx = BT_MESH_KEY_UNUSED; - memset(sub->keys, 0, sizeof(sub->keys)); -} - -struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_get(uint16_t net_idx) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) { - if (bt_mesh_cdb.subnets[i].net_idx == net_idx) { - return &bt_mesh_cdb.subnets[i]; - } - } - - return NULL; -} - -void bt_mesh_cdb_subnet_store(const struct bt_mesh_cdb_subnet *sub) -{ - if (MYNEWT_VAL(BLE_MESH_SETTINGS)) { - bt_mesh_store_cdb_subnet(sub); - } -} - -uint8_t bt_mesh_cdb_subnet_flags(const struct bt_mesh_cdb_subnet *sub) -{ - uint8_t flags = 0x00; - - if (sub && sub->kr_flag) { - flags |= BT_MESH_NET_FLAG_KR; - } - - if (atomic_test_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS)) { - flags |= BT_MESH_NET_FLAG_IVU; - } - - return flags; -} - -struct bt_mesh_cdb_node *bt_mesh_cdb_node_alloc(const uint8_t uuid[16], uint16_t addr, - uint8_t num_elem, uint16_t net_idx) -{ - int i; - - if (addr == BT_MESH_ADDR_UNASSIGNED) { - addr = find_lowest_free_addr(num_elem); - if (addr == BT_MESH_ADDR_UNASSIGNED) { - return NULL; - } - } else if (addr_is_free(addr, num_elem, NULL) < 0) { - BT_DBG("Address range 0x%04x-0x%04x is not free", addr, - addr + num_elem - 1); - return NULL; - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); i++) { - struct bt_mesh_cdb_node *node = &bt_mesh_cdb.nodes[i]; - - if (node->addr == BT_MESH_ADDR_UNASSIGNED) { - memcpy(node->uuid, uuid, 16); - node->addr = addr; - node->num_elem = num_elem; - node->net_idx = net_idx; - atomic_set(node->flags, 0); - return node; - } - } - - return NULL; -} - -void bt_mesh_cdb_node_del(struct bt_mesh_cdb_node *node, bool store) -{ - BT_DBG("Node addr 0x%04x store %u", node->addr, store); - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_clear_cdb_node(node); - } - - node->addr = BT_MESH_ADDR_UNASSIGNED; - memset(node->dev_key, 0, sizeof(node->dev_key)); -} - -struct bt_mesh_cdb_node *bt_mesh_cdb_node_get(uint16_t addr) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); i++) { - struct bt_mesh_cdb_node *node = &bt_mesh_cdb.nodes[i]; - - if (addr >= node->addr && - addr <= node->addr + node->num_elem - 1) { - return node; - } - } - - return NULL; -} - -void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node) -{ - if (MYNEWT_VAL(BLE_MESH_SETTINGS)) { - bt_mesh_store_cdb_node(node); - } -} - -void bt_mesh_cdb_node_foreach(bt_mesh_cdb_node_func_t func, void *user_data) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); ++i) { - if (bt_mesh_cdb.nodes[i].addr == BT_MESH_ADDR_UNASSIGNED) { - continue; - } - - if (func(&bt_mesh_cdb.nodes[i], user_data) == - BT_MESH_CDB_ITER_STOP) { - break; - } - } -} - -struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_alloc(uint16_t net_idx, - uint16_t app_idx) -{ - struct bt_mesh_cdb_app_key *key; - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) { - key = &bt_mesh_cdb.app_keys[i]; - - if (key->net_idx != BT_MESH_KEY_UNUSED) { - continue; - } - - key->net_idx = net_idx; - key->app_idx = app_idx; - - return key; - } - - return NULL; -} - -void bt_mesh_cdb_app_key_del(struct bt_mesh_cdb_app_key *key, bool store) -{ - BT_DBG("AppIdx 0x%03x store %u", key->app_idx, store); - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_clear_cdb_app_key(key); - } - - key->net_idx = BT_MESH_ADDR_UNASSIGNED; - memset(key->keys, 0, sizeof(key->keys)); -} - -struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(uint16_t app_idx) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); i++) { - struct bt_mesh_cdb_app_key *key = &bt_mesh_cdb.app_keys[i]; - - if (key->net_idx != BT_MESH_KEY_UNUSED && - key->app_idx == app_idx) { - return key; - } - } - - return NULL; -} - -void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key) -{ - if (MYNEWT_VAL(BLE_MESH_SETTINGS)) { - bt_mesh_store_cdb_app_key(key); - } -} -#endif - -#endif // MYNEWT_VAL(BLE_MESH) \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cfg.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cfg.c deleted file mode 100644 index 819fc48be..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cfg.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#include "../include/mesh/mesh.h" -#include "mesh_priv.h" -#include "net.h" -#include "rpl.h" -#include "beacon.h" -#include "settings.h" -#include "heartbeat.h" -#include "friend.h" -#include "cfg.h" -#include "../include/mesh/glue.h" - -void bt_mesh_beacon_set(bool beacon) -{ - if (atomic_test_bit(bt_mesh.flags, BT_MESH_BEACON) == beacon) { - return; - } - - atomic_set_bit_to(bt_mesh.flags, BT_MESH_BEACON, beacon); - - if (beacon) { - bt_mesh_beacon_enable(); - } else { - bt_mesh_beacon_disable(); - } - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && - atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); - } -} - -bool bt_mesh_beacon_enabled(void) -{ - return atomic_test_bit(bt_mesh.flags, BT_MESH_BEACON); -} - -static int feature_set(int feature_flag, enum bt_mesh_feat_state state) -{ - if (state != BT_MESH_FEATURE_DISABLED && - state != BT_MESH_FEATURE_ENABLED) { - return -EINVAL; - } - - if (atomic_test_bit(bt_mesh.flags, feature_flag) == - (state == BT_MESH_FEATURE_ENABLED)) { - return -EALREADY; - } - - atomic_set_bit_to(bt_mesh.flags, feature_flag, - (state == BT_MESH_FEATURE_ENABLED)); - - return 0; -} - -static enum bt_mesh_feat_state feature_get(int feature_flag) -{ - return atomic_test_bit(bt_mesh.flags, feature_flag) ? - BT_MESH_FEATURE_ENABLED : - BT_MESH_FEATURE_DISABLED; -} - -int bt_mesh_gatt_proxy_set(enum bt_mesh_feat_state gatt_proxy) -{ - int err; - - if (!IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - return -ENOTSUP; - } - - err = feature_set(BT_MESH_GATT_PROXY, gatt_proxy); - if (err) { - return err; - } - - bt_mesh_hb_feature_changed(BT_MESH_FEAT_PROXY); - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && - atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); - } - - return 0; -} - -enum bt_mesh_feat_state bt_mesh_gatt_proxy_get(void) -{ - if (!IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - return BT_MESH_FEATURE_NOT_SUPPORTED; - } - - return feature_get(BT_MESH_GATT_PROXY); -} - -int bt_mesh_default_ttl_set(uint8_t default_ttl) -{ - if (default_ttl == 1 || default_ttl > BT_MESH_TTL_MAX) { - return -EINVAL; - } - - if (default_ttl == bt_mesh.default_ttl) { - return 0; - } - - bt_mesh.default_ttl = default_ttl; - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && - atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); - } - - return 0; -} - -uint8_t bt_mesh_default_ttl_get(void) -{ - return bt_mesh.default_ttl; -} - -int bt_mesh_friend_set(enum bt_mesh_feat_state friendship) -{ - int err; - - if (!IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - return -ENOTSUP; - } - - err = feature_set(BT_MESH_FRIEND, friendship); - if (err) { - return err; - } - - bt_mesh_hb_feature_changed(BT_MESH_FEAT_FRIEND); - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && - atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); - } - - if (friendship == BT_MESH_FEATURE_DISABLED) { - bt_mesh_friends_clear(); - } - - return 0; -} - -enum bt_mesh_feat_state bt_mesh_friend_get(void) -{ - if (!IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - return BT_MESH_FEATURE_NOT_SUPPORTED; - } - - return feature_get(BT_MESH_FRIEND); -} - -void bt_mesh_net_transmit_set(uint8_t xmit) -{ - if (bt_mesh.net_xmit == xmit) { - return; - } - - bt_mesh.net_xmit = xmit; - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && - atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); - } -} - -uint8_t bt_mesh_net_transmit_get(void) -{ - return bt_mesh.net_xmit; -} - -int bt_mesh_relay_set(enum bt_mesh_feat_state relay, uint8_t xmit) -{ - int err; - - if (!CONFIG_BT_MESH_RELAY) { - return -ENOTSUP; - } - - err = feature_set(BT_MESH_RELAY, relay); - if (err == -EINVAL) { - return err; - } - - if (err == -EALREADY && bt_mesh.relay_xmit == xmit) { - return -EALREADY; - } - - bt_mesh.relay_xmit = xmit; - bt_mesh_hb_feature_changed(BT_MESH_FEAT_RELAY); - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && - atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); - } - - return 0; -} - -enum bt_mesh_feat_state bt_mesh_relay_get(void) -{ - return feature_get(BT_MESH_RELAY); -} - -uint8_t bt_mesh_relay_retransmit_get(void) -{ - if (!CONFIG_BT_MESH_RELAY) { - return 0; - } - - return bt_mesh.relay_xmit; -} - -bool bt_mesh_fixed_group_match(uint16_t addr) -{ - /* Check for fixed group addresses */ - switch (addr) { - case BT_MESH_ADDR_ALL_NODES: - return true; - case BT_MESH_ADDR_PROXIES: - return (bt_mesh_gatt_proxy_get() == BT_MESH_FEATURE_ENABLED); - case BT_MESH_ADDR_FRIENDS: - return (bt_mesh_friend_get() == BT_MESH_FEATURE_ENABLED); - case BT_MESH_ADDR_RELAYS: - return (bt_mesh_relay_get() == BT_MESH_FEATURE_ENABLED); - default: - return false; - } -} - -void bt_mesh_cfg_init(void) -{ - bt_mesh.default_ttl = CONFIG_BT_MESH_DEFAULT_TTL; - bt_mesh.net_xmit = - BT_MESH_TRANSMIT(CONFIG_BT_MESH_NETWORK_TRANSMIT_COUNT, - CONFIG_BT_MESH_NETWORK_TRANSMIT_INTERVAL); - -#if defined(CONFIG_BT_MESH_RELAY) - bt_mesh.relay_xmit = - BT_MESH_TRANSMIT(CONFIG_BT_MESH_RELAY_RETRANSMIT_COUNT, - CONFIG_BT_MESH_RELAY_RETRANSMIT_INTERVAL); -#endif - - if (CONFIG_BT_MESH_RELAY_ENABLED) { - atomic_set_bit(bt_mesh.flags, BT_MESH_RELAY); - } - - if (CONFIG_BT_MESH_BEACON_ENABLED) { - atomic_set_bit(bt_mesh.flags, BT_MESH_BEACON); - } - - if (CONFIG_BT_MESH_GATT_PROXY_ENABLED) { - atomic_set_bit(bt_mesh.flags, BT_MESH_GATT_PROXY); - } - - if (CONFIG_BT_MESH_FRIEND_ENABLED) { - atomic_set_bit(bt_mesh.flags, BT_MESH_FRIEND); - } -} - -#endif /* MYNEWT_VAL(BLE_MESH) */ \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cfg.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cfg.h deleted file mode 100644 index 6f58acf8b..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cfg.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -void bt_mesh_cfg_init(void); - -bool bt_mesh_fixed_group_match(uint16_t addr); \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cfg_cli.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cfg_cli.c deleted file mode 100644 index d3c88f78c..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cfg_cli.c +++ /dev/null @@ -1,2120 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG -#if MYNEWT_VAL(BLE_MESH_CFG_CLI) - -#include "../include/mesh/mesh.h" - -#include -#include -#include - -#include "net.h" -#include "foundation.h" - -#define CID_NVAL 0xffff - -/* 2 byte dummy opcode for getting compile time buffer sizes. */ -#define DUMMY_2_BYTE_OP BT_MESH_MODEL_OP_2(0xff, 0xff) - -struct comp_data { - uint8_t *status; - struct os_mbuf *comp; -}; - -static int32_t msg_timeout = K_SECONDS(5); - -static struct bt_mesh_cfg_cli *cli; - -static void comp_data_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct comp_data *param; - size_t to_copy; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_DEV_COMP_DATA_STATUS) { - BT_WARN("Unexpected Composition Data Status"); - return; - } - - param = cli->op_param; - - *(param->status) = net_buf_simple_pull_u8(buf); - to_copy = min(net_buf_simple_tailroom(param->comp), buf->om_len); - net_buf_simple_add_mem(param->comp, buf->om_data, to_copy); - - k_sem_give(&cli->op_sync); -} - -static void state_status_u8(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf, - uint32_t expect_status) -{ - uint8_t *status; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != expect_status) { - BT_WARN("Unexpected Status (0x%08x != 0x%08x)", - (unsigned) cli->op_pending, (unsigned) expect_status); - return; - } - - status = cli->op_param; - *status = net_buf_simple_pull_u8(buf); - - k_sem_give(&cli->op_sync); -} - -static void beacon_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - state_status_u8(model, ctx, buf, OP_BEACON_STATUS); -} - -static void ttl_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) -{ - state_status_u8(model, ctx, buf, OP_DEFAULT_TTL_STATUS); -} - -static void friend_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) -{ - state_status_u8(model, ctx, buf, OP_FRIEND_STATUS); -} - -static void gatt_proxy_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) -{ - state_status_u8(model, ctx, buf, OP_GATT_PROXY_STATUS); -} - -struct relay_param { - uint8_t *status; - uint8_t *transmit; -}; - -static void relay_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) -{ - struct relay_param *param; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_RELAY_STATUS) { - BT_WARN("Unexpected Relay Status message"); - return; - } - - param = cli->op_param; - *param->status = net_buf_simple_pull_u8(buf); - *param->transmit = net_buf_simple_pull_u8(buf); - - k_sem_give(&cli->op_sync); -} - -struct net_key_param { - uint8_t *status; - uint16_t net_idx; -}; - -static void net_key_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct net_key_param *param; - uint16_t net_idx; - uint8_t status; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_NET_KEY_STATUS) { - BT_WARN("Unexpected Net Key Status message"); - return; - } - - status = net_buf_simple_pull_u8(buf); - net_idx = net_buf_simple_pull_le16(buf) & 0xfff; - - param = cli->op_param; - if (param->net_idx != net_idx) { - BT_WARN("Net Key Status key index does not match"); - return; - } - - if (param->status) { - *param->status = status; - } - - k_sem_give(&cli->op_sync); -} - -struct net_key_list_param { - uint16_t *keys; - size_t *key_cnt; -}; - -static void net_key_list(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct net_key_list_param *param; - int i; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_NET_KEY_LIST) { - BT_WARN("Unexpected Net Key List message"); - return; - } - - param = cli->op_param; - - for (i = 0; i < *param->key_cnt && buf->om_len >= 3; i += 2) { - key_idx_unpack(buf, ¶m->keys[i], ¶m->keys[i + 1]); - } - - if (i < *param->key_cnt && buf->om_len >= 2) { - param->keys[i++] = net_buf_simple_pull_le16(buf) & 0xfff; - } - - *param->key_cnt = i; - - k_sem_give(&cli->op_sync); -} - -static void node_reset_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) -{ - bool *param = NULL; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x", - ctx->net_idx, ctx->app_idx, ctx->addr); - - if (cli->op_pending != OP_NODE_RESET_STATUS) { - BT_WARN("Unexpected Node Reset Status message"); - return; - } - - param = cli->op_param; - - if (param) { - *param = true; - } - k_sem_give(&cli->op_sync); -} - -struct app_key_param { - uint8_t *status; - uint16_t net_idx; - uint16_t app_idx; -}; - -static void app_key_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) -{ - struct app_key_param *param; - uint16_t net_idx, app_idx; - uint8_t status; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_APP_KEY_STATUS) { - BT_WARN("Unexpected App Key Status message"); - return; - } - - status = net_buf_simple_pull_u8(buf); - key_idx_unpack(buf, &net_idx, &app_idx); - - param = cli->op_param; - if (param->net_idx != net_idx || param->app_idx != app_idx) { - BT_WARN("App Key Status key indices did not match"); - return; - } - - if (param->status) { - *param->status = status; - } - - k_sem_give(&cli->op_sync); -} - -struct app_key_list_param { - uint16_t net_idx; - uint8_t *status; - uint16_t *keys; - size_t *key_cnt; -}; - -static void app_key_list(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct app_key_list_param *param; - uint16_t net_idx; - uint8_t status; - int i; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_APP_KEY_LIST) { - BT_WARN("Unexpected App Key List message"); - return; - } - - status = net_buf_simple_pull_u8(buf); - net_idx = net_buf_simple_pull_le16(buf) & 0xfff; - - param = cli->op_param; - if (param->net_idx != net_idx) { - BT_WARN("App Key List Net Key index did not match"); - return; - } - - for (i = 0; i < *param->key_cnt && buf->om_len >= 3; i += 2) { - key_idx_unpack(buf, ¶m->keys[i], ¶m->keys[i + 1]); - } - - if (i < *param->key_cnt && buf->om_len >= 2) { - param->keys[i++] = net_buf_simple_pull_le16(buf) & 0xfff; - } - - *param->key_cnt = i; - if (param->status) { - *param->status = status; - } - - k_sem_give(&cli->op_sync); -} - -struct mod_app_param { - uint8_t *status; - uint16_t elem_addr; - uint16_t mod_app_idx; - uint16_t mod_id; - uint16_t cid; -}; - -static void mod_app_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) -{ - uint16_t elem_addr, mod_app_idx, mod_id, cid; - struct mod_app_param *param; - uint8_t status; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_MOD_APP_STATUS) { - BT_WARN("Unexpected Model App Status message"); - return; - } - - status = net_buf_simple_pull_u8(buf); - elem_addr = net_buf_simple_pull_le16(buf); - mod_app_idx = net_buf_simple_pull_le16(buf); - - if (buf->om_len >= 4) { - cid = net_buf_simple_pull_le16(buf); - } else { - cid = CID_NVAL; - } - - mod_id = net_buf_simple_pull_le16(buf); - - param = cli->op_param; - if (param->elem_addr != elem_addr || - param->mod_app_idx != mod_app_idx || param->mod_id != mod_id || - param->cid != cid) { - BT_WARN("Model App Status parameters did not match"); - return; - } - - if (param->status) { - *param->status = status; - } - - k_sem_give(&cli->op_sync); -} - -struct mod_member_list_param { - uint8_t *status; - uint16_t elem_addr; - uint16_t mod_id; - uint16_t cid; - uint16_t *members; - size_t *member_cnt; -}; - -static void mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf, bool vnd) -{ - struct mod_member_list_param *param; - uint16_t elem_addr, mod_id, cid; - uint8_t status; - int i; - - status = net_buf_simple_pull_u8(buf); - elem_addr = net_buf_simple_pull_le16(buf); - if (vnd) { - cid = net_buf_simple_pull_le16(buf); - } - - mod_id = net_buf_simple_pull_le16(buf); - - param = cli->op_param; - if (param->elem_addr != elem_addr || param->mod_id != mod_id || - (vnd && param->cid != cid)) { - BT_WARN("Model Member List parameters did not match"); - return; - } - - if (buf->om_len % 2) { - BT_WARN("Model Member List invalid length"); - return; - } - - for (i = 0; i < *param->member_cnt && buf->om_len; i++) { - param->members[i] = net_buf_simple_pull_le16(buf); - } - - *param->member_cnt = i; - if (param->status) { - *param->status = status; - } - - k_sem_give(&cli->op_sync); -} - -static void mod_app_list(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_SIG_MOD_APP_LIST) { - BT_WARN("Unexpected Model App List message"); - return; - } - - mod_member_list_handle(ctx, buf, false); -} - -static void mod_app_list_vnd(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_VND_MOD_APP_LIST) { - BT_WARN("Unexpected Model App List Vendor message"); - return; - } - - mod_member_list_handle(ctx, buf, true); -} - -struct mod_pub_param { - uint16_t mod_id; - uint16_t cid; - uint16_t elem_addr; - uint8_t *status; - struct bt_mesh_cfg_mod_pub *pub; -}; - -static void mod_pub_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) -{ - uint16_t mod_id, cid, elem_addr; - struct mod_pub_param *param; - uint8_t status; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_MOD_PUB_STATUS) { - BT_WARN("Unexpected Model Pub Status message"); - return; - } - - param = cli->op_param; - if (param->cid != CID_NVAL) { - if (buf->om_len < 14) { - BT_WARN("Unexpected Mod Pub Status with SIG Model"); - return; - } - - cid = sys_get_le16(&buf->om_data[10]); - mod_id = sys_get_le16(&buf->om_data[12]); - } else { - if (buf->om_len > 12) { - BT_WARN("Unexpected Mod Pub Status with Vendor Model"); - return; - } - - cid = CID_NVAL; - mod_id = sys_get_le16(&buf->om_data[10]); - } - - if (mod_id != param->mod_id || cid != param->cid) { - BT_WARN("Mod Pub Model ID or Company ID mismatch"); - return; - } - - status = net_buf_simple_pull_u8(buf); - - elem_addr = net_buf_simple_pull_le16(buf); - if (elem_addr != param->elem_addr) { - BT_WARN("Model Pub Status for unexpected element (0x%04x)", - elem_addr); - return; - } - - if (param->status) { - *param->status = status; - } - - if (param->pub) { - param->pub->addr = net_buf_simple_pull_le16(buf); - param->pub->app_idx = net_buf_simple_pull_le16(buf); - param->pub->cred_flag = (param->pub->app_idx & BIT(12)); - param->pub->app_idx &= BIT_MASK(12); - param->pub->ttl = net_buf_simple_pull_u8(buf); - param->pub->period = net_buf_simple_pull_u8(buf); - param->pub->transmit = net_buf_simple_pull_u8(buf); - } - - k_sem_give(&cli->op_sync); -} - -struct mod_sub_param { - uint8_t *status; - uint16_t elem_addr; - uint16_t *sub_addr; - uint16_t *expect_sub; - uint16_t mod_id; - uint16_t cid; -}; - -static void mod_sub_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) -{ - uint16_t elem_addr, sub_addr, mod_id, cid; - struct mod_sub_param *param; - uint8_t status; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_MOD_SUB_STATUS) { - BT_WARN("Unexpected Model Subscription Status message"); - return; - } - - status = net_buf_simple_pull_u8(buf); - elem_addr = net_buf_simple_pull_le16(buf); - sub_addr = net_buf_simple_pull_le16(buf); - - if (buf->om_len >= 4) { - cid = net_buf_simple_pull_le16(buf); - } else { - cid = CID_NVAL; - } - - mod_id = net_buf_simple_pull_le16(buf); - - param = cli->op_param; - if (param->elem_addr != elem_addr || param->mod_id != mod_id || - (param->expect_sub && *param->expect_sub != sub_addr) || - param->cid != cid) { - BT_WARN("Model Subscription Status parameters did not match"); - return; - } - - if (param->sub_addr) { - *param->sub_addr = sub_addr; - } - - if (param->status) { - *param->status = status; - } - - k_sem_give(&cli->op_sync); -} - -static void mod_sub_list(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_MOD_SUB_LIST) { - BT_WARN("Unexpected Model Subscription List message"); - return; - } - - mod_member_list_handle(ctx, buf, false); -} - -static void mod_sub_list_vnd(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_MOD_SUB_LIST_VND) { - BT_WARN("Unexpected Model Subscription List Vendor message"); - return; - } - - mod_member_list_handle(ctx, buf, true); -} - -struct hb_sub_param { - uint8_t *status; - struct bt_mesh_cfg_hb_sub *sub; -}; - -static void hb_sub_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) -{ - struct hb_sub_param *param; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_HEARTBEAT_SUB_STATUS) { - BT_WARN("Unexpected Heartbeat Subscription Status message"); - return; - } - - param = cli->op_param; - - *param->status = net_buf_simple_pull_u8(buf); - - param->sub->src = net_buf_simple_pull_le16(buf); - param->sub->dst = net_buf_simple_pull_le16(buf); - param->sub->period = net_buf_simple_pull_u8(buf); - param->sub->count = net_buf_simple_pull_u8(buf); - param->sub->min = net_buf_simple_pull_u8(buf); - param->sub->max = net_buf_simple_pull_u8(buf); - - k_sem_give(&cli->op_sync); -} - -struct hb_pub_param { - uint8_t *status; - struct bt_mesh_cfg_hb_pub *pub; -}; - -static void hb_pub_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct hb_pub_param *param; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_HEARTBEAT_PUB_STATUS) { - BT_WARN("Unexpected Heartbeat Publication Status message"); - return; - } - - param = cli->op_param; - - *param->status = net_buf_simple_pull_u8(buf); - - if (param->pub) { - param->pub->dst = net_buf_simple_pull_le16(buf); - param->pub->count = net_buf_simple_pull_u8(buf); - param->pub->period = net_buf_simple_pull_u8(buf); - param->pub->ttl = net_buf_simple_pull_u8(buf); - param->pub->feat = net_buf_simple_pull_u8(buf); - param->pub->net_idx = net_buf_simple_pull_u8(buf); - } - - k_sem_give(&cli->op_sync); -} - -const struct bt_mesh_model_op bt_mesh_cfg_cli_op[] = { - { OP_DEV_COMP_DATA_STATUS, 15, comp_data_status }, - { OP_BEACON_STATUS, 1, beacon_status }, - { OP_DEFAULT_TTL_STATUS, 1, ttl_status }, - { OP_FRIEND_STATUS, 1, friend_status }, - { OP_GATT_PROXY_STATUS, 1, gatt_proxy_status }, - { OP_RELAY_STATUS, 2, relay_status }, - { OP_NET_KEY_STATUS, 3, net_key_status }, - { OP_NET_KEY_LIST, 0, net_key_list }, - { OP_APP_KEY_STATUS, 4, app_key_status }, - { OP_APP_KEY_LIST, 3, app_key_list }, - { OP_MOD_APP_STATUS, 7, mod_app_status }, - { OP_SIG_MOD_APP_LIST, 5, mod_app_list}, - { OP_VND_MOD_APP_LIST, 7, mod_app_list_vnd}, - { OP_MOD_PUB_STATUS, 12, mod_pub_status }, - { OP_MOD_SUB_STATUS, 7, mod_sub_status }, - { OP_MOD_SUB_LIST, 5, mod_sub_list}, - { OP_MOD_SUB_LIST_VND, 7, mod_sub_list_vnd}, - { OP_HEARTBEAT_SUB_STATUS, 9, hb_sub_status }, - { OP_HEARTBEAT_PUB_STATUS, 10, hb_pub_status }, - { OP_NODE_RESET_STATUS, 0, node_reset_status}, - BT_MESH_MODEL_OP_END, -}; - -static int cfg_cli_init(struct bt_mesh_model *model) -{ - BT_DBG(""); - - if (!bt_mesh_model_in_primary(model)) { - BT_ERR("Configuration Client only allowed in primary element"); - return -EINVAL; - } - - if (!model->user_data) { - BT_ERR("No Configuration Client context provided"); - return -EINVAL; - } - - cli = model->user_data; - cli->model = model; - - /* - * Configuration Model security is device-key based and both the local - * and remote keys are allowed to access this model. - */ - model->keys[0] = BT_MESH_KEY_DEV_ANY; - - k_sem_init(&cli->op_sync, 0, 1); - - return 0; -} - -const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb = { - .init = cfg_cli_init, -}; - -static int cli_prepare(void *param, uint32_t op) -{ - if (!cli) { - BT_ERR("No available Configuration Client context!"); - return -EINVAL; - } - - if (cli->op_pending) { - BT_WARN("Another synchronous operation pending"); - return -EBUSY; - } - - cli->op_param = param; - cli->op_pending = op; - - return 0; -} - -static void cli_reset(void) -{ - cli->op_pending = 0; - cli->op_param = NULL; -} - -static int cli_wait(void) -{ - int err; - - err = k_sem_take(&cli->op_sync, msg_timeout); - - cli_reset(); - - return err; -} - -int bt_mesh_cfg_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page, - uint8_t *status, struct os_mbuf *comp) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_DEV_COMP_DATA_GET, 1); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct comp_data param = { - .status = status, - .comp = comp, - }; - int err; - - err = cli_prepare(¶m, OP_DEV_COMP_DATA_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_DEV_COMP_DATA_GET); - net_buf_simple_add_u8(msg, page); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -static int get_state_u8(uint16_t net_idx, uint16_t addr, uint32_t op, uint32_t rsp, - uint8_t *val) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(DUMMY_2_BYTE_OP, 0); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - int err; - - err = cli_prepare(val, rsp); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, op); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -static int set_state_u8(uint16_t net_idx, uint16_t addr, uint32_t op, uint32_t rsp, - uint8_t new_val, uint8_t *val) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(DUMMY_2_BYTE_OP, 1); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - int err; - - err = cli_prepare(val, rsp); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, op); - net_buf_simple_add_u8(msg, new_val); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_beacon_get(uint16_t net_idx, uint16_t addr, uint8_t *status) -{ - return get_state_u8(net_idx, addr, OP_BEACON_GET, OP_BEACON_STATUS, - status); -} - -int bt_mesh_cfg_beacon_set(uint16_t net_idx, uint16_t addr, uint8_t val, uint8_t *status) -{ - return set_state_u8(net_idx, addr, OP_BEACON_SET, OP_BEACON_STATUS, - val, status); -} - -int bt_mesh_cfg_ttl_get(uint16_t net_idx, uint16_t addr, uint8_t *ttl) -{ - return get_state_u8(net_idx, addr, OP_DEFAULT_TTL_GET, - OP_DEFAULT_TTL_STATUS, ttl); -} - -int bt_mesh_cfg_ttl_set(uint16_t net_idx, uint16_t addr, uint8_t val, uint8_t *ttl) -{ - return set_state_u8(net_idx, addr, OP_DEFAULT_TTL_SET, - OP_DEFAULT_TTL_STATUS, val, ttl); -} - -int bt_mesh_cfg_friend_get(uint16_t net_idx, uint16_t addr, uint8_t *status) -{ - return get_state_u8(net_idx, addr, OP_FRIEND_GET, - OP_FRIEND_STATUS, status); -} - -int bt_mesh_cfg_friend_set(uint16_t net_idx, uint16_t addr, uint8_t val, uint8_t *status) -{ - return set_state_u8(net_idx, addr, OP_FRIEND_SET, OP_FRIEND_STATUS, - val, status); -} - -int bt_mesh_cfg_gatt_proxy_get(uint16_t net_idx, uint16_t addr, uint8_t *status) -{ - return get_state_u8(net_idx, addr, OP_GATT_PROXY_GET, - OP_GATT_PROXY_STATUS, status); -} - -int bt_mesh_cfg_gatt_proxy_set(uint16_t net_idx, uint16_t addr, uint8_t val, - uint8_t *status) -{ - return set_state_u8(net_idx, addr, OP_GATT_PROXY_SET, - OP_GATT_PROXY_STATUS, val, status); -} - -int bt_mesh_cfg_net_transmit_set(uint16_t net_idx, uint16_t addr, - uint8_t val, uint8_t *transmit) -{ - return set_state_u8(net_idx, addr, OP_NET_TRANSMIT_SET, - OP_NET_TRANSMIT_STATUS, val, transmit); -} - -int bt_mesh_cfg_net_transmit_get(uint16_t net_idx, uint16_t addr, - uint8_t *transmit) -{ - return get_state_u8(net_idx, addr, OP_NET_TRANSMIT_GET, - OP_NET_TRANSMIT_STATUS, transmit); -} - -int bt_mesh_cfg_relay_get(uint16_t net_idx, uint16_t addr, uint8_t *status, - uint8_t *transmit) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_RELAY_GET, 0); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct relay_param param = { - .status = status, - .transmit = transmit, - }; - int err; - - err = cli_prepare(¶m, OP_RELAY_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_RELAY_GET); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_relay_set(uint16_t net_idx, uint16_t addr, uint8_t new_relay, - uint8_t new_transmit, uint8_t *status, uint8_t *transmit) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_RELAY_SET, 2); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct relay_param param = { - .status = status, - .transmit = transmit, - }; - int err; - - err = cli_prepare(¶m, OP_RELAY_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_RELAY_SET); - net_buf_simple_add_u8(msg, new_relay); - net_buf_simple_add_u8(msg, new_transmit); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_net_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, - const uint8_t net_key[16], uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_KEY_ADD, 18); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct net_key_param param = { - .status = status, - .net_idx = key_net_idx, - }; - int err; - - err = cli_prepare(¶m, OP_NET_KEY_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_NET_KEY_ADD); - net_buf_simple_add_le16(msg, key_net_idx); - net_buf_simple_add_mem(msg, net_key, 16); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_net_key_get(uint16_t net_idx, uint16_t addr, uint16_t *keys, - size_t *key_cnt) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_KEY_GET, 0); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct net_key_list_param param = { - .keys = keys, - .key_cnt = key_cnt, - }; - int err; - - err = cli_prepare(¶m, OP_NET_KEY_LIST); - if (err) { - return err; - } - - bt_mesh_model_msg_init(msg, OP_NET_KEY_GET); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - return err; - } - - os_mbuf_free_chain(msg); - return cli_wait(); -} - -int bt_mesh_cfg_net_key_del(uint16_t net_idx, uint16_t addr, - uint16_t key_net_idx, uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_KEY_DEL, 2); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct net_key_param param = { - .status = status, - .net_idx = key_net_idx, - }; - int err; - - err = cli_prepare(¶m, OP_NET_KEY_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_NET_KEY_DEL); - net_buf_simple_add_le16(msg, key_net_idx); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_app_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, - uint16_t key_app_idx, const uint8_t app_key[16], - uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_APP_KEY_ADD, 19); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct app_key_param param = { - .status = status, - .net_idx = key_net_idx, - .app_idx = key_app_idx, - }; - int err; - - err = cli_prepare(¶m, OP_APP_KEY_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_APP_KEY_ADD); - key_idx_pack(msg, key_net_idx, key_app_idx); - net_buf_simple_add_mem(msg, app_key, 16); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_node_reset(uint16_t net_idx, uint16_t addr, bool *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_RESET, 0); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - - int err; - - if (status) { - *status = false; - } - - err = cli_prepare(status, OP_NODE_RESET_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_NODE_RESET); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - if (err) { - return err; - } else { - return 0; - } -} - -int bt_mesh_cfg_app_key_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, - uint8_t *status, uint16_t *keys, size_t *key_cnt) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_APP_KEY_GET, 2); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct app_key_list_param param = { - .net_idx = key_net_idx, - .status = status, - .keys = keys, - .key_cnt = key_cnt, - }; - int err; - - err = cli_prepare(¶m, OP_APP_KEY_LIST); - if (err) { - os_mbuf_free_chain(msg); - return err; - } - - bt_mesh_model_msg_init(msg, OP_APP_KEY_GET); - net_buf_simple_add_le16(msg, key_net_idx); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - os_mbuf_free_chain(msg); - cli_reset(); - return err; - } - - os_mbuf_free_chain(msg); - return cli_wait(); -} - -int bt_mesh_cfg_app_key_del(uint16_t net_idx, uint16_t addr, - uint16_t key_net_idx, uint16_t key_app_idx, uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_APP_KEY_DEL, 3); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct app_key_param param = { - .status = status, - .net_idx = key_net_idx, - .app_idx = key_app_idx, - }; - int err; - - err = cli_prepare(¶m, OP_APP_KEY_STATUS); - if (err) { - os_mbuf_free_chain(msg); - return err; - } - - bt_mesh_model_msg_init(msg, OP_APP_KEY_DEL); - key_idx_pack(msg, key_net_idx, key_app_idx); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - os_mbuf_free_chain(msg); - cli_reset(); - return err; - } - - if (!status) { - cli_reset(); - os_mbuf_free_chain(msg); - return 0; - } - - os_mbuf_free_chain(msg); - return cli_wait(); -} - -static int mod_app_bind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_app_idx, uint16_t mod_id, uint16_t cid, - uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_APP_BIND, 8); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct mod_app_param param = { - .status = status, - .elem_addr = elem_addr, - .mod_app_idx = mod_app_idx, - .mod_id = mod_id, - .cid = cid, - }; - int err; - - err = cli_prepare(¶m, OP_MOD_APP_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_MOD_APP_BIND); - net_buf_simple_add_le16(msg, elem_addr); - net_buf_simple_add_le16(msg, mod_app_idx); - - if (cid != CID_NVAL) { - net_buf_simple_add_le16(msg, cid); - } - - net_buf_simple_add_le16(msg, mod_id); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_mod_app_bind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_app_idx, uint16_t mod_id, uint8_t *status) -{ - return mod_app_bind(net_idx, addr, elem_addr, mod_app_idx, mod_id, - CID_NVAL, status); -} - -int bt_mesh_cfg_mod_app_bind_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_app_idx, uint16_t mod_id, uint16_t cid, - uint8_t *status) -{ - if (cid == CID_NVAL) { - return -EINVAL; - } - - return mod_app_bind(net_idx, addr, elem_addr, mod_app_idx, mod_id, cid, - status); -} - -static int mod_app_unbind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_app_idx, uint16_t mod_id, uint16_t cid, - uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_APP_UNBIND, 8); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct mod_app_param param = { - .status = status, - .elem_addr = elem_addr, - .mod_app_idx = mod_app_idx, - .mod_id = mod_id, - .cid = cid, - }; - int err; - - err = cli_prepare(¶m, OP_MOD_APP_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_MOD_APP_UNBIND); - net_buf_simple_add_le16(msg, elem_addr); - net_buf_simple_add_le16(msg, mod_app_idx); - - if (cid != CID_NVAL) { - net_buf_simple_add_le16(msg, cid); - } - - net_buf_simple_add_le16(msg, mod_id); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - err = 0; - goto done; - } - -done: - os_mbuf_free_chain(msg); - if (err) { - return err; - } else { - return cli_wait(); - } -} - -int bt_mesh_cfg_mod_app_unbind(uint16_t net_idx, uint16_t addr, - uint16_t elem_addr, uint16_t mod_app_idx, - uint16_t mod_id, uint8_t *status) -{ - return mod_app_unbind(net_idx, addr, elem_addr, mod_app_idx, mod_id, - CID_NVAL, status); -} - -int bt_mesh_cfg_mod_app_unbind_vnd(uint16_t net_idx, uint16_t addr, - uint16_t elem_addr, uint16_t mod_app_idx, - uint16_t mod_id, uint16_t cid, uint8_t *status) -{ - if (cid == CID_NVAL) { - return -EINVAL; - } - - return mod_app_unbind(net_idx, addr, elem_addr, mod_app_idx, - mod_id, cid, status); -} - -static int mod_member_list_get(uint32_t op, uint32_t expect_op, uint16_t net_idx, - uint16_t addr, uint16_t elem_addr, uint16_t mod_id, - uint16_t cid, uint8_t *status, uint16_t *apps, - size_t *app_cnt) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(DUMMY_2_BYTE_OP, 6); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct mod_member_list_param param = { - .status = status, - .elem_addr = elem_addr, - .mod_id = mod_id, - .cid = cid, - .members = apps, - .member_cnt = app_cnt, - }; - int err; - - err = cli_prepare(¶m, expect_op); - if (err) { - goto done; - } - - BT_DBG("net_idx 0x%04x addr 0x%04x elem_addr 0x%04x", - net_idx, addr, elem_addr); - BT_DBG("mod_id 0x%04x cid 0x%04x op: %x", mod_id, cid, op); - - bt_mesh_model_msg_init(msg, op); - net_buf_simple_add_le16(msg, elem_addr); - - if (cid != CID_NVAL) { - net_buf_simple_add_le16(msg, cid); - } - - net_buf_simple_add_le16(msg, mod_id); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_mod_app_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint8_t *status, uint16_t *apps, - size_t *app_cnt) -{ - return mod_member_list_get(OP_SIG_MOD_APP_GET, OP_SIG_MOD_APP_LIST, - net_idx, addr, elem_addr, mod_id, CID_NVAL, - status, apps, app_cnt); -} - -int bt_mesh_cfg_mod_app_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint16_t cid, uint8_t *status, - uint16_t *apps, size_t *app_cnt) -{ - if (cid == CID_NVAL) { - return -EINVAL; - } - - return mod_member_list_get(OP_VND_MOD_APP_GET, OP_VND_MOD_APP_LIST, - net_idx, addr, elem_addr, mod_id, CID_NVAL, - status, apps, app_cnt); -} - -static int mod_sub(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t sub_addr, uint16_t mod_id, uint16_t cid, uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(DUMMY_2_BYTE_OP, 8); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct mod_sub_param param = { - .status = status, - .elem_addr = elem_addr, - .expect_sub = &sub_addr, - .mod_id = mod_id, - .cid = cid, - }; - int err; - - err = cli_prepare(¶m, OP_MOD_SUB_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, op); - net_buf_simple_add_le16(msg, elem_addr); - net_buf_simple_add_le16(msg, sub_addr); - - if (cid != CID_NVAL) { - net_buf_simple_add_le16(msg, cid); - } - - net_buf_simple_add_le16(msg, mod_id); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - err = 0; - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_mod_sub_add(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t sub_addr, uint16_t mod_id, uint8_t *status) -{ - return mod_sub(OP_MOD_SUB_ADD, net_idx, addr, elem_addr, sub_addr, - mod_id, CID_NVAL, status); -} - -int bt_mesh_cfg_mod_sub_add_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t sub_addr, uint16_t mod_id, uint16_t cid, - uint8_t *status) -{ - if (cid == CID_NVAL) { - return -EINVAL; - } - - return mod_sub(OP_MOD_SUB_ADD, net_idx, addr, elem_addr, sub_addr, - mod_id, cid, status); -} - -int bt_mesh_cfg_mod_sub_del(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t sub_addr, uint16_t mod_id, uint8_t *status) -{ - return mod_sub(OP_MOD_SUB_DEL, net_idx, addr, elem_addr, sub_addr, - mod_id, CID_NVAL, status); -} - -int bt_mesh_cfg_mod_sub_del_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t sub_addr, uint16_t mod_id, uint16_t cid, - uint8_t *status) -{ - if (cid == CID_NVAL) { - return -EINVAL; - } - - return mod_sub(OP_MOD_SUB_DEL, net_idx, addr, elem_addr, sub_addr, - mod_id, cid, status); -} - -int bt_mesh_cfg_mod_sub_overwrite(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t sub_addr, uint16_t mod_id, uint8_t *status) -{ - return mod_sub(OP_MOD_SUB_OVERWRITE, net_idx, addr, elem_addr, - sub_addr, mod_id, CID_NVAL, status); -} - -int bt_mesh_cfg_mod_sub_overwrite_vnd(uint16_t net_idx, uint16_t addr, - uint16_t elem_addr, uint16_t sub_addr, - uint16_t mod_id, uint16_t cid, uint8_t *status) -{ - if (cid == CID_NVAL) { - return -EINVAL; - } - - return mod_sub(OP_MOD_SUB_OVERWRITE, net_idx, addr, elem_addr, - sub_addr, mod_id, cid, status); -} - -static int mod_sub_va(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - const uint8_t label[16], uint16_t mod_id, uint16_t cid, - uint16_t *virt_addr, uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(DUMMY_2_BYTE_OP, 22); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct mod_sub_param param = { - .status = status, - .elem_addr = elem_addr, - .sub_addr = virt_addr, - .mod_id = mod_id, - .cid = cid, - }; - int err; - - err = cli_prepare(¶m, OP_MOD_SUB_STATUS); - if (err) { - goto done; - } - - BT_DBG("net_idx 0x%04x addr 0x%04x elem_addr 0x%04x label %s", - net_idx, addr, elem_addr, label); - BT_DBG("mod_id 0x%04x cid 0x%04x", mod_id, cid); - - bt_mesh_model_msg_init(msg, op); - net_buf_simple_add_le16(msg, elem_addr); - net_buf_simple_add_mem(msg, label, 16); - - if (cid != CID_NVAL) { - net_buf_simple_add_le16(msg, cid); - } - - net_buf_simple_add_le16(msg, mod_id); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_mod_sub_va_add(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - const uint8_t label[16], uint16_t mod_id, - uint16_t *virt_addr, uint8_t *status) -{ - return mod_sub_va(OP_MOD_SUB_VA_ADD, net_idx, addr, elem_addr, label, - mod_id, CID_NVAL, virt_addr, status); -} - -int bt_mesh_cfg_mod_sub_va_add_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - const uint8_t label[16], uint16_t mod_id, - uint16_t cid, uint16_t *virt_addr, uint8_t *status) -{ - if (cid == CID_NVAL) { - return -EINVAL; - } - - return mod_sub_va(OP_MOD_SUB_VA_ADD, net_idx, addr, elem_addr, label, - mod_id, cid, virt_addr, status); -} - -int bt_mesh_cfg_mod_sub_va_del(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - const uint8_t label[16], uint16_t mod_id, - uint16_t *virt_addr, uint8_t *status) -{ - return mod_sub_va(OP_MOD_SUB_VA_DEL, net_idx, addr, elem_addr, label, - mod_id, CID_NVAL, virt_addr, status); -} - -int bt_mesh_cfg_mod_sub_va_del_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - const uint8_t label[16], uint16_t mod_id, - uint16_t cid, uint16_t *virt_addr, uint8_t *status) -{ - if (cid == CID_NVAL) { - return -EINVAL; - } - - return mod_sub_va(OP_MOD_SUB_VA_DEL, net_idx, addr, elem_addr, label, - mod_id, cid, virt_addr, status); -} - -int bt_mesh_cfg_mod_sub_va_overwrite(uint16_t net_idx, uint16_t addr, - uint16_t elem_addr, const uint8_t label[16], - uint16_t mod_id, uint16_t *virt_addr, - uint8_t *status) -{ - return mod_sub_va(OP_MOD_SUB_VA_OVERWRITE, net_idx, addr, elem_addr, - label, mod_id, CID_NVAL, virt_addr, status); -} - -int bt_mesh_cfg_mod_sub_va_overwrite_vnd(uint16_t net_idx, uint16_t addr, - uint16_t elem_addr, const uint8_t label[16], - uint16_t mod_id, uint16_t cid, - uint16_t *virt_addr, uint8_t *status) -{ - if (cid == CID_NVAL) { - return -EINVAL; - } - - return mod_sub_va(OP_MOD_SUB_VA_OVERWRITE, net_idx, addr, elem_addr, - label, mod_id, cid, virt_addr, status); -} - -int bt_mesh_cfg_mod_sub_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint8_t *status, uint16_t *subs, - size_t *sub_cnt) -{ - return mod_member_list_get(OP_MOD_SUB_GET, OP_MOD_SUB_LIST, net_idx, - addr, elem_addr, mod_id, CID_NVAL, status, - subs, sub_cnt); -} - -int bt_mesh_cfg_mod_sub_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint16_t cid, uint8_t *status, - uint16_t *subs, size_t *sub_cnt) -{ - if (cid == CID_NVAL) { - return -EINVAL; - } - - return mod_member_list_get(OP_MOD_SUB_GET_VND, OP_MOD_SUB_LIST_VND, - net_idx, addr, elem_addr, mod_id, CID_NVAL, - status, subs, sub_cnt); -} - -static int mod_pub_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint16_t cid, - struct bt_mesh_cfg_mod_pub *pub, uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_PUB_GET, 6); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct mod_pub_param param = { - .mod_id = mod_id, - .cid = cid, - .elem_addr = elem_addr, - .status = status, - .pub = pub, - }; - int err; - - err = cli_prepare(¶m, OP_MOD_PUB_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_MOD_PUB_GET); - - net_buf_simple_add_le16(msg, elem_addr); - - if (cid != CID_NVAL) { - net_buf_simple_add_le16(msg, cid); - } - - net_buf_simple_add_le16(msg, mod_id); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_mod_pub_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, struct bt_mesh_cfg_mod_pub *pub, - uint8_t *status) -{ - return mod_pub_get(net_idx, addr, elem_addr, mod_id, CID_NVAL, - pub, status); -} - -int bt_mesh_cfg_mod_pub_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint16_t cid, - struct bt_mesh_cfg_mod_pub *pub, uint8_t *status) -{ - if (cid == CID_NVAL) { - return -EINVAL; - } - - return mod_pub_get(net_idx, addr, elem_addr, mod_id, cid, pub, status); -} - -static int mod_pub_set(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint16_t cid, - struct bt_mesh_cfg_mod_pub *pub, uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_PUB_SET, 13); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct mod_pub_param param = { - .mod_id = mod_id, - .cid = cid, - .elem_addr = elem_addr, - .status = status, - .pub = pub, - }; - int err; - - err = cli_prepare(¶m, OP_MOD_PUB_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_MOD_PUB_SET); - - net_buf_simple_add_le16(msg, elem_addr); - net_buf_simple_add_le16(msg, pub->addr); - net_buf_simple_add_le16(msg, (pub->app_idx & (pub->cred_flag << 12))); - net_buf_simple_add_u8(msg, pub->ttl); - net_buf_simple_add_u8(msg, pub->period); - net_buf_simple_add_u8(msg, pub->transmit); - - if (cid != CID_NVAL) { - net_buf_simple_add_le16(msg, cid); - } - - net_buf_simple_add_le16(msg, mod_id); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_mod_pub_set(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, struct bt_mesh_cfg_mod_pub *pub, - uint8_t *status) -{ - return mod_pub_set(net_idx, addr, elem_addr, mod_id, CID_NVAL, - pub, status); -} - -int bt_mesh_cfg_mod_pub_set_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint16_t cid, - struct bt_mesh_cfg_mod_pub *pub, uint8_t *status) -{ - if (cid == CID_NVAL) { - return -EINVAL; - } - - return mod_pub_set(net_idx, addr, elem_addr, mod_id, cid, pub, status); -} - -int bt_mesh_cfg_hb_sub_set(uint16_t net_idx, uint16_t addr, - struct bt_mesh_cfg_hb_sub *sub, uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_SUB_SET, 5); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct hb_sub_param param = { - .status = status, - .sub = sub, - }; - int err; - - err = cli_prepare(¶m, OP_HEARTBEAT_SUB_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_HEARTBEAT_SUB_SET); - net_buf_simple_add_le16(msg, sub->src); - net_buf_simple_add_le16(msg, sub->dst); - net_buf_simple_add_u8(msg, sub->period); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_hb_sub_get(uint16_t net_idx, uint16_t addr, - struct bt_mesh_cfg_hb_sub *sub, uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_SUB_GET, 0); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct hb_sub_param param = { - .status = status, - .sub = sub, - }; - int err; - - err = cli_prepare(¶m, OP_HEARTBEAT_SUB_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_HEARTBEAT_SUB_GET); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_hb_pub_set(uint16_t net_idx, uint16_t addr, - const struct bt_mesh_cfg_hb_pub *pub, uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_PUB_SET, 9); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV_REMOTE, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct hb_pub_param param = { - .status = status, - }; - int err; - - err = cli_prepare(¶m, OP_HEARTBEAT_PUB_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_HEARTBEAT_PUB_SET); - net_buf_simple_add_le16(msg, pub->dst); - net_buf_simple_add_u8(msg, pub->count); - net_buf_simple_add_u8(msg, pub->period); - net_buf_simple_add_u8(msg, pub->ttl); - net_buf_simple_add_le16(msg, pub->feat); - net_buf_simple_add_le16(msg, pub->net_idx); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_cfg_hb_pub_get(uint16_t net_idx, uint16_t addr, - struct bt_mesh_cfg_hb_pub *pub, uint8_t *status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_PUB_GET, 0); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BT_MESH_KEY_DEV, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct hb_pub_param param = { - .status = status, - .pub = pub, - }; - int err; - - err = cli_prepare(¶m, OP_HEARTBEAT_PUB_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_HEARTBEAT_PUB_GET); - - err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!status) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int32_t bt_mesh_cfg_cli_timeout_get(void) -{ - return msg_timeout; -} - -void bt_mesh_cfg_cli_timeout_set(int32_t timeout) -{ - msg_timeout = timeout; -} - -#endif -#endif \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cfg_srv.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cfg_srv.c deleted file mode 100644 index 14ada332a..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/cfg_srv.c +++ /dev/null @@ -1,2501 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG - -#include -#include -#include - -#include "../include/mesh/mesh.h" - -#include "mesh_priv.h" -#include "adv.h" -#include "app_keys.h" -#include "net.h" -#include "rpl.h" -#include "lpn.h" -#include "transport.h" -#include "heartbeat.h" -#include "crypto.h" -#include "access.h" -#include "beacon.h" -#include "proxy.h" -#include "foundation.h" -#include "friend.h" -#include "settings.h" -#include "cfg.h" - -void (*bt_mesh_app_key_cb_list[1]) (uint16_t app_idx, uint16_t net_idx, - enum bt_mesh_key_evt evt); - -static int comp_add_elem(struct os_mbuf *buf, struct bt_mesh_elem *elem, - bool primary) -{ - struct bt_mesh_model *mod; - int i; - - if (net_buf_simple_tailroom(buf) < - 4 + (elem->model_count * 2) + (elem->vnd_model_count * 4)) { - BT_ERR("Too large device composition"); - return -E2BIG; - } - - net_buf_simple_add_le16(buf, elem->loc); - - net_buf_simple_add_u8(buf, elem->model_count); - net_buf_simple_add_u8(buf, elem->vnd_model_count); - - for (i = 0; i < elem->model_count; i++) { - mod = &elem->models[i]; - net_buf_simple_add_le16(buf, mod->id); - } - - for (i = 0; i < elem->vnd_model_count; i++) { - mod = &elem->vnd_models[i]; - net_buf_simple_add_le16(buf, mod->vnd.company); - net_buf_simple_add_le16(buf, mod->vnd.id); - } - - return 0; -} - -static int comp_get_page_0(struct os_mbuf *buf) -{ - uint16_t feat = 0; - const struct bt_mesh_comp *comp; - int i; - - comp = bt_mesh_comp_get(); - - if ((MYNEWT_VAL(BLE_MESH_RELAY))) { - feat |= BT_MESH_FEAT_RELAY; - } - - if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY))) { - feat |= BT_MESH_FEAT_PROXY; - } - - if ((MYNEWT_VAL(BLE_MESH_FRIEND))) { - feat |= BT_MESH_FEAT_FRIEND; - } - - if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) { - feat |= BT_MESH_FEAT_LOW_POWER; - } - - net_buf_simple_add_le16(buf, comp->cid); - net_buf_simple_add_le16(buf, comp->pid); - net_buf_simple_add_le16(buf, comp->vid); - net_buf_simple_add_le16(buf, MYNEWT_VAL(BLE_MESH_CRPL)); - net_buf_simple_add_le16(buf, feat); - - for (i = 0; i < comp->elem_count; i++) { - int err; - - err = comp_add_elem(buf, &comp->elem[i], i == 0); - if (err) { - return err; - } - } - - return 0; -} - -static void dev_comp_data_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); - uint8_t page; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - page = net_buf_simple_pull_u8(buf); - if (page != 0U) { - BT_DBG("Composition page %u not available", page); - page = 0U; - } - - bt_mesh_model_msg_init(sdu, OP_DEV_COMP_DATA_STATUS); - - net_buf_simple_add_u8(sdu, page); - if (comp_get_page_0(sdu) < 0) { - BT_ERR("Unable to get composition page 0"); - goto done; - } - - if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) { - BT_ERR("Unable to send Device Composition Status response"); - } - -done: - os_mbuf_free_chain(sdu); -} - -static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, - struct os_mbuf *buf, bool *vnd) -{ - if (buf->om_len < 4) { - uint16_t id; - - id = net_buf_simple_pull_le16(buf); - - BT_DBG("ID 0x%04x addr 0x%04x", id, elem->addr); - - *vnd = false; - - return bt_mesh_model_find(elem, id); - } else { - uint16_t company, id; - - company = net_buf_simple_pull_le16(buf); - id = net_buf_simple_pull_le16(buf); - - BT_DBG("Company 0x%04x ID 0x%04x addr 0x%04x", company, id, - elem->addr); - - *vnd = true; - - return bt_mesh_model_find_vnd(elem, company, id); - } -} - -static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, - uint16_t app_idx, uint8_t cred_flag, uint8_t ttl, uint8_t period, - uint8_t retransmit, bool store) -{ - if (!model->pub) { - return STATUS_NVAL_PUB_PARAM; - } - - if (!(MYNEWT_VAL(BLE_MESH_LOW_POWER)) && cred_flag) { - return STATUS_FEAT_NOT_SUPP; - } - - if (!model->pub->update && period) { - return STATUS_NVAL_PUB_PARAM; - } - - if (pub_addr == BT_MESH_ADDR_UNASSIGNED) { - if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return STATUS_SUCCESS; - } - - model->pub->addr = BT_MESH_ADDR_UNASSIGNED; - model->pub->key = 0; - model->pub->cred = 0; - model->pub->ttl = 0; - model->pub->period = 0; - model->pub->retransmit = 0; - model->pub->count = 0; - - if (model->pub->update) { - k_delayed_work_cancel(&model->pub->timer); - } - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_store_mod_pub(model); - } - - return STATUS_SUCCESS; - } - - if (!bt_mesh_app_key_exists(app_idx)) { - return STATUS_INVALID_APPKEY; - } - -#if CONFIG_BT_MESH_LABEL_COUNT > 0 - if (BT_MESH_ADDR_IS_VIRTUAL(model->pub->addr)) { - uint8_t *uuid = bt_mesh_va_label_get(model->pub->addr); - - if (uuid) { - bt_mesh_va_del(uuid, NULL); - } - } -#endif - - model->pub->addr = pub_addr; - model->pub->key = app_idx; - model->pub->cred = cred_flag; - model->pub->ttl = ttl; - model->pub->period = period; - model->pub->retransmit = retransmit; - - if (model->pub->update) { - int32_t period_ms; - - period_ms = bt_mesh_model_pub_period_get(model); - BT_DBG("period %u ms", (unsigned) period_ms); - - if (period_ms > 0) { - k_delayed_work_submit(&model->pub->timer, period_ms); - } else { - k_delayed_work_cancel(&model->pub->timer); - } - } - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_store_mod_pub(model); - } - - return STATUS_SUCCESS; -} - -uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx) -{ - int i; - - BT_DBG("model %p key_idx 0x%03x", model, key_idx); - - if (!bt_mesh_app_key_exists(key_idx)) { - return STATUS_INVALID_APPKEY; - } - - for (i = 0; i < ARRAY_SIZE(model->keys); i++) { - /* Treat existing binding as success */ - if (model->keys[i] == key_idx) { - return STATUS_SUCCESS; - } - } - - for (i = 0; i < ARRAY_SIZE(model->keys); i++) { - if (model->keys[i] == BT_MESH_KEY_UNUSED) { - model->keys[i] = key_idx; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_bind(model); - } - - return STATUS_SUCCESS; - } - } - - return STATUS_INSUFF_RESOURCES; -} - -uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool store) -{ - int i; - - BT_DBG("model %p key_idx 0x%03x store %u", model, key_idx, store); - - if (!bt_mesh_app_key_exists(key_idx)) { - return STATUS_INVALID_APPKEY; - } - - for (i = 0; i < ARRAY_SIZE(model->keys); i++) { - if (model->keys[i] != key_idx) { - continue; - } - - model->keys[i] = BT_MESH_KEY_UNUSED; - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_store_mod_bind(model); - } - - if (model->pub && model->pub->key == key_idx) { - _mod_pub_set(model, BT_MESH_ADDR_UNASSIGNED, - 0, 0, 0, 0, 0, store); - } - } - - return STATUS_SUCCESS; -} - -static void send_app_key_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - uint8_t status, - uint16_t app_idx, uint16_t net_idx) -{ - struct os_mbuf *msg = NET_BUF_SIMPLE( - BT_MESH_MODEL_BUF_LEN(OP_APP_KEY_STATUS, 4)); - - bt_mesh_model_msg_init(msg, OP_APP_KEY_STATUS); - net_buf_simple_add_u8(msg, status); - key_idx_pack(msg, net_idx, app_idx); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send App Key Status response"); - } - - os_mbuf_free_chain(msg); -} - -static void app_key_add(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint16_t key_net_idx, key_app_idx; - uint8_t status; - - key_idx_unpack(buf, &key_net_idx, &key_app_idx); - - BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); - - status = bt_mesh_app_key_add(key_app_idx, key_net_idx, buf->om_data); - - send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); -} - -static void app_key_update(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint16_t key_net_idx, key_app_idx; - uint8_t status; - - key_idx_unpack(buf, &key_net_idx, &key_app_idx); - - BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); - - status = bt_mesh_app_key_update(key_app_idx, key_net_idx, buf->om_data); - BT_DBG("status 0x%02x", status); - send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); -} - -static void mod_app_key_del(struct bt_mesh_model *mod, - struct bt_mesh_elem *elem, bool vnd, bool primary, - void *user_data) -{ - uint16_t *app_idx = user_data; - - mod_unbind(mod, *app_idx, true); -} - -static void app_key_evt(uint16_t app_idx, uint16_t net_idx, - enum bt_mesh_key_evt evt) -{ - if (evt == BT_MESH_KEY_DELETED) { - bt_mesh_model_foreach(&mod_app_key_del, &app_idx); - } -} - -static void app_key_del(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint16_t key_net_idx, key_app_idx; - uint8_t status; - - key_idx_unpack(buf, &key_net_idx, &key_app_idx); - - BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); - - status = bt_mesh_app_key_del(key_app_idx, key_net_idx); - - send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); -} - -/* Index list length: 3 bytes for every pair and 2 bytes for an odd idx */ -#define IDX_LEN(num) (((num) / 2) * 3 + ((num) % 2) * 2) - -static void app_key_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = - BT_MESH_MODEL_BUF(OP_APP_KEY_LIST, - 3 + IDX_LEN(CONFIG_BT_MESH_APP_KEY_COUNT)); - uint16_t app_idx[CONFIG_BT_MESH_APP_KEY_COUNT]; - uint16_t get_idx; - uint8_t status; - ssize_t count; - int i; - - get_idx = net_buf_simple_pull_le16(buf); - if (get_idx > 0xfff) { - BT_ERR("Invalid NetKeyIndex 0x%04x", get_idx); - goto done; - } - - BT_DBG("idx 0x%04x", get_idx); - - bt_mesh_model_msg_init(msg, OP_APP_KEY_LIST); - - if (!bt_mesh_subnet_exists(get_idx)) { - status = STATUS_INVALID_NETKEY; - } else { - status = STATUS_SUCCESS; - } - - net_buf_simple_add_u8(msg, status); - net_buf_simple_add_le16(msg, get_idx); - - if (status != STATUS_SUCCESS) { - goto send_status; - } - - count = bt_mesh_app_keys_get(get_idx, app_idx, ARRAY_SIZE(app_idx), 0); - if (count < 0 || count > ARRAY_SIZE(app_idx)) { - count = ARRAY_SIZE(app_idx); - } - - for (i = 0; i < count - 1; i += 2) { - key_idx_pack(msg, app_idx[i], app_idx[i + 1]); - } - - if (i < count) { - net_buf_simple_add_le16(msg, app_idx[i]); - } - -send_status: - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send AppKey List"); - } - -done: - os_mbuf_free_chain(msg); -} - -static void beacon_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_BEACON_STATUS, 1); - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - bt_mesh_model_msg_init(msg, OP_BEACON_STATUS); - net_buf_simple_add_u8(msg, bt_mesh_beacon_enabled()); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Config Beacon Status response"); - } - os_mbuf_free_chain(msg); -} - -static void beacon_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_BEACON_STATUS, 1); - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) { - BT_WARN("Invalid Config Beacon value 0x%02x", buf->om_data[0]); - goto done; - } - - bt_mesh_beacon_set(buf->om_data[0]); - - bt_mesh_model_msg_init(msg, OP_BEACON_STATUS); - net_buf_simple_add_u8(msg, buf->om_data[0]); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Config Beacon Status response"); - } - -done: - os_mbuf_free_chain(msg); - -} - -static void default_ttl_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_DEFAULT_TTL_STATUS, 1); - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - bt_mesh_model_msg_init(msg, OP_DEFAULT_TTL_STATUS); - net_buf_simple_add_u8(msg, bt_mesh_default_ttl_get()); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Default TTL Status response"); - } - - os_mbuf_free_chain(msg); - -} - -static void default_ttl_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_DEFAULT_TTL_STATUS, 1); - int err; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - err = bt_mesh_default_ttl_set(buf->om_data[0]); - if (err) { - BT_WARN("Prohibited Default TTL value 0x%02x", buf->om_data[0]); - goto done; - } - - bt_mesh_model_msg_init(msg, OP_DEFAULT_TTL_STATUS); - net_buf_simple_add_u8(msg, buf->om_data[0]); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Default TTL Status response"); - } - -done: - os_mbuf_free_chain(msg); -} - -static void send_gatt_proxy_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_GATT_PROXY_STATUS, 1); - - bt_mesh_model_msg_init(msg, OP_GATT_PROXY_STATUS); - net_buf_simple_add_u8(msg, bt_mesh_gatt_proxy_get()); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send GATT Proxy Status"); - } - - os_mbuf_free_chain(msg); - -} - -static void gatt_proxy_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - send_gatt_proxy_status(model, ctx); -} - -static void gatt_proxy_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) { - BT_WARN("Invalid GATT Proxy value 0x%02x", buf->om_data[0]); - return; - } - - (void)bt_mesh_gatt_proxy_set(buf->om_data[0]); - - send_gatt_proxy_status(model, ctx); -} - -static void net_transmit_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_TRANSMIT_STATUS, 1); - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - bt_mesh_model_msg_init(msg, OP_NET_TRANSMIT_STATUS); - net_buf_simple_add_u8(msg, bt_mesh_net_transmit_get()); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Config Network Transmit Status"); - } - - os_mbuf_free_chain(msg); - -} - -static void net_transmit_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_TRANSMIT_STATUS, 1); - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - BT_DBG("Transmit 0x%02x (count %u interval %ums)", buf->om_data[0], - BT_MESH_TRANSMIT_COUNT(buf->om_data[0]), - BT_MESH_TRANSMIT_INT(buf->om_data[0])); - - bt_mesh_net_transmit_set(buf->om_data[0]); - - bt_mesh_model_msg_init(msg, OP_NET_TRANSMIT_STATUS); - net_buf_simple_add_u8(msg, buf->om_data[0]); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Network Transmit Status"); - } - - os_mbuf_free_chain(msg); -} - -static void relay_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_RELAY_STATUS, 2); - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - bt_mesh_model_msg_init(msg, OP_RELAY_STATUS); - net_buf_simple_add_u8(msg, bt_mesh_relay_get()); - net_buf_simple_add_u8(msg, bt_mesh_relay_retransmit_get()); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Config Relay Status response"); - } - - os_mbuf_free_chain(msg); - -} - -static void relay_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_RELAY_STATUS, 2); - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) { - BT_WARN("Invalid Relay value 0x%02x", buf->om_data[0]); - goto done; - } - - (void)bt_mesh_relay_set(buf->om_data[0], buf->om_data[1]); - - bt_mesh_model_msg_init(msg, OP_RELAY_STATUS); - net_buf_simple_add_u8(msg, bt_mesh_relay_get()); - net_buf_simple_add_u8(msg, bt_mesh_relay_retransmit_get()); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Relay Status response"); - } - -done: - os_mbuf_free_chain(msg); - -} - -static void send_mod_pub_status(struct bt_mesh_model *cfg_mod, - struct bt_mesh_msg_ctx *ctx, - uint16_t elem_addr, uint16_t pub_addr, - bool vnd, struct bt_mesh_model *mod, - uint8_t status, uint8_t *mod_id) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_PUB_STATUS, 14); - - bt_mesh_model_msg_init(msg, OP_MOD_PUB_STATUS); - - net_buf_simple_add_u8(msg, status); - net_buf_simple_add_le16(msg, elem_addr); - - if (status != STATUS_SUCCESS) { - memset(net_buf_simple_add(msg, 7), 0, 7); - } else { - uint16_t idx_cred; - - net_buf_simple_add_le16(msg, pub_addr); - - idx_cred = mod->pub->key | (uint16_t)mod->pub->cred << 12; - net_buf_simple_add_le16(msg, idx_cred); - net_buf_simple_add_u8(msg, mod->pub->ttl); - net_buf_simple_add_u8(msg, mod->pub->period); - net_buf_simple_add_u8(msg, mod->pub->retransmit); - } - - if (vnd) { - memcpy(net_buf_simple_add(msg, 4), mod_id, 4); - } else { - memcpy(net_buf_simple_add(msg, 2), mod_id, 2); - } - - if (bt_mesh_model_send(cfg_mod, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Model Publication Status"); - } - - os_mbuf_free_chain(msg); -} - -static void mod_pub_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint16_t elem_addr, pub_addr = 0; - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint8_t *mod_id, status; - bool vnd; - - elem_addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_WARN("Prohibited element address"); - return; - } - - mod_id = buf->om_data; - - BT_DBG("elem_addr 0x%04x", elem_addr); - - elem = bt_mesh_elem_find(elem_addr); - if (!elem) { - mod = NULL; - vnd = (buf->om_len == 4); - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - mod = get_model(elem, buf, &vnd); - if (!mod) { - status = STATUS_INVALID_MODEL; - goto send_status; - } - - if (!mod->pub) { - status = STATUS_NVAL_PUB_PARAM; - goto send_status; - } - - pub_addr = mod->pub->addr; - status = STATUS_SUCCESS; - -send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); -} - -static void mod_pub_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint8_t retransmit, status, pub_ttl, pub_period, cred_flag; - uint16_t elem_addr, pub_addr, pub_app_idx; - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint8_t *mod_id; - bool vnd; - - elem_addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_WARN("Prohibited element address"); - return; - } - - pub_addr = net_buf_simple_pull_le16(buf); - pub_app_idx = net_buf_simple_pull_le16(buf); - cred_flag = ((pub_app_idx >> 12) & BIT_MASK(1)); - pub_app_idx &= BIT_MASK(12); - - pub_ttl = net_buf_simple_pull_u8(buf); - if (pub_ttl > BT_MESH_TTL_MAX && pub_ttl != BT_MESH_TTL_DEFAULT) { - BT_ERR("Invalid TTL value 0x%02x", pub_ttl); - return; - } - - pub_period = net_buf_simple_pull_u8(buf); - retransmit = net_buf_simple_pull_u8(buf); - mod_id = buf->om_data; - - BT_DBG("elem_addr 0x%04x pub_addr 0x%04x cred_flag %u", - elem_addr, pub_addr, cred_flag); - BT_DBG("pub_app_idx 0x%03x, pub_ttl %u pub_period 0x%02x", - pub_app_idx, pub_ttl, pub_period); - BT_DBG("retransmit 0x%02x (count %u interval %ums)", retransmit, - BT_MESH_PUB_TRANSMIT_COUNT(retransmit), - BT_MESH_PUB_TRANSMIT_INT(retransmit)); - - elem = bt_mesh_elem_find(elem_addr); - if (!elem) { - mod = NULL; - vnd = (buf->om_len == 4); - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - mod = get_model(elem, buf, &vnd); - if (!mod) { - status = STATUS_INVALID_MODEL; - goto send_status; - } - - status = _mod_pub_set(mod, pub_addr, pub_app_idx, cred_flag, pub_ttl, - pub_period, retransmit, true); - -send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); -} - -static size_t mod_sub_list_clear(struct bt_mesh_model *mod) -{ - uint8_t *label_uuid; - size_t clear_count; - int i; - - /* Unref stored labels related to this model */ - for (i = 0, clear_count = 0; i < ARRAY_SIZE(mod->groups); i++) { - if (!BT_MESH_ADDR_IS_VIRTUAL(mod->groups[i])) { - if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { - mod->groups[i] = BT_MESH_ADDR_UNASSIGNED; - clear_count++; - } - - continue; - } - - label_uuid = bt_mesh_va_label_get(mod->groups[i]); - - mod->groups[i] = BT_MESH_ADDR_UNASSIGNED; - clear_count++; - - if (label_uuid) { - bt_mesh_va_del(label_uuid, NULL); - } else { - BT_ERR("Label UUID not found"); - } - } - - return clear_count; -} - -static void mod_pub_va_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint8_t retransmit, status, pub_ttl, pub_period, cred_flag; - uint16_t elem_addr, pub_addr, pub_app_idx; - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint8_t *label_uuid; - uint8_t *mod_id; - bool vnd; - - elem_addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_WARN("Prohibited element address"); - return; - } - - label_uuid = net_buf_simple_pull_mem(buf, 16); - pub_app_idx = net_buf_simple_pull_le16(buf); - cred_flag = ((pub_app_idx >> 12) & BIT_MASK(1)); - pub_app_idx &= BIT_MASK(12); - pub_ttl = net_buf_simple_pull_u8(buf); - if (pub_ttl > BT_MESH_TTL_MAX && pub_ttl != BT_MESH_TTL_DEFAULT) { - BT_ERR("Invalid TTL value 0x%02x", pub_ttl); - return; - } - - pub_period = net_buf_simple_pull_u8(buf); - retransmit = net_buf_simple_pull_u8(buf); - mod_id = buf->om_data; - - BT_DBG("elem_addr 0x%04x cred_flag %u", elem_addr, cred_flag); - BT_DBG("pub_app_idx 0x%03x, pub_ttl %u pub_period 0x%02x", - pub_app_idx, pub_ttl, pub_period); - BT_DBG("retransmit 0x%02x (count %u interval %ums)", retransmit, - BT_MESH_PUB_TRANSMIT_COUNT(retransmit), - BT_MESH_PUB_TRANSMIT_INT(retransmit)); - - elem = bt_mesh_elem_find(elem_addr); - if (!elem) { - mod = NULL; - vnd = (buf->om_len == 4); - pub_addr = 0; - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - mod = get_model(elem, buf, &vnd); - if (!mod) { - pub_addr = 0; - status = STATUS_INVALID_MODEL; - goto send_status; - } - - status = bt_mesh_va_add(label_uuid, &pub_addr); - if (status != STATUS_SUCCESS) { - goto send_status; - } - - status = _mod_pub_set(mod, pub_addr, pub_app_idx, cred_flag, pub_ttl, - pub_period, retransmit, true); - if (status != STATUS_SUCCESS) { - bt_mesh_va_del(label_uuid, NULL); - } - -send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); -} - -static void send_mod_sub_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, uint8_t status, - uint16_t elem_addr, uint16_t sub_addr, uint8_t *mod_id, - bool vnd) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_SUB_STATUS, 9); - - BT_DBG("status 0x%02x elem_addr 0x%04x sub_addr 0x%04x", status, - elem_addr, sub_addr); - - bt_mesh_model_msg_init(msg, OP_MOD_SUB_STATUS); - - net_buf_simple_add_u8(msg, status); - net_buf_simple_add_le16(msg, elem_addr); - net_buf_simple_add_le16(msg, sub_addr); - - if (vnd) { - memcpy(net_buf_simple_add(msg, 4), mod_id, 4); - } else { - memcpy(net_buf_simple_add(msg, 2), mod_id, 2); - } - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Model Subscription Status"); - } - - os_mbuf_free_chain(msg); -} - -static void mod_sub_add(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint16_t elem_addr, sub_addr; - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint8_t *mod_id; - uint8_t status; - uint16_t *entry; - bool vnd; - - elem_addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_WARN("Prohibited element address"); - return; - } - - sub_addr = net_buf_simple_pull_le16(buf); - - BT_DBG("elem_addr 0x%04x, sub_addr 0x%04x", elem_addr, sub_addr); - - mod_id = buf->om_data; - - elem = bt_mesh_elem_find(elem_addr); - if (!elem) { - mod = NULL; - vnd = (buf->om_len == 4); - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - mod = get_model(elem, buf, &vnd); - if (!mod) { - status = STATUS_INVALID_MODEL; - goto send_status; - } - - if (!BT_MESH_ADDR_IS_GROUP(sub_addr)) { - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - if (bt_mesh_model_find_group(&mod, sub_addr)) { - /* Tried to add existing subscription */ - BT_DBG("found existing subscription"); - status = STATUS_SUCCESS; - goto send_status; - } - - entry = bt_mesh_model_find_group(&mod, BT_MESH_ADDR_UNASSIGNED); - if (!entry) { - status = STATUS_INSUFF_RESOURCES; - goto send_status; - } - - *entry = sub_addr; - status = STATUS_SUCCESS; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); - } - - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_group_add(sub_addr); - } - - -send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); -} - -static void mod_sub_del(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint16_t elem_addr, sub_addr; - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint8_t *mod_id; - uint16_t *match; - uint8_t status; - bool vnd; - - elem_addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_WARN("Prohibited element address"); - return; - } - - sub_addr = net_buf_simple_pull_le16(buf); - - BT_DBG("elem_addr 0x%04x sub_addr 0x%04x", elem_addr, sub_addr); - - mod_id = buf->om_data; - - elem = bt_mesh_elem_find(elem_addr); - if (!elem) { - mod = NULL; - vnd = (buf->om_len == 4); - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - mod = get_model(elem, buf, &vnd); - if (!mod) { - status = STATUS_INVALID_MODEL; - goto send_status; - } - - if (!BT_MESH_ADDR_IS_GROUP(sub_addr)) { - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - /* An attempt to remove a non-existing address shall be treated - * as a success. - */ - status = STATUS_SUCCESS; - - if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) { - bt_mesh_lpn_group_del(&sub_addr, 1); - } - - match = bt_mesh_model_find_group(&mod, sub_addr); - if (match) { - *match = BT_MESH_ADDR_UNASSIGNED; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); - } - } - -send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); -} - -static enum bt_mesh_walk mod_sub_clear_visitor(struct bt_mesh_model *mod, - uint32_t depth, void *user_data) -{ - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups)); - } - - mod_sub_list_clear(mod); - - return BT_MESH_WALK_CONTINUE; -} - -static void mod_sub_overwrite(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint16_t elem_addr, sub_addr; - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint8_t *mod_id; - uint8_t status; - bool vnd; - - elem_addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_WARN("Prohibited element address"); - return; - } - - sub_addr = net_buf_simple_pull_le16(buf); - - BT_DBG("elem_addr 0x%04x sub_addr 0x%04x", elem_addr, sub_addr); - - mod_id = buf->om_data; - - elem = bt_mesh_elem_find(elem_addr); - if (!elem) { - mod = NULL; - vnd = (buf->om_len == 4); - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - mod = get_model(elem, buf, &vnd); - if (!mod) { - status = STATUS_INVALID_MODEL; - goto send_status; - } - - if (!BT_MESH_ADDR_IS_GROUP(sub_addr)) { - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - if (ARRAY_SIZE(mod->groups) > 0) { - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), - mod_sub_clear_visitor, NULL); - - mod->groups[0] = sub_addr; - status = STATUS_SUCCESS; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); - } - - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_group_add(sub_addr); - } - } else { - status = STATUS_INSUFF_RESOURCES; - } - - -send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); -} - -static void mod_sub_del_all(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint16_t elem_addr; - uint8_t *mod_id; - uint8_t status; - bool vnd; - - elem_addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_WARN("Prohibited element address"); - return; - } - - BT_DBG("elem_addr 0x%04x", elem_addr); - - mod_id = buf->om_data; - - elem = bt_mesh_elem_find(elem_addr); - if (!elem) { - mod = NULL; - vnd = (buf->om_len == 4); - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - mod = get_model(elem, buf, &vnd); - if (!mod) { - status = STATUS_INVALID_MODEL; - goto send_status; - } - - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_clear_visitor, - NULL); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); - } - - status = STATUS_SUCCESS; - -send_status: - send_mod_sub_status(model, ctx, status, elem_addr, - BT_MESH_ADDR_UNASSIGNED, mod_id, vnd); -} - -struct mod_sub_list_ctx { - uint16_t elem_idx; - struct os_mbuf *msg; -}; - -static enum bt_mesh_walk mod_sub_list_visitor(struct bt_mesh_model *mod, - uint32_t depth, void *ctx) -{ - struct mod_sub_list_ctx *visit = ctx; - int count = 0; - int i; - - if (mod->elem_idx != visit->elem_idx) { - return BT_MESH_WALK_CONTINUE; - } - - for (i = 0; i < ARRAY_SIZE(mod->groups); i++) { - if (mod->groups[i] == BT_MESH_ADDR_UNASSIGNED) { - continue; - } - - if (net_buf_simple_tailroom(visit->msg) < - 2 + BT_MESH_MIC_SHORT) { - BT_WARN("No room for all groups"); - return BT_MESH_WALK_STOP; - } - - net_buf_simple_add_le16(visit->msg, mod->groups[i]); - count++; - } - - BT_DBG("sublist: model %u:%x: %u groups", mod->elem_idx, mod->id, - count); - - return BT_MESH_WALK_CONTINUE; -} - -static void mod_sub_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); - struct mod_sub_list_ctx visit_ctx; - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint16_t addr, id; - - addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(addr)) { - BT_WARN("Prohibited element address"); - goto done; - } - - id = net_buf_simple_pull_le16(buf); - - BT_DBG("addr 0x%04x id 0x%04x", addr, id); - - bt_mesh_model_msg_init(msg, OP_MOD_SUB_LIST); - - elem = bt_mesh_elem_find(addr); - if (!elem) { - net_buf_simple_add_u8(msg, STATUS_INVALID_ADDRESS); - net_buf_simple_add_le16(msg, addr); - net_buf_simple_add_le16(msg, id); - goto send_list; - } - - mod = bt_mesh_model_find(elem, id); - if (!mod) { - net_buf_simple_add_u8(msg, STATUS_INVALID_MODEL); - net_buf_simple_add_le16(msg, addr); - net_buf_simple_add_le16(msg, id); - goto send_list; - } - - net_buf_simple_add_u8(msg, STATUS_SUCCESS); - - net_buf_simple_add_le16(msg, addr); - net_buf_simple_add_le16(msg, id); - - visit_ctx.msg = msg; - visit_ctx.elem_idx = mod->elem_idx; - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_list_visitor, - &visit_ctx); - -send_list: - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Model Subscription List"); - } - -done: - os_mbuf_free_chain(msg); - -} - -static void mod_sub_get_vnd(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); - struct mod_sub_list_ctx visit_ctx; - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint16_t company, addr, id; - - addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(addr)) { - BT_WARN("Prohibited element address"); - goto done; - } - - company = net_buf_simple_pull_le16(buf); - id = net_buf_simple_pull_le16(buf); - - BT_DBG("addr 0x%04x company 0x%04x id 0x%04x", addr, company, id); - - bt_mesh_model_msg_init(msg, OP_MOD_SUB_LIST_VND); - - elem = bt_mesh_elem_find(addr); - if (!elem) { - net_buf_simple_add_u8(msg, STATUS_INVALID_ADDRESS); - net_buf_simple_add_le16(msg, addr); - net_buf_simple_add_le16(msg, company); - net_buf_simple_add_le16(msg, id); - goto send_list; - } - - mod = bt_mesh_model_find_vnd(elem, company, id); - if (!mod) { - net_buf_simple_add_u8(msg, STATUS_INVALID_MODEL); - net_buf_simple_add_le16(msg, addr); - net_buf_simple_add_le16(msg, company); - net_buf_simple_add_le16(msg, id); - goto send_list; - } - - net_buf_simple_add_u8(msg, STATUS_SUCCESS); - - net_buf_simple_add_le16(msg, addr); - net_buf_simple_add_le16(msg, company); - net_buf_simple_add_le16(msg, id); - - visit_ctx.msg = msg; - visit_ctx.elem_idx = mod->elem_idx; - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_list_visitor, - &visit_ctx); - -send_list: - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Vendor Model Subscription List"); - } - -done: - os_mbuf_free_chain(msg); - -} - -static void mod_sub_va_add(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint16_t elem_addr, sub_addr; - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint8_t *label_uuid; - uint8_t *mod_id; - uint16_t *entry; - uint8_t status; - bool vnd; - - elem_addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_WARN("Prohibited element address"); - return; - } - - label_uuid = net_buf_simple_pull_mem(buf, 16); - - BT_DBG("elem_addr 0x%04x", elem_addr); - - mod_id = buf->om_data; - elem = bt_mesh_elem_find(elem_addr); - if (!elem) { - mod = NULL; - vnd = (buf->om_len == 4); - sub_addr = BT_MESH_ADDR_UNASSIGNED; - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - mod = get_model(elem, buf, &vnd); - if (!mod) { - sub_addr = BT_MESH_ADDR_UNASSIGNED; - status = STATUS_INVALID_MODEL; - goto send_status; - } - - status = bt_mesh_va_add(label_uuid, &sub_addr); - if (status != STATUS_SUCCESS) { - goto send_status; - } - - if (bt_mesh_model_find_group(&mod, sub_addr)) { - /* Tried to add existing subscription */ - status = STATUS_SUCCESS; - bt_mesh_va_del(label_uuid, NULL); - goto send_status; - } - - - entry = bt_mesh_model_find_group(&mod, BT_MESH_ADDR_UNASSIGNED); - if (!entry) { - status = STATUS_INSUFF_RESOURCES; - bt_mesh_va_del(label_uuid, NULL); - goto send_status; - } - - *entry = sub_addr; - - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_group_add(sub_addr); - } - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); - } - - status = STATUS_SUCCESS; - -send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); -} - -static void mod_sub_va_del(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint16_t elem_addr, sub_addr; - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint8_t *label_uuid; - uint8_t *mod_id; - uint16_t *match; - uint8_t status; - bool vnd; - - elem_addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_WARN("Prohibited element address"); - return; - } - - label_uuid = net_buf_simple_pull_mem(buf, 16); - - BT_DBG("elem_addr 0x%04x", elem_addr); - - mod_id = buf->om_data; - - elem = bt_mesh_elem_find(elem_addr); - if (!elem) { - mod = NULL; - vnd = (buf->om_len == 4); - sub_addr = BT_MESH_ADDR_UNASSIGNED; - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - mod = get_model(elem, buf, &vnd); - if (!mod) { - sub_addr = BT_MESH_ADDR_UNASSIGNED; - status = STATUS_INVALID_MODEL; - goto send_status; - } - - status = bt_mesh_va_del(label_uuid, &sub_addr); - if (sub_addr == BT_MESH_ADDR_UNASSIGNED) { - goto send_status; - } - - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_group_del(&sub_addr, 1); - } - - match = bt_mesh_model_find_group(&mod, sub_addr); - if (match) { - *match = BT_MESH_ADDR_UNASSIGNED; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); - } - - status = STATUS_SUCCESS; - } else { - status = STATUS_CANNOT_REMOVE; - } - -send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); -} - -static void mod_sub_va_overwrite(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint8_t *label_uuid; - uint8_t *mod_id; - uint8_t status; - bool vnd; - - elem_addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_WARN("Prohibited element address"); - return; - } - - label_uuid = net_buf_simple_pull_mem(buf, 16); - - BT_DBG("elem_addr 0x%04x", elem_addr); - - mod_id = buf->om_data; - - elem = bt_mesh_elem_find(elem_addr); - if (!elem) { - mod = NULL; - vnd = (buf->om_len == 4); - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - mod = get_model(elem, buf, &vnd); - if (!mod) { - status = STATUS_INVALID_MODEL; - goto send_status; - } - - if (ARRAY_SIZE(mod->groups) > 0) { - status = bt_mesh_va_add(label_uuid, &sub_addr); - if (status == STATUS_SUCCESS) { - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), - mod_sub_clear_visitor, NULL); - mod->groups[0] = sub_addr; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); - } - - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_group_add(sub_addr); - } - } - } else { - status = STATUS_INSUFF_RESOURCES; - } - -send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); -} - -static void send_net_key_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - uint16_t idx, uint8_t status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_KEY_STATUS, 3); - - bt_mesh_model_msg_init(msg, OP_NET_KEY_STATUS); - - net_buf_simple_add_u8(msg, status); - net_buf_simple_add_le16(msg, idx); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send NetKey Status"); - } - - os_mbuf_free_chain(msg); -} - -static void net_key_add(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint8_t status; - uint16_t idx; - - idx = net_buf_simple_pull_le16(buf); - if (idx > 0xfff) { - BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; - } - - BT_DBG("idx 0x%04x", idx); - - status = bt_mesh_subnet_add(idx, buf->om_data); - send_net_key_status(model, ctx, idx, status); -} - -static void net_key_update(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint8_t status; - uint16_t idx; - - idx = net_buf_simple_pull_le16(buf); - if (idx > 0xfff) { - BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; - } - - status = bt_mesh_subnet_update(idx, buf->om_data); - - send_net_key_status(model, ctx, idx, status); -} - -static void net_key_del(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint16_t del_idx; - - del_idx = net_buf_simple_pull_le16(buf); - if (del_idx > 0xfff) { - BT_ERR("Invalid NetKeyIndex 0x%04x", del_idx); - return; - } - - BT_DBG("idx 0x%04x", del_idx); - - /* The key that the message was encrypted with cannot be removed. - * The NetKey List must contain a minimum of one NetKey. - */ - if (ctx->net_idx == del_idx) { - send_net_key_status(model, ctx, del_idx, - STATUS_CANNOT_REMOVE); - return; - } - - bt_mesh_subnet_del(del_idx); - - send_net_key_status(model, ctx, del_idx, STATUS_SUCCESS); -} - -static void net_key_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = - BT_MESH_MODEL_BUF(OP_NET_KEY_LIST, - IDX_LEN(CONFIG_BT_MESH_SUBNET_COUNT)); - uint16_t net_idx[CONFIG_BT_MESH_SUBNET_COUNT]; - ssize_t count; - int i; - - bt_mesh_model_msg_init(msg, OP_NET_KEY_LIST); - - count = bt_mesh_subnets_get(net_idx, ARRAY_SIZE(net_idx), 0); - if (count < 0 || count > ARRAY_SIZE(net_idx)) { - count = ARRAY_SIZE(net_idx); - } - - for (i = 0; i < count - 1; i += 2) { - key_idx_pack(msg, net_idx[i], net_idx[i + 1]); - } - - if (i < count) { - net_buf_simple_add_le16(msg, net_idx[i]); - } - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send NetKey List"); - } - - os_mbuf_free_chain(msg); -} - -static void send_node_id_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - uint8_t status, - uint16_t net_idx, uint8_t node_id) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_IDENTITY_STATUS, 4); - - bt_mesh_model_msg_init(msg, OP_NODE_IDENTITY_STATUS); - net_buf_simple_add_u8(msg, status); - net_buf_simple_add_le16(msg, net_idx); - net_buf_simple_add_u8(msg, node_id); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Node Identity Status"); - } - - os_mbuf_free_chain(msg); -} - -static void node_identity_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - enum bt_mesh_feat_state node_id; - uint8_t status; - uint16_t idx; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - idx = net_buf_simple_pull_le16(buf); - if (idx > 0xfff) { - BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; - } - - status = bt_mesh_subnet_node_id_get(idx, &node_id); - - send_node_id_status(model, ctx, status, idx, node_id); -} - -static void node_identity_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint8_t node_id, status; - uint16_t idx; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - idx = net_buf_simple_pull_le16(buf); - if (idx > 0xfff) { - BT_WARN("Invalid NetKeyIndex 0x%04x", idx); - return; - } - - node_id = net_buf_simple_pull_u8(buf); - if (node_id != 0x00 && node_id != 0x01) { - BT_WARN("Invalid Node ID value 0x%02x", node_id); - return; - } - - status = bt_mesh_subnet_node_id_set(idx, node_id); - if (status == STATUS_INVALID_NETKEY) { - send_node_id_status(model, ctx, status, idx, - BT_MESH_NODE_IDENTITY_STOPPED); - return; - } - - if (status == STATUS_FEAT_NOT_SUPP) { - /* Should return success, even if feature isn't supported: */ - send_node_id_status(model, ctx, STATUS_SUCCESS, idx, - BT_MESH_NODE_IDENTITY_NOT_SUPPORTED); - return; - } - - send_node_id_status(model, ctx, status, idx, node_id); -} - -static void create_mod_app_status(struct os_mbuf *msg, - struct bt_mesh_model *mod, bool vnd, - uint16_t elem_addr, uint16_t app_idx, - uint8_t status, uint8_t *mod_id) -{ - bt_mesh_model_msg_init(msg, OP_MOD_APP_STATUS); - - net_buf_simple_add_u8(msg, status); - net_buf_simple_add_le16(msg, elem_addr); - net_buf_simple_add_le16(msg, app_idx); - - if (vnd) { - memcpy(net_buf_simple_add(msg, 4), mod_id, 4); - } else { - memcpy(net_buf_simple_add(msg, 2), mod_id, 2); - } -} - -static void mod_app_bind(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_APP_STATUS, 9); - uint16_t elem_addr, key_app_idx; - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint8_t *mod_id, status; - bool vnd; - - elem_addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_WARN("Prohibited element address"); - goto done; - } - - key_app_idx = net_buf_simple_pull_le16(buf); - mod_id = buf->om_data; - - elem = bt_mesh_elem_find(elem_addr); - if (!elem) { - mod = NULL; - vnd = (buf->om_len == 4); - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - mod = get_model(elem, buf, &vnd); - if (!mod) { - status = STATUS_INVALID_MODEL; - goto send_status; - } - - /* Configuration Server only allows device key based access */ - if (model == mod) { - BT_ERR("Client tried to bind AppKey to Configuration Model"); - status = STATUS_CANNOT_BIND; - goto send_status; - } - - status = mod_bind(mod, key_app_idx); - - if (IS_ENABLED(CONFIG_BT_TESTING) && status == STATUS_SUCCESS) { - bt_test_mesh_model_bound(ctx->addr, mod, key_app_idx); - } - -send_status: - BT_DBG("status 0x%02x", status); - create_mod_app_status(msg, mod, vnd, elem_addr, key_app_idx, status, - mod_id); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Model App Bind Status response"); - } - -done: - os_mbuf_free_chain(msg); - -} - -static void mod_app_unbind(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_APP_STATUS, 9); - uint16_t elem_addr, key_app_idx; - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint8_t *mod_id, status; - bool vnd; - - elem_addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_WARN("Prohibited element address"); - goto done; - } - - key_app_idx = net_buf_simple_pull_le16(buf); - mod_id = buf->om_data; - - elem = bt_mesh_elem_find(elem_addr); - if (!elem) { - mod = NULL; - vnd = (buf->om_len == 4); - status = STATUS_INVALID_ADDRESS; - goto send_status; - } - - mod = get_model(elem, buf, &vnd); - if (!mod) { - status = STATUS_INVALID_MODEL; - goto send_status; - } - - status = mod_unbind(mod, key_app_idx, true); - - if (IS_ENABLED(CONFIG_BT_TESTING) && status == STATUS_SUCCESS) { - bt_test_mesh_model_unbound(ctx->addr, mod, key_app_idx); - } - -send_status: - BT_DBG("status 0x%02x", status); - create_mod_app_status(msg, mod, vnd, elem_addr, key_app_idx, status, - mod_id); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Model App Unbind Status response"); - } - -done: - os_mbuf_free_chain(msg); -} - -#define KEY_LIST_LEN (MYNEWT_VAL(BLE_MESH_MODEL_KEY_COUNT) * 2) - -static void mod_app_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = NET_BUF_SIMPLE(max(BT_MESH_MODEL_BUF_LEN(OP_VND_MOD_APP_LIST, - 9 + KEY_LIST_LEN), - BT_MESH_MODEL_BUF_LEN(OP_SIG_MOD_APP_LIST, - 9 + KEY_LIST_LEN))); - - struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; - uint8_t *mod_id, status; - uint16_t elem_addr; - bool vnd; - - elem_addr = net_buf_simple_pull_le16(buf); - if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_WARN("Prohibited element address"); - goto done; - } - - mod_id = buf->om_data; - - BT_DBG("elem_addr 0x%04x", elem_addr); - - elem = bt_mesh_elem_find(elem_addr); - if (!elem) { - mod = NULL; - vnd = (buf->om_len == 4); - status = STATUS_INVALID_ADDRESS; - goto send_list; - } - - mod = get_model(elem, buf, &vnd); - if (!mod) { - status = STATUS_INVALID_MODEL; - goto send_list; - } - - status = STATUS_SUCCESS; - -send_list: - if (vnd) { - bt_mesh_model_msg_init(msg, OP_VND_MOD_APP_LIST); - } else { - bt_mesh_model_msg_init(msg, OP_SIG_MOD_APP_LIST); - } - - net_buf_simple_add_u8(msg, status); - net_buf_simple_add_le16(msg, elem_addr); - - if (vnd) { - net_buf_simple_add_mem(msg, mod_id, 4); - } else { - net_buf_simple_add_mem(msg, mod_id, 2); - } - - if (mod) { - int i; - - for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { - if (mod->keys[i] != BT_MESH_KEY_UNUSED) { - net_buf_simple_add_le16(msg, mod->keys[i]); - } - } - } - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Model Application List message"); - } - -done: - os_mbuf_free_chain(msg); -} - -static void node_reset(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - static struct bt_mesh_proxy_idle_cb proxy_idle = {.cb = bt_mesh_reset}; - - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_RESET_STATUS, 0); - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - - bt_mesh_model_msg_init(msg, OP_NODE_RESET_STATUS); - - /* Send the response first since we wont have any keys left to - * send it later. - */ - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Node Reset Status"); - } - - if (!IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - bt_mesh_reset(); - return; - } - - /* If the response goes to a proxy node, we'll wait for the sending to - * complete before moving on. - */ - bt_mesh_proxy_on_idle(&proxy_idle); - os_mbuf_free_chain(msg); -} - -static void send_friend_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_FRIEND_STATUS, 1); - - bt_mesh_model_msg_init(msg, OP_FRIEND_STATUS); - net_buf_simple_add_u8(msg, bt_mesh_friend_get()); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Friend Status"); - } - os_mbuf_free_chain(msg); -} - -static void friend_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - send_friend_status(model, ctx); -} - -static void friend_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) { - BT_WARN("Invalid Friend value 0x%02x", buf->om_data[0]); - return; - } - - (void)bt_mesh_friend_set(buf->om_data[0]); - - send_friend_status(model, ctx); -} - -static void lpn_timeout_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_LPN_TIMEOUT_STATUS, 5); - struct bt_mesh_friend *frnd; - uint16_t lpn_addr; - int32_t timeout; - - lpn_addr = net_buf_simple_pull_le16(buf); - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x lpn_addr 0x%02x", - ctx->net_idx, ctx->app_idx, ctx->addr, lpn_addr); - - /* check if it's the address of the Low Power Node? */ - if (!BT_MESH_ADDR_IS_UNICAST(lpn_addr)) { - BT_WARN("Invalid LPNAddress; ignoring msg"); - goto done; - } - - bt_mesh_model_msg_init(msg, OP_LPN_TIMEOUT_STATUS); - net_buf_simple_add_le16(msg, lpn_addr); - - if (!IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - timeout = 0; - goto send_rsp; - } - - frnd = bt_mesh_friend_find(BT_MESH_KEY_ANY, lpn_addr, true, true); - if (!frnd) { - timeout = 0; - goto send_rsp; - } - - timeout = k_delayed_work_remaining_get(&frnd->timer) / 100; - -send_rsp: - net_buf_simple_add_le24(msg, timeout); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send LPN PollTimeout Status"); - } - -done: - os_mbuf_free_chain(msg); -} - -static void send_krp_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - uint16_t idx, uint8_t phase, uint8_t status) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_KRP_STATUS, 4); - - bt_mesh_model_msg_init(msg, OP_KRP_STATUS); - - net_buf_simple_add_u8(msg, status); - net_buf_simple_add_le16(msg, idx); - net_buf_simple_add_u8(msg, phase); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Key Refresh State Status"); - } - - os_mbuf_free_chain(msg); -} - -static void krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint8_t kr_phase, status; - uint16_t idx; - - idx = net_buf_simple_pull_le16(buf); - if (idx > 0xfff) { - BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; - } - - BT_DBG("idx 0x%04x", idx); - - status = bt_mesh_subnet_kr_phase_get(idx, &kr_phase); - - send_krp_status(model, ctx, idx, kr_phase, status); -} - -static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint8_t phase, status; - uint16_t idx; - - idx = net_buf_simple_pull_le16(buf); - phase = net_buf_simple_pull_u8(buf); - - if (idx > 0xfff) { - BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; - } - - status = bt_mesh_subnet_kr_phase_set(idx, &phase); - if (status == STATUS_CANNOT_UPDATE) { - BT_ERR("Invalid kr phase transition 0x%02x", phase); - return; - } - - send_krp_status(model, ctx, idx, phase, status); -} - -static uint8_t hb_pub_count_log(uint16_t val) -{ - if (!val) { - return 0x00; - } else if (val == 0x01) { - return 0x01; - } else if (val == 0xffff) { - return 0xff; - } else { - return 32 - __builtin_clz(val - 1) + 1; - } -} - -struct hb_pub_param { - uint16_t dst; - uint8_t count_log; - uint8_t period_log; - uint8_t ttl; - uint16_t feat; - uint16_t net_idx; -} __packed; - -static void hb_pub_send_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, uint8_t status, - const struct bt_mesh_hb_pub *pub) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_PUB_STATUS, 10); - - BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status); - - bt_mesh_model_msg_init(msg, OP_HEARTBEAT_PUB_STATUS); - - net_buf_simple_add_u8(msg, status); - - net_buf_simple_add_le16(msg, pub->dst); - net_buf_simple_add_u8(msg, hb_pub_count_log(pub->count)); - net_buf_simple_add_u8(msg, bt_mesh_hb_log(pub->period)); - net_buf_simple_add_u8(msg, pub->ttl); - net_buf_simple_add_le16(msg, pub->feat); - net_buf_simple_add_le16(msg, pub->net_idx); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Heartbeat Publication Status"); - } - - os_mbuf_free_chain(msg); -} - -static void heartbeat_pub_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct bt_mesh_hb_pub pub; - - BT_DBG("src 0x%04x", ctx->addr); - - bt_mesh_hb_pub_get(&pub); - - hb_pub_send_status(model, ctx, STATUS_SUCCESS, &pub); -} - -static void heartbeat_pub_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct hb_pub_param *param = (void *)buf->om_data; - struct bt_mesh_hb_pub pub; - uint8_t status; - - BT_DBG("src 0x%04x", ctx->addr); - - pub.dst = sys_le16_to_cpu(param->dst); - pub.count = bt_mesh_hb_pwr2(param->count_log); - pub.period = bt_mesh_hb_pwr2(param->period_log); - pub.ttl = param->ttl; - pub.feat = sys_le16_to_cpu(param->feat); - pub.net_idx = sys_le16_to_cpu(param->net_idx); - - /* All other address types but virtual are valid */ - if (BT_MESH_ADDR_IS_VIRTUAL(pub.dst)) { - status = STATUS_INVALID_ADDRESS; - goto rsp; - } - - if (param->count_log > 0x11 && param->count_log != 0xff) { - status = STATUS_CANNOT_SET; - goto rsp; - } - - if (param->period_log > 0x10) { - status = STATUS_CANNOT_SET; - goto rsp; - } - - if (param->ttl > BT_MESH_TTL_MAX && param->ttl != BT_MESH_TTL_DEFAULT) { - BT_ERR("Invalid TTL value 0x%02x", param->ttl); - return; - } - - if (pub.net_idx > 0xfff) { - BT_ERR("Invalid NetKeyIndex 0x%04x", pub.net_idx); - return; - } - - status = bt_mesh_hb_pub_set(&pub); -rsp: - hb_pub_send_status(model, ctx, status, &pub); -} - -static void hb_sub_send_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - const struct bt_mesh_hb_sub *sub) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_SUB_STATUS, 9); - BT_DBG("src 0x%04x ", ctx->addr); - - bt_mesh_model_msg_init(msg, OP_HEARTBEAT_SUB_STATUS); - - net_buf_simple_add_u8(msg, STATUS_SUCCESS); - net_buf_simple_add_le16(msg, sub->src); - net_buf_simple_add_le16(msg, sub->dst); - net_buf_simple_add_u8(msg, bt_mesh_hb_log(sub->remaining)); - net_buf_simple_add_u8(msg, bt_mesh_hb_log(sub->count)); - net_buf_simple_add_u8(msg, sub->min_hops); - net_buf_simple_add_u8(msg, sub->max_hops); - - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Heartbeat Subscription Status"); - } - - os_mbuf_free_chain(msg); -} - -static void heartbeat_sub_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct bt_mesh_hb_sub sub; - - BT_DBG("src 0x%04x", ctx->addr); - - bt_mesh_hb_sub_get(&sub); - - hb_sub_send_status(model, ctx, &sub); -} - -static void heartbeat_sub_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint8_t period_log, status; - struct bt_mesh_hb_sub sub; - uint16_t sub_src, sub_dst; - uint32_t period; - - BT_DBG("src 0x%04x", ctx->addr); - - sub_src = net_buf_simple_pull_le16(buf); - sub_dst = net_buf_simple_pull_le16(buf); - period_log = net_buf_simple_pull_u8(buf); - - BT_DBG("sub_src 0x%04x sub_dst 0x%04x period 0x%02x", - sub_src, sub_dst, period_log); - - if (period_log > 0x11) { - BT_WARN("Prohibited subscription period 0x%02x", period_log); - return; - } - - period = bt_mesh_hb_pwr2(period_log); - - status = bt_mesh_hb_sub_set(sub_src, sub_dst, period); - if (status != STATUS_SUCCESS) { - /* All errors are caused by invalid packets, which should be - * ignored. - */ - return; - } - - bt_mesh_hb_sub_get(&sub); - - /* MESH/NODE/CFG/HBS/BV-01-C expects the MinHops to be 0x7f after - * disabling subscription, but 0x00 for subsequent Get requests. - */ - if (!period_log) { - sub.min_hops = BT_MESH_TTL_MAX; - } - - hb_sub_send_status(model, ctx, &sub); -} - -const struct bt_mesh_model_op bt_mesh_cfg_srv_op[] = { - { OP_DEV_COMP_DATA_GET, 1, dev_comp_data_get }, - { OP_APP_KEY_ADD, 19, app_key_add }, - { OP_APP_KEY_UPDATE, 19, app_key_update }, - { OP_APP_KEY_DEL, 3, app_key_del }, - { OP_APP_KEY_GET, 2, app_key_get }, - { OP_BEACON_GET, 0, beacon_get }, - { OP_BEACON_SET, 1, beacon_set }, - { OP_DEFAULT_TTL_GET, 0, default_ttl_get }, - { OP_DEFAULT_TTL_SET, 1, default_ttl_set }, - { OP_GATT_PROXY_GET, 0, gatt_proxy_get }, - { OP_GATT_PROXY_SET, 1, gatt_proxy_set }, - { OP_NET_TRANSMIT_GET, 0, net_transmit_get }, - { OP_NET_TRANSMIT_SET, 1, net_transmit_set }, - { OP_RELAY_GET, 0, relay_get }, - { OP_RELAY_SET, 2, relay_set }, - { OP_MOD_PUB_GET, 4, mod_pub_get }, - { OP_MOD_PUB_SET, 11, mod_pub_set }, - { OP_MOD_PUB_VA_SET, 24, mod_pub_va_set }, - { OP_MOD_SUB_ADD, 6, mod_sub_add }, - { OP_MOD_SUB_VA_ADD, 20, mod_sub_va_add }, - { OP_MOD_SUB_DEL, 6, mod_sub_del }, - { OP_MOD_SUB_VA_DEL, 20, mod_sub_va_del }, - { OP_MOD_SUB_OVERWRITE, 6, mod_sub_overwrite }, - { OP_MOD_SUB_VA_OVERWRITE, 20, mod_sub_va_overwrite }, - { OP_MOD_SUB_DEL_ALL, 4, mod_sub_del_all }, - { OP_MOD_SUB_GET, 4, mod_sub_get }, - { OP_MOD_SUB_GET_VND, 6, mod_sub_get_vnd }, - { OP_NET_KEY_ADD, 18, net_key_add }, - { OP_NET_KEY_UPDATE, 18, net_key_update }, - { OP_NET_KEY_DEL, 2, net_key_del }, - { OP_NET_KEY_GET, 0, net_key_get }, - { OP_NODE_IDENTITY_GET, 2, node_identity_get }, - { OP_NODE_IDENTITY_SET, 3, node_identity_set }, - { OP_MOD_APP_BIND, 6, mod_app_bind }, - { OP_MOD_APP_UNBIND, 6, mod_app_unbind }, - { OP_SIG_MOD_APP_GET, 4, mod_app_get }, - { OP_VND_MOD_APP_GET, 6, mod_app_get }, - { OP_NODE_RESET, 0, node_reset }, - { OP_FRIEND_GET, 0, friend_get }, - { OP_FRIEND_SET, 1, friend_set }, - { OP_LPN_TIMEOUT_GET, 2, lpn_timeout_get }, - { OP_KRP_GET, 2, krp_get }, - { OP_KRP_SET, 3, krp_set }, - { OP_HEARTBEAT_PUB_GET, 0, heartbeat_pub_get }, - { OP_HEARTBEAT_PUB_SET, 9, heartbeat_pub_set }, - { OP_HEARTBEAT_SUB_GET, 0, heartbeat_sub_get }, - { OP_HEARTBEAT_SUB_SET, 5, heartbeat_sub_set }, - BT_MESH_MODEL_OP_END, -}; - -static int cfg_srv_init(struct bt_mesh_model *model) -{ - bt_mesh_app_key_cb_list[0] = app_key_evt; - - BT_DBG(""); - - if (!bt_mesh_model_in_primary(model)) { - BT_ERR("Configuration Server only allowed in primary element"); - return -EINVAL; - } - - /* - * Configuration Model security is device-key based and only the local - * device-key is allowed to access this model. - */ - model->keys[0] = BT_MESH_KEY_DEV_LOCAL; - - return 0; -} - -const struct bt_mesh_model_cb bt_mesh_cfg_srv_cb = { - .init = cfg_srv_init, -}; - -static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, - bool vnd, bool primary, void *user_data) -{ - size_t clear_count; - - /* Clear model state that isn't otherwise cleared. E.g. AppKey - * binding and model publication is cleared as a consequence - * of removing all app keys, however model subscription and user data - * clearing must be taken care of here. - */ - - clear_count = mod_sub_list_clear(mod); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - if (clear_count) { - bt_mesh_store_mod_sub(mod); - } - } - - if (mod->cb && mod->cb->reset) { - mod->cb->reset(mod); - } -} - -void bt_mesh_cfg_reset(void) -{ - bt_mesh_model_foreach(mod_reset, NULL); -} -#endif \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/crypto.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/crypto.c deleted file mode 100644 index cc75f65f8..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/crypto.c +++ /dev/null @@ -1,607 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_CRYPTO_LOG - -#include -#include -#include - -#if (MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS)) -#include "mbedtls/aes.h" -#include "mbedtls/cipher.h" -#include "mbedtls/entropy.h" -#include "mbedtls/ctr_drbg.h" -#include "mbedtls/cmac.h" -#include "mbedtls/ecdh.h" -#include "mbedtls/ecp.h" - -#else -#include "nimble/ext/tinycrypt/include/tinycrypt/constants.h" -#include "nimble/ext/tinycrypt/include/tinycrypt/utils.h" -#include "nimble/ext/tinycrypt/include/tinycrypt/aes.h" -#include "nimble/ext/tinycrypt/include/tinycrypt/cmac_mode.h" -#include "nimble/ext/tinycrypt/include/tinycrypt/ccm_mode.h" -#endif - -#include "crypto.h" - -#define NET_MIC_LEN(pdu) (((pdu)[1] & 0x80) ? 8 : 4) -#define APP_MIC_LEN(aszmic) ((aszmic) ? 8 : 4) - -#if MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS) -int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg, - size_t sg_len, uint8_t mac[16]) -{ - int rc = BLE_HS_EUNKNOWN; - mbedtls_cipher_context_t ctx = {0}; - const mbedtls_cipher_info_t *cipher_info; - - mbedtls_cipher_init(&ctx); - - cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB); - if (cipher_info == NULL) { - goto exit; - } - - if (mbedtls_cipher_setup(&ctx, cipher_info) != 0) { - goto exit; - } - - rc = mbedtls_cipher_cmac_starts(&ctx, key, 128); - if (rc != 0) { - goto exit; - } - - for (; sg_len; sg_len--, sg++) { - if (sg->len != 0 && sg->data != NULL) { - if ((rc = mbedtls_cipher_cmac_update(&ctx, sg->data, sg->len)) != 0) { - goto exit; - } - } - } - rc = mbedtls_cipher_cmac_finish(&ctx, mac); - -exit: - mbedtls_cipher_free(&ctx); - if (rc != 0) { - return -EIO; - } - - return 0; -} - -#else -int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg, - size_t sg_len, uint8_t mac[16]) -{ - struct tc_aes_key_sched_struct sched; - struct tc_cmac_struct state; - - if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) { - return -EIO; - } - - for (; sg_len; sg_len--, sg++) { - if (tc_cmac_update(&state, sg->data, - sg->len) == TC_CRYPTO_FAIL) { - return -EIO; - } - } - - if (tc_cmac_final(mac, &state) == TC_CRYPTO_FAIL) { - return -EIO; - } - - return 0; -} -#endif - -int bt_mesh_k1(const uint8_t *ikm, size_t ikm_len, const uint8_t salt[16], - const char *info, uint8_t okm[16]) -{ - int err; - - err = bt_mesh_aes_cmac_one(salt, ikm, ikm_len, okm); - if (err < 0) { - return err; - } - - return bt_mesh_aes_cmac_one(okm, info, strlen(info), okm); -} - -int bt_mesh_k2(const uint8_t n[16], const uint8_t *p, size_t p_len, - uint8_t net_id[1], uint8_t enc_key[16], uint8_t priv_key[16]) -{ - struct bt_mesh_sg sg[3]; - uint8_t salt[16]; - uint8_t out[16]; - uint8_t t[16]; - uint8_t pad; - int err; - - BT_DBG("n %s", bt_hex(n, 16)); - BT_DBG("p %s", bt_hex(p, p_len)); - - err = bt_mesh_s1("smk2", salt); - if (err) { - return err; - } - - err = bt_mesh_aes_cmac_one(salt, n, 16, t); - if (err) { - return err; - } - - pad = 0x01; - - sg[0].data = NULL; - sg[0].len = 0; - sg[1].data = p; - sg[1].len = p_len; - sg[2].data = &pad; - sg[2].len = sizeof(pad); - - err = bt_mesh_aes_cmac(t, sg, ARRAY_SIZE(sg), out); - if (err) { - return err; - } - - net_id[0] = out[15] & 0x7f; - - sg[0].data = out; - sg[0].len = sizeof(out); - pad = 0x02; - - err = bt_mesh_aes_cmac(t, sg, ARRAY_SIZE(sg), out); - if (err) { - return err; - } - - memcpy(enc_key, out, 16); - - pad = 0x03; - - err = bt_mesh_aes_cmac(t, sg, ARRAY_SIZE(sg), out); - if (err) { - return err; - } - - memcpy(priv_key, out, 16); - - BT_DBG("NID 0x%02x enc_key %s", net_id[0], bt_hex(enc_key, 16)); - BT_DBG("priv_key %s", bt_hex(priv_key, 16)); - - return 0; -} - -int bt_mesh_k3(const uint8_t n[16], uint8_t out[8]) -{ - uint8_t id64[] = { 'i', 'd', '6', '4', 0x01 }; - uint8_t tmp[16]; - uint8_t t[16]; - int err; - - err = bt_mesh_s1("smk3", tmp); - if (err) { - return err; - } - - err = bt_mesh_aes_cmac_one(tmp, n, 16, t); - if (err) { - return err; - } - - err = bt_mesh_aes_cmac_one(t, id64, sizeof(id64), tmp); - if (err) { - return err; - } - - memcpy(out, tmp + 8, 8); - - return 0; -} - -int bt_mesh_k4(const uint8_t n[16], uint8_t out[1]) -{ - uint8_t id6[] = { 'i', 'd', '6', 0x01 }; - uint8_t tmp[16]; - uint8_t t[16]; - int err; - - err = bt_mesh_s1("smk4", tmp); - if (err) { - return err; - } - - err = bt_mesh_aes_cmac_one(tmp, n, 16, t); - if (err) { - return err; - } - - err = bt_mesh_aes_cmac_one(t, id6, sizeof(id6), tmp); - if (err) { - return err; - } - - out[0] = tmp[15] & BIT_MASK(6); - - return 0; -} - -int bt_mesh_id128(const uint8_t n[16], const char *s, uint8_t out[16]) -{ - const char *id128 = "id128\x01"; - uint8_t salt[16]; - int err; - - err = bt_mesh_s1(s, salt); - if (err) { - return err; - } - - return bt_mesh_k1(n, 16, salt, id128, out); -} - -static void create_proxy_nonce(uint8_t nonce[13], const uint8_t *pdu, - uint32_t iv_index) -{ - /* Nonce Type */ - nonce[0] = 0x03; - - /* Pad */ - nonce[1] = 0x00; - - /* Sequence Number */ - nonce[2] = pdu[2]; - nonce[3] = pdu[3]; - nonce[4] = pdu[4]; - - /* Source Address */ - nonce[5] = pdu[5]; - nonce[6] = pdu[6]; - - /* Pad */ - nonce[7] = 0; - nonce[8] = 0; - - /* IV Index */ - sys_put_be32(iv_index, &nonce[9]); -} - -static void create_net_nonce(uint8_t nonce[13], const uint8_t *pdu, - uint32_t iv_index) -{ - /* Nonce Type */ - nonce[0] = 0x00; - - /* FRND + TTL */ - nonce[1] = pdu[1]; - - /* Sequence Number */ - nonce[2] = pdu[2]; - nonce[3] = pdu[3]; - nonce[4] = pdu[4]; - - /* Source Address */ - nonce[5] = pdu[5]; - nonce[6] = pdu[6]; - - /* Pad */ - nonce[7] = 0; - nonce[8] = 0; - - /* IV Index */ - sys_put_be32(iv_index, &nonce[9]); -} - -int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index, - const uint8_t privacy_key[16]) -{ - uint8_t priv_rand[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, }; - uint8_t tmp[16]; - int err, i; - - BT_DBG("IVIndex %u, PrivacyKey %s", (unsigned) iv_index, - bt_hex(privacy_key, 16)); - - sys_put_be32(iv_index, &priv_rand[5]); - memcpy(&priv_rand[9], &pdu[7], 7); - - BT_DBG("PrivacyRandom %s", bt_hex(priv_rand, 16)); - - err = bt_encrypt_be(privacy_key, priv_rand, tmp); - if (err) { - return err; - } - - for (i = 0; i < 6; i++) { - pdu[1 + i] ^= tmp[i]; - } - - return 0; -} - -int bt_mesh_net_encrypt(const uint8_t key[16], struct os_mbuf *buf, - uint32_t iv_index, bool proxy) -{ - uint8_t mic_len = NET_MIC_LEN(buf->om_data); - uint8_t nonce[13]; - int err; - - BT_DBG("IVIndex %u EncKey %s mic_len %u", (unsigned) iv_index, - bt_hex(key, 16), mic_len); - BT_DBG("PDU (len %u) %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - - if (IS_ENABLED(CONFIG_BT_MESH_PROXY) && proxy) { - create_proxy_nonce(nonce, buf->om_data, iv_index); - } else { - create_net_nonce(nonce, buf->om_data, iv_index); - } - - BT_DBG("Nonce %s", bt_hex(nonce, 13)); - - err = bt_ccm_encrypt(key, nonce, &buf->om_data[7], buf->om_len - 7, - NULL, 0, &buf->om_data[7], mic_len); - if (!err) { - net_buf_simple_add(buf, mic_len); - } - - return err; -} - -int bt_mesh_net_decrypt(const uint8_t key[16], struct os_mbuf *buf, - uint32_t iv_index, bool proxy) -{ - uint8_t mic_len = NET_MIC_LEN(buf->om_data); - uint8_t nonce[13]; - - BT_DBG("PDU (%u bytes) %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - BT_DBG("iv_index %u, key %s mic_len %u", (unsigned) iv_index, - bt_hex(key, 16), mic_len); - - if (IS_ENABLED(CONFIG_BT_MESH_PROXY) && proxy) { - create_proxy_nonce(nonce, buf->om_data, iv_index); - } else { - create_net_nonce(nonce, buf->om_data, iv_index); - } - - BT_DBG("Nonce %s", bt_hex(nonce, 13)); - - buf->om_len -= mic_len; - - return bt_ccm_decrypt(key, nonce, &buf->om_data[7], buf->om_len - 7, - NULL, 0, &buf->om_data[7], mic_len); -} - -static void create_app_nonce(uint8_t nonce[13], - const struct bt_mesh_app_crypto_ctx *ctx) -{ - if (ctx->dev_key) { - nonce[0] = 0x02; - } else { - nonce[0] = 0x01; - } - - sys_put_be32((ctx->seq_num | ((uint32_t)ctx->aszmic << 31)), &nonce[1]); - - sys_put_be16(ctx->src, &nonce[5]); - sys_put_be16(ctx->dst, &nonce[7]); - - sys_put_be32(ctx->iv_index, &nonce[9]); -} - -int bt_mesh_app_encrypt(const uint8_t key[16], - const struct bt_mesh_app_crypto_ctx *ctx, - struct os_mbuf *buf) -{ - int err; - uint8_t nonce[13]; - - BT_DBG("AppKey %s", bt_hex(key, 16)); - BT_DBG("dev_key %u src 0x%04x dst 0x%04x", ctx->dev_key, ctx->src, - ctx->dst); - BT_DBG("seq_num 0x%08x iv_index 0x%08x", ctx->seq_num, ctx->iv_index); - BT_DBG("Clear: %s", bt_hex(buf->om_data, buf->om_len)); - - create_app_nonce(nonce, ctx); - - BT_DBG("Nonce %s", bt_hex(nonce, 13)); - - err = bt_ccm_encrypt(key, nonce, buf->om_data, buf->om_len, ctx->ad, - ctx->ad ? 16 : 0, buf->om_data, - APP_MIC_LEN(ctx->aszmic)); - - if (!err) { - net_buf_simple_add(buf, APP_MIC_LEN(ctx->aszmic)); - BT_DBG("Encr: %s", bt_hex(buf->om_data, buf->om_len)); - } - - return err; -} - -int bt_mesh_app_decrypt(const uint8_t key[16], - const struct bt_mesh_app_crypto_ctx *ctx, - struct os_mbuf *buf, struct os_mbuf *out) -{ - uint8_t nonce[13]; - int err; - - BT_DBG("EncData (len %u) %s", buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - create_app_nonce(nonce, ctx); - - BT_DBG("AppKey %s", bt_hex(key, 16)); - BT_DBG("Nonce %s", bt_hex(nonce, 13)); - - err = bt_ccm_decrypt(key, nonce, buf->om_data, buf->om_len, ctx->ad, - ctx->ad ? 16 : 0, out->om_data, - APP_MIC_LEN(ctx->aszmic)); - if (!err) { - net_buf_simple_add(out, buf->om_len); - } - - return err; -} - -/* reversed, 8-bit, poly=0x07 */ -static const uint8_t crc_table[256] = { - 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, - 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, - 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, - 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67, - - 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, - 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43, - 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, - 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f, - - 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, - 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b, - 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, - 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17, - - 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, - 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33, - 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, - 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f, - - 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, - 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b, - 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, - 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87, - - 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, - 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3, - 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, - 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf, - - 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, - 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb, - 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, - 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7, - - 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, - 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3, - 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, - 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf -}; - -uint8_t bt_mesh_fcs_calc(const uint8_t *data, uint8_t data_len) -{ - uint8_t fcs = 0xff; - - while (data_len--) { - fcs = crc_table[fcs ^ *data++]; - } - - BT_DBG("fcs 0x%02x", 0xff - fcs); - - return 0xff - fcs; -} - -bool bt_mesh_fcs_check(struct os_mbuf *buf, uint8_t received_fcs) -{ - const uint8_t *data = buf->om_data; - uint16_t data_len = buf->om_len; - uint8_t fcs = 0xff; - - while (data_len--) { - fcs = crc_table[fcs ^ *data++]; - } - - return crc_table[fcs ^ received_fcs] == 0xcf; -} - -int bt_mesh_virtual_addr(const uint8_t virtual_label[16], uint16_t *addr) -{ - uint8_t salt[16]; - uint8_t tmp[16]; - int err; - - err = bt_mesh_s1("vtad", salt); - if (err) { - return err; - } - - err = bt_mesh_aes_cmac_one(salt, virtual_label, 16, tmp); - if (err) { - return err; - } - - *addr = (sys_get_be16(&tmp[14]) & 0x3fff) | 0x8000; - - return 0; -} - -int bt_mesh_prov_conf_salt(const uint8_t conf_inputs[145], uint8_t salt[16]) -{ - const uint8_t conf_salt_key[16] = { 0 }; - - return bt_mesh_aes_cmac_one(conf_salt_key, conf_inputs, 145, salt); -} - -int bt_mesh_prov_conf_key(const uint8_t dhkey[32], const uint8_t conf_salt[16], - uint8_t conf_key[16]) -{ - return bt_mesh_k1(dhkey, 32, conf_salt, "prck", conf_key); -} - -int bt_mesh_prov_conf(const uint8_t conf_key[16], const uint8_t rand[16], - const uint8_t auth[16], uint8_t conf[16]) -{ - struct bt_mesh_sg sg[] = { { rand, 16 }, { auth, 16 } }; - - BT_DBG("ConfirmationKey %s", bt_hex(conf_key, 16)); - BT_DBG("RandomDevice %s", bt_hex(rand, 16)); - BT_DBG("AuthValue %s", bt_hex(auth, 16)); - - return bt_mesh_aes_cmac(conf_key, sg, ARRAY_SIZE(sg), conf); -} - -int bt_mesh_prov_decrypt(const uint8_t key[16], uint8_t nonce[13], - const uint8_t data[25 + 8], uint8_t out[25]) -{ - return bt_ccm_decrypt(key, nonce, data, 25, NULL, 0, out, 8); -} - -int bt_mesh_prov_encrypt(const uint8_t key[16], uint8_t nonce[13], - const uint8_t data[25], uint8_t out[25 + 8]) -{ - return bt_ccm_encrypt(key, nonce, data, 25, NULL, 0, out, 8); -} - -int bt_mesh_beacon_auth(const uint8_t beacon_key[16], uint8_t flags, - const uint8_t net_id[8], uint32_t iv_index, - uint8_t auth[8]) -{ - uint8_t msg[13], tmp[16]; - int err; - - BT_DBG("BeaconKey %s", bt_hex(beacon_key, 16)); - BT_DBG("NetId %s", bt_hex(net_id, 8)); - BT_DBG("IV Index 0x%08x", (unsigned) iv_index); - - msg[0] = flags; - memcpy(&msg[1], net_id, 8); - sys_put_be32(iv_index, &msg[9]); - - BT_DBG("BeaconMsg %s", bt_hex(msg, sizeof(msg))); - - err = bt_mesh_aes_cmac_one(beacon_key, msg, sizeof(msg), tmp); - if (!err) { - memcpy(auth, tmp, 8); - } - - return err; -} -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/crypto.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/crypto.h deleted file mode 100644 index 4fbbc119e..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/crypto.h +++ /dev/null @@ -1,171 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __CRYPTO_H__ -#define __CRYPTO_H__ - -#include "../include/mesh/mesh.h" - -struct bt_mesh_sg { - const void *data; - size_t len; -}; - -int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg, - size_t sg_len, uint8_t mac[16]); - -static inline int bt_mesh_aes_cmac_one(const uint8_t key[16], const void *m, - size_t len, uint8_t mac[16]) -{ - struct bt_mesh_sg sg = { m, len }; - - return bt_mesh_aes_cmac(key, &sg, 1, mac); -} - -static inline bool bt_mesh_s1(const char *m, uint8_t salt[16]) -{ - const uint8_t zero[16] = { 0 }; - - return bt_mesh_aes_cmac_one(zero, m, strlen(m), salt); -} - -int bt_mesh_k1(const uint8_t *ikm, size_t ikm_len, const uint8_t salt[16], - const char *info, uint8_t okm[16]); - -#define bt_mesh_k1_str(ikm, ikm_len, salt_str, info, okm) \ -({ \ - const uint8_t salt[16] = salt_str; \ - bt_mesh_k1(ikm, ikm_len, salt, info, okm); \ -}) - -int bt_mesh_k2(const uint8_t n[16], const uint8_t *p, size_t p_len, - uint8_t net_id[1], uint8_t enc_key[16], uint8_t priv_key[16]); - -int bt_mesh_k3(const uint8_t n[16], uint8_t out[8]); - -int bt_mesh_k4(const uint8_t n[16], uint8_t out[1]); - -int bt_mesh_id128(const uint8_t n[16], const char *s, uint8_t out[16]); - -static inline int bt_mesh_id_resolving_key(const uint8_t net_key[16], - uint8_t resolving_key[16]) -{ - return bt_mesh_k1_str(net_key, 16, "smbt", "smbi", resolving_key); -} - -static inline int bt_mesh_identity_key(const uint8_t net_key[16], - uint8_t identity_key[16]) -{ - return bt_mesh_id128(net_key, "nkik", identity_key); -} - -static inline int bt_mesh_beacon_key(const uint8_t net_key[16], - uint8_t beacon_key[16]) -{ - return bt_mesh_id128(net_key, "nkbk", beacon_key); -} - -int bt_mesh_beacon_auth(const uint8_t beacon_key[16], uint8_t flags, - const uint8_t net_id[8], uint32_t iv_index, - uint8_t auth[8]); - -static inline int bt_mesh_app_id(const uint8_t app_key[16], uint8_t app_id[1]) -{ - return bt_mesh_k4(app_key, app_id); -} - -static inline int bt_mesh_session_key(const uint8_t dhkey[32], - const uint8_t prov_salt[16], - uint8_t session_key[16]) -{ - return bt_mesh_k1(dhkey, 32, prov_salt, "prsk", session_key); -} - -static inline int bt_mesh_prov_nonce(const uint8_t dhkey[32], - const uint8_t prov_salt[16], - uint8_t nonce[13]) -{ - uint8_t tmp[16]; - int err; - - err = bt_mesh_k1(dhkey, 32, prov_salt, "prsn", tmp); - if (!err) { - memcpy(nonce, tmp + 3, 13); - } - - return err; -} - -static inline int bt_mesh_dev_key(const uint8_t dhkey[32], - const uint8_t prov_salt[16], - uint8_t dev_key[16]) -{ - return bt_mesh_k1(dhkey, 32, prov_salt, "prdk", dev_key); -} - -static inline int bt_mesh_prov_salt(const uint8_t conf_salt[16], - const uint8_t prov_rand[16], - const uint8_t dev_rand[16], - uint8_t prov_salt[16]) -{ - const uint8_t prov_salt_key[16] = { 0 }; - struct bt_mesh_sg sg[] = { - { conf_salt, 16 }, - { prov_rand, 16 }, - { dev_rand, 16 }, - }; - - return bt_mesh_aes_cmac(prov_salt_key, sg, ARRAY_SIZE(sg), prov_salt); -} - -int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index, - const uint8_t privacy_key[16]); - -int bt_mesh_net_encrypt(const uint8_t key[16], struct os_mbuf *buf, - uint32_t iv_index, bool proxy); - -int bt_mesh_net_decrypt(const uint8_t key[16], struct os_mbuf *buf, - uint32_t iv_index, bool proxy); - -struct bt_mesh_app_crypto_ctx { - bool dev_key; - uint8_t aszmic; - uint16_t src; - uint16_t dst; - uint32_t seq_num; - uint32_t iv_index; - const uint8_t *ad; -}; - -int bt_mesh_app_encrypt(const uint8_t key[16], - const struct bt_mesh_app_crypto_ctx *ctx, - struct os_mbuf *buf); - -int bt_mesh_app_decrypt(const uint8_t key[16], - const struct bt_mesh_app_crypto_ctx *ctx, - struct os_mbuf *buf, struct os_mbuf *out); - -uint8_t bt_mesh_fcs_calc(const uint8_t *data, uint8_t data_len); - -bool bt_mesh_fcs_check(struct os_mbuf *buf, uint8_t received_fcs); - -int bt_mesh_virtual_addr(const uint8_t virtual_label[16], uint16_t *addr); - -int bt_mesh_prov_conf_salt(const uint8_t conf_inputs[145], uint8_t salt[16]); - -int bt_mesh_prov_conf_key(const uint8_t dhkey[32], const uint8_t conf_salt[16], - uint8_t conf_key[16]); - -int bt_mesh_prov_conf(const uint8_t conf_key[16], const uint8_t rand[16], - const uint8_t auth[16], uint8_t conf[16]); - -int bt_mesh_prov_decrypt(const uint8_t key[16], uint8_t nonce[13], - const uint8_t data[25 + 8], uint8_t out[25]); - -int bt_mesh_prov_encrypt(const uint8_t key[16], uint8_t nonce[13], - const uint8_t data[25], uint8_t out[25 + 8]); -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/foundation.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/foundation.h deleted file mode 100644 index 012afbbb0..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/foundation.h +++ /dev/null @@ -1,137 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __FUNDATION_H__ -#define __FUNDATION_H__ - -#define OP_APP_KEY_ADD BT_MESH_MODEL_OP_1(0x00) -#define OP_APP_KEY_UPDATE BT_MESH_MODEL_OP_1(0x01) -#define OP_DEV_COMP_DATA_STATUS BT_MESH_MODEL_OP_1(0x02) -#define OP_MOD_PUB_SET BT_MESH_MODEL_OP_1(0x03) -#define OP_HEALTH_CURRENT_STATUS BT_MESH_MODEL_OP_1(0x04) -#define OP_HEALTH_FAULT_STATUS BT_MESH_MODEL_OP_1(0x05) -#define OP_HEARTBEAT_PUB_STATUS BT_MESH_MODEL_OP_1(0x06) -#define OP_APP_KEY_DEL BT_MESH_MODEL_OP_2(0x80, 0x00) -#define OP_APP_KEY_GET BT_MESH_MODEL_OP_2(0x80, 0x01) -#define OP_APP_KEY_LIST BT_MESH_MODEL_OP_2(0x80, 0x02) -#define OP_APP_KEY_STATUS BT_MESH_MODEL_OP_2(0x80, 0x03) -#define OP_ATTENTION_GET BT_MESH_MODEL_OP_2(0x80, 0x04) -#define OP_ATTENTION_SET BT_MESH_MODEL_OP_2(0x80, 0x05) -#define OP_ATTENTION_SET_UNREL BT_MESH_MODEL_OP_2(0x80, 0x06) -#define OP_ATTENTION_STATUS BT_MESH_MODEL_OP_2(0x80, 0x07) -#define OP_DEV_COMP_DATA_GET BT_MESH_MODEL_OP_2(0x80, 0x08) -#define OP_BEACON_GET BT_MESH_MODEL_OP_2(0x80, 0x09) -#define OP_BEACON_SET BT_MESH_MODEL_OP_2(0x80, 0x0a) -#define OP_BEACON_STATUS BT_MESH_MODEL_OP_2(0x80, 0x0b) -#define OP_DEFAULT_TTL_GET BT_MESH_MODEL_OP_2(0x80, 0x0c) -#define OP_DEFAULT_TTL_SET BT_MESH_MODEL_OP_2(0x80, 0x0d) -#define OP_DEFAULT_TTL_STATUS BT_MESH_MODEL_OP_2(0x80, 0x0e) -#define OP_FRIEND_GET BT_MESH_MODEL_OP_2(0x80, 0x0f) -#define OP_FRIEND_SET BT_MESH_MODEL_OP_2(0x80, 0x10) -#define OP_FRIEND_STATUS BT_MESH_MODEL_OP_2(0x80, 0x11) -#define OP_GATT_PROXY_GET BT_MESH_MODEL_OP_2(0x80, 0x12) -#define OP_GATT_PROXY_SET BT_MESH_MODEL_OP_2(0x80, 0x13) -#define OP_GATT_PROXY_STATUS BT_MESH_MODEL_OP_2(0x80, 0x14) -#define OP_KRP_GET BT_MESH_MODEL_OP_2(0x80, 0x15) -#define OP_KRP_SET BT_MESH_MODEL_OP_2(0x80, 0x16) -#define OP_KRP_STATUS BT_MESH_MODEL_OP_2(0x80, 0x17) -#define OP_MOD_PUB_GET BT_MESH_MODEL_OP_2(0x80, 0x18) -#define OP_MOD_PUB_STATUS BT_MESH_MODEL_OP_2(0x80, 0x19) -#define OP_MOD_PUB_VA_SET BT_MESH_MODEL_OP_2(0x80, 0x1a) -#define OP_MOD_SUB_ADD BT_MESH_MODEL_OP_2(0x80, 0x1b) -#define OP_MOD_SUB_DEL BT_MESH_MODEL_OP_2(0x80, 0x1c) -#define OP_MOD_SUB_DEL_ALL BT_MESH_MODEL_OP_2(0x80, 0x1d) -#define OP_MOD_SUB_OVERWRITE BT_MESH_MODEL_OP_2(0x80, 0x1e) -#define OP_MOD_SUB_STATUS BT_MESH_MODEL_OP_2(0x80, 0x1f) -#define OP_MOD_SUB_VA_ADD BT_MESH_MODEL_OP_2(0x80, 0x20) -#define OP_MOD_SUB_VA_DEL BT_MESH_MODEL_OP_2(0x80, 0x21) -#define OP_MOD_SUB_VA_OVERWRITE BT_MESH_MODEL_OP_2(0x80, 0x22) -#define OP_NET_TRANSMIT_GET BT_MESH_MODEL_OP_2(0x80, 0x23) -#define OP_NET_TRANSMIT_SET BT_MESH_MODEL_OP_2(0x80, 0x24) -#define OP_NET_TRANSMIT_STATUS BT_MESH_MODEL_OP_2(0x80, 0x25) -#define OP_RELAY_GET BT_MESH_MODEL_OP_2(0x80, 0x26) -#define OP_RELAY_SET BT_MESH_MODEL_OP_2(0x80, 0x27) -#define OP_RELAY_STATUS BT_MESH_MODEL_OP_2(0x80, 0x28) -#define OP_MOD_SUB_GET BT_MESH_MODEL_OP_2(0x80, 0x29) -#define OP_MOD_SUB_LIST BT_MESH_MODEL_OP_2(0x80, 0x2a) -#define OP_MOD_SUB_GET_VND BT_MESH_MODEL_OP_2(0x80, 0x2b) -#define OP_MOD_SUB_LIST_VND BT_MESH_MODEL_OP_2(0x80, 0x2c) -#define OP_LPN_TIMEOUT_GET BT_MESH_MODEL_OP_2(0x80, 0x2d) -#define OP_LPN_TIMEOUT_STATUS BT_MESH_MODEL_OP_2(0x80, 0x2e) -#define OP_HEALTH_FAULT_CLEAR BT_MESH_MODEL_OP_2(0x80, 0x2f) -#define OP_HEALTH_FAULT_CLEAR_UNREL BT_MESH_MODEL_OP_2(0x80, 0x30) -#define OP_HEALTH_FAULT_GET BT_MESH_MODEL_OP_2(0x80, 0x31) -#define OP_HEALTH_FAULT_TEST BT_MESH_MODEL_OP_2(0x80, 0x32) -#define OP_HEALTH_FAULT_TEST_UNREL BT_MESH_MODEL_OP_2(0x80, 0x33) -#define OP_HEALTH_PERIOD_GET BT_MESH_MODEL_OP_2(0x80, 0x34) -#define OP_HEALTH_PERIOD_SET BT_MESH_MODEL_OP_2(0x80, 0x35) -#define OP_HEALTH_PERIOD_SET_UNREL BT_MESH_MODEL_OP_2(0x80, 0x36) -#define OP_HEALTH_PERIOD_STATUS BT_MESH_MODEL_OP_2(0x80, 0x37) -#define OP_HEARTBEAT_PUB_GET BT_MESH_MODEL_OP_2(0x80, 0x38) -#define OP_HEARTBEAT_PUB_SET BT_MESH_MODEL_OP_2(0x80, 0x39) -#define OP_HEARTBEAT_SUB_GET BT_MESH_MODEL_OP_2(0x80, 0x3a) -#define OP_HEARTBEAT_SUB_SET BT_MESH_MODEL_OP_2(0x80, 0x3b) -#define OP_HEARTBEAT_SUB_STATUS BT_MESH_MODEL_OP_2(0x80, 0x3c) -#define OP_MOD_APP_BIND BT_MESH_MODEL_OP_2(0x80, 0x3d) -#define OP_MOD_APP_STATUS BT_MESH_MODEL_OP_2(0x80, 0x3e) -#define OP_MOD_APP_UNBIND BT_MESH_MODEL_OP_2(0x80, 0x3f) -#define OP_NET_KEY_ADD BT_MESH_MODEL_OP_2(0x80, 0x40) -#define OP_NET_KEY_DEL BT_MESH_MODEL_OP_2(0x80, 0x41) -#define OP_NET_KEY_GET BT_MESH_MODEL_OP_2(0x80, 0x42) -#define OP_NET_KEY_LIST BT_MESH_MODEL_OP_2(0x80, 0x43) -#define OP_NET_KEY_STATUS BT_MESH_MODEL_OP_2(0x80, 0x44) -#define OP_NET_KEY_UPDATE BT_MESH_MODEL_OP_2(0x80, 0x45) -#define OP_NODE_IDENTITY_GET BT_MESH_MODEL_OP_2(0x80, 0x46) -#define OP_NODE_IDENTITY_SET BT_MESH_MODEL_OP_2(0x80, 0x47) -#define OP_NODE_IDENTITY_STATUS BT_MESH_MODEL_OP_2(0x80, 0x48) -#define OP_NODE_RESET BT_MESH_MODEL_OP_2(0x80, 0x49) -#define OP_NODE_RESET_STATUS BT_MESH_MODEL_OP_2(0x80, 0x4a) -#define OP_SIG_MOD_APP_GET BT_MESH_MODEL_OP_2(0x80, 0x4b) -#define OP_SIG_MOD_APP_LIST BT_MESH_MODEL_OP_2(0x80, 0x4c) -#define OP_VND_MOD_APP_GET BT_MESH_MODEL_OP_2(0x80, 0x4d) -#define OP_VND_MOD_APP_LIST BT_MESH_MODEL_OP_2(0x80, 0x4e) - -#define STATUS_SUCCESS 0x00 -#define STATUS_INVALID_ADDRESS 0x01 -#define STATUS_INVALID_MODEL 0x02 -#define STATUS_INVALID_APPKEY 0x03 -#define STATUS_INVALID_NETKEY 0x04 -#define STATUS_INSUFF_RESOURCES 0x05 -#define STATUS_IDX_ALREADY_STORED 0x06 -#define STATUS_NVAL_PUB_PARAM 0x07 -#define STATUS_NOT_SUB_MOD 0x08 -#define STATUS_STORAGE_FAIL 0x09 -#define STATUS_FEAT_NOT_SUPP 0x0a -#define STATUS_CANNOT_UPDATE 0x0b -#define STATUS_CANNOT_REMOVE 0x0c -#define STATUS_CANNOT_BIND 0x0d -#define STATUS_TEMP_STATE_CHG_FAIL 0x0e -#define STATUS_CANNOT_SET 0x0f -#define STATUS_UNSPECIFIED 0x10 -#define STATUS_INVALID_BINDING 0x11 - -void bt_mesh_cfg_reset(void); - -void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time); - -static inline void key_idx_pack(struct os_mbuf *buf, - uint16_t idx1, uint16_t idx2) -{ - net_buf_simple_add_le16(buf, idx1 | ((idx2 & 0x00f) << 12)); - net_buf_simple_add_u8(buf, idx2 >> 4); -} - -static inline void key_idx_unpack(struct os_mbuf *buf, - uint16_t *idx1, uint16_t *idx2) -{ - *idx1 = sys_get_le16(&buf->om_data[0]) & 0xfff; - *idx2 = sys_get_le16(&buf->om_data[1]) >> 4; - net_buf_simple_pull_mem(buf, 3); -} - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/friend.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/friend.c deleted file mode 100644 index d15d3bbe5..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/friend.c +++ /dev/null @@ -1,1745 +0,0 @@ - /* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_FRIEND_LOG - -#if MYNEWT_VAL(BLE_MESH_FRIEND) - -#include -#include -#include - -#include "../include/mesh/mesh.h" -#include "../include/mesh/slist.h" -#include "../include/mesh_priv.h" -#include "crypto.h" -#include "adv.h" -#include "net.h" -#include "app_keys.h" -#include "transport.h" -#include "access.h" -#include "foundation.h" -#include "friend.h" -#include "subnet.h" - -/* We reserve one extra buffer for each friendship, since we need to be able - * to resend the last sent PDU, which sits separately outside of the queue. - */ -#define FRIEND_BUF_COUNT ((MYNEWT_VAL(BLE_MESH_FRIEND_QUEUE_SIZE) + 1) * MYNEWT_VAL(BLE_MESH_FRIEND_LPN_COUNT)) - -static os_membuf_t friend_buf_mem[OS_MEMPOOL_SIZE( - FRIEND_BUF_COUNT, - BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE)]; - -struct os_mbuf_pool friend_os_mbuf_pool; -static struct os_mempool friend_buf_mempool; - -#define NET_BUF_FRAGS BIT(0) - -#define FRIEND_ADV(buf) CONTAINER_OF(BT_MESH_ADV(buf), struct friend_adv, adv) - -/* PDUs from Friend to the LPN should only be transmitted once with the - * smallest possible interval (20ms). - */ -#define FRIEND_XMIT BT_MESH_TRANSMIT(0, 20) - -struct friend_pdu_info { - uint16_t src; - uint16_t dst; - - uint8_t seq[3]; - - uint8_t ttl:7, - ctl:1; - - uint32_t iv_index; -}; - -static struct friend_adv { - struct bt_mesh_adv adv; - uint16_t app_idx; -} adv_pool[FRIEND_BUF_COUNT]; - -static struct bt_mesh_adv *adv_alloc(int id) -{ - adv_pool[id].app_idx = BT_MESH_KEY_UNUSED; - return &adv_pool[id].adv; -} - -static bool is_lpn_unicast(struct bt_mesh_friend *frnd, uint16_t addr) -{ - if (frnd->lpn == BT_MESH_ADDR_UNASSIGNED) { - return false; - } - - return (addr >= frnd->lpn && addr < (frnd->lpn + frnd->num_elem)); -} - -struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr, - bool valid, bool established) -{ - int i; - - BT_DBG("net_idx 0x%04x lpn_addr 0x%04x", net_idx, lpn_addr); - - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { - struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - - if (valid && !frnd->subnet) { - continue; - } - - if (established && !frnd->established) { - continue; - } - - if (net_idx != BT_MESH_KEY_ANY && - (!frnd->subnet || frnd->subnet->net_idx != net_idx)) { - continue; - } - - if (is_lpn_unicast(frnd, lpn_addr)) { - return frnd; - } - } - - return NULL; -} - -static int friend_cred_create(struct bt_mesh_friend *frnd, uint8_t idx) -{ - return bt_mesh_friend_cred_create(&frnd->cred[idx], frnd->lpn, - bt_mesh_primary_addr(), - frnd->lpn_counter, frnd->counter, - frnd->subnet->keys[idx].net); -} - -static void purge_buffers(struct net_buf_slist_t *list) -{ - while (!net_buf_slist_is_empty(list)) { - struct os_mbuf *buf; - buf = (void *)net_buf_slist_get(list); - BT_MESH_ADV(buf)->flags &= ~NET_BUF_FRAGS; - net_buf_unref(buf); - } -} - -/* Intentionally start a little bit late into the ReceiveWindow when - * it's large enough. This may improve reliability with some platforms, - * like the PTS, where the receiver might not have sufficiently compensated - * for internal latencies required to start scanning. - */ -static int32_t recv_delay(struct bt_mesh_friend *frnd) -{ -#if CONFIG_BT_MESH_FRIEND_RECV_WIN > 50 - return (int32_t)frnd->recv_delay + (CONFIG_BT_MESH_FRIEND_RECV_WIN / 5); -#else - return frnd->recv_delay; -#endif -} - -static void friend_clear(struct bt_mesh_friend *frnd) -{ - int i; - - BT_DBG("LPN 0x%04x", frnd->lpn); - - k_delayed_work_cancel(&frnd->timer); - - memset(frnd->cred, 0, sizeof(frnd->cred)); - - if (frnd->last) { - /* Cancel the sending if necessary */ - if (frnd->pending_buf) { - BT_MESH_ADV(frnd->last)->busy = 0; - } - - net_buf_unref(frnd->last); - frnd->last = NULL; - } - - purge_buffers(&frnd->queue); - - for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) { - struct bt_mesh_friend_seg *seg = &frnd->seg[i]; - - purge_buffers(&seg->queue); - seg->seg_count = 0U; - } - - frnd->counter++; - frnd->subnet = NULL; - frnd->established = 0; - frnd->pending_buf = 0; - frnd->fsn = 0; - frnd->queue_size = 0; - frnd->pending_req = 0; - memset(frnd->sub_list, 0, sizeof(frnd->sub_list)); -} - -void bt_mesh_friends_clear(void) -{ - int i; - - BT_DBG(""); - - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { - struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - - if (!frnd->subnet) { - continue; - } - - friend_clear(frnd); - } -} - -static void enqueue_update(struct bt_mesh_friend *frnd, uint8_t md); - -void bt_mesh_friend_sec_update(uint16_t net_idx) -{ - int i; - - BT_DBG("net_idx 0x%04x", net_idx); - - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { - struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - - if (!frnd->subnet) { - continue; - } - - if (net_idx == BT_MESH_KEY_ANY || - frnd->subnet->net_idx == net_idx) { - enqueue_update(frnd, 0x00); - } - } -} - -int bt_mesh_friend_clear(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) -{ - struct bt_mesh_ctl_friend_clear *msg = (void *)buf->om_data; - struct bt_mesh_friend *frnd; - uint16_t lpn_addr, lpn_counter; - struct bt_mesh_net_tx tx = { - .sub = rx->sub, - .ctx = &rx->ctx, - .src = bt_mesh_primary_addr(), - .xmit = bt_mesh_net_transmit_get(), - }; - struct bt_mesh_ctl_friend_clear_confirm cfm; - - if (buf->om_len < sizeof(*msg)) { - BT_WARN("Too short Friend Clear"); - return -EINVAL; - } - - lpn_addr = sys_be16_to_cpu(msg->lpn_addr); - lpn_counter = sys_be16_to_cpu(msg->lpn_counter); - - BT_DBG("LPN addr 0x%04x counter 0x%04x", lpn_addr, lpn_counter); - - frnd = bt_mesh_friend_find(rx->sub->net_idx, lpn_addr, false, false); - if (!frnd) { - BT_WARN("No matching LPN addr 0x%04x", lpn_addr); - return 0; - } - - /* A Friend Clear message is considered valid if the result of the - * subtraction of the value of the LPNCounter field of the Friend - * Request message (the one that initiated the friendship) from the - * value of the LPNCounter field of the Friend Clear message, modulo - * 65536, is in the range 0 to 255 inclusive. - */ - if (lpn_counter - frnd->lpn_counter > 255) { - BT_WARN("LPN Counter out of range (old %u new %u)", - frnd->lpn_counter, lpn_counter); - return 0; - } - - tx.ctx->send_ttl = BT_MESH_TTL_MAX; - - cfm.lpn_addr = msg->lpn_addr; - cfm.lpn_counter = msg->lpn_counter; - - bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR_CFM, &cfm, - sizeof(cfm), NULL, NULL); - - friend_clear(frnd); - - return 0; -} - -static void friend_sub_add(struct bt_mesh_friend *frnd, uint16_t addr) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { - if (frnd->sub_list[i] == BT_MESH_ADDR_UNASSIGNED) { - frnd->sub_list[i] = addr; - return; - } - } - - BT_WARN("No space in friend subscription list"); -} - -static void friend_sub_rem(struct bt_mesh_friend *frnd, uint16_t addr) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { - if (frnd->sub_list[i] == addr) { - frnd->sub_list[i] = BT_MESH_ADDR_UNASSIGNED; - return; - } - } -} - -static struct os_mbuf *create_friend_pdu(struct bt_mesh_friend *frnd, - struct friend_pdu_info *info, - struct os_mbuf *sdu) -{ - struct os_mbuf *buf; - - buf = bt_mesh_adv_create_from_pool(&friend_os_mbuf_pool, adv_alloc, - BT_MESH_ADV_DATA, - FRIEND_XMIT, K_NO_WAIT); - if (!buf) { - return NULL; - } - - net_buf_add_u8(buf, (info->iv_index & 1) << 7); /* Will be reset in encryption */ - - if (info->ctl) { - net_buf_add_u8(buf, info->ttl | 0x80); - } else { - net_buf_add_u8(buf, info->ttl); - } - - net_buf_add_mem(buf, info->seq, sizeof(info->seq)); - - net_buf_add_be16(buf, info->src); - net_buf_add_be16(buf, info->dst); - - net_buf_add_mem(buf, sdu->om_data, sdu->om_len); - - return buf; -} - -struct unseg_app_sdu_meta { - struct bt_mesh_app_crypto_ctx crypto; - const uint8_t *key; - struct bt_mesh_subnet *subnet; - uint8_t aid; -}; - -static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd, - struct os_mbuf *buf, - struct unseg_app_sdu_meta *meta) -{ - uint16_t app_idx = FRIEND_ADV(buf)->app_idx; - struct bt_mesh_net_rx net; - int err; - - meta->subnet = frnd->subnet; - bt_mesh_net_header_parse(buf, &net); - err = bt_mesh_keys_resolve(&net.ctx, &net.sub, &meta->key, &meta->aid); - if (err) { - return err; - } - - meta->crypto.src = net.ctx.addr; - meta->crypto.dst = net.ctx.recv_dst; - meta->crypto.iv_index = BT_MESH_NET_IVI_TX; - meta->crypto.dev_key = BT_MESH_IS_DEV_KEY(app_idx); - meta->crypto.seq_num = net.seq; - meta->crypto.aszmic = 0; - - if (BT_MESH_ADDR_IS_VIRTUAL(meta->crypto.dst)) { - meta->crypto.ad = bt_mesh_va_label_get(meta->crypto.dst); - if (!meta->crypto.ad) { - return -ENOENT; - } - } else { - meta->crypto.ad = NULL; - } - - return 0; -} - -static int unseg_app_sdu_decrypt(struct bt_mesh_friend *frnd, - struct os_mbuf *buf, - const struct unseg_app_sdu_meta *meta) -{ - struct net_buf_simple_state state; - int err; - - BT_DBG(""); - - net_buf_simple_save(buf, &state); - net_buf_simple_pull_mem(buf, 10); - buf->om_len -= 4; - - err = bt_mesh_app_decrypt(meta->key, &meta->crypto, buf, buf); - - net_buf_simple_restore(buf, &state); - net_buf_unref(buf); - return err; -} - -static int unseg_app_sdu_encrypt(struct bt_mesh_friend *frnd, - struct os_mbuf *buf, - const struct unseg_app_sdu_meta *meta) -{ - struct net_buf_simple_state state; - int err; - - BT_DBG(""); - - net_buf_simple_save(buf, &state); - net_buf_simple_pull_mem(buf, 10); - buf->om_len -= 4; - - err = bt_mesh_app_encrypt(meta->key, &meta->crypto, buf); - - net_buf_simple_restore(buf, &state); - return err; -} - -static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd, - struct os_mbuf *buf) -{ - struct unseg_app_sdu_meta meta; - int err; - - BT_DBG(""); - - if (FRIEND_ADV(buf)->app_idx == BT_MESH_KEY_UNUSED) { - return 0; - } - - err = unseg_app_sdu_unpack(frnd, buf, &meta); - if (err) { - return err; - } - - /* No need to reencrypt the message if the sequence number is - * unchanged. - */ - if (meta.crypto.seq_num == bt_mesh.seq) { - return 0; - } - - err = unseg_app_sdu_decrypt(frnd, buf, &meta); - if (err) { - BT_WARN("Decryption failed! %d", err); - return err; - } - - err = unseg_app_sdu_encrypt(frnd, buf, &meta); - if (err) { - BT_WARN("Re-encryption failed! %d", err); - } - - return err; -} - -static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct os_mbuf *buf, - bool master_cred) -{ - const struct bt_mesh_net_cred *cred; - uint32_t iv_index; - uint16_t src; - int err; - - if (master_cred) { - cred = &frnd->subnet->keys[SUBNET_KEY_TX_IDX(frnd->subnet)] - .msg; - } else { - cred = &frnd->cred[SUBNET_KEY_TX_IDX(frnd->subnet)]; - } - - src = sys_get_be16(&buf->om_data[5]); - - if (bt_mesh_elem_find(src)) { - uint32_t seq; - - if (FRIEND_ADV(buf)->app_idx != BT_MESH_KEY_UNUSED) { - err = unseg_app_sdu_prepare(frnd, buf); - if (err) { - return err; - } - } - - seq = bt_mesh_next_seq(); - sys_put_be24(seq, &buf->om_data[2]); - - iv_index = BT_MESH_NET_IVI_TX; - FRIEND_ADV(buf)->app_idx = BT_MESH_KEY_UNUSED; - } else { - uint8_t ivi = (buf->om_data[0] >> 7); - iv_index = (bt_mesh.iv_index - ((bt_mesh.iv_index & 1) != ivi)); - } - - buf->om_data[0] = (cred->nid | (iv_index & 1) << 7); - - if (bt_mesh_net_encrypt(cred->enc, buf, iv_index, false)) { - BT_ERR("Encrypting failed"); - return -EINVAL; - } - - if (bt_mesh_net_obfuscate(buf->om_data, iv_index, cred->privacy)) { - BT_ERR("Obfuscating failed"); - return -EINVAL; - } - - return 0; -} - -static struct os_mbuf *encode_friend_ctl(struct bt_mesh_friend *frnd, - uint8_t ctl_op, - struct os_mbuf *sdu) -{ - struct friend_pdu_info info; - - BT_DBG("LPN 0x%04x", frnd->lpn); - - net_buf_simple_push_u8(sdu, TRANS_CTL_HDR(ctl_op, 0)); - - info.src = bt_mesh_primary_addr(); - info.dst = frnd->lpn; - - info.ctl = 1; - info.ttl = 0; - - memset(info.seq, 0, sizeof(info.seq)); - - info.iv_index = BT_MESH_NET_IVI_TX; - - return create_friend_pdu(frnd, &info, sdu); -} - -static struct os_mbuf *encode_update(struct bt_mesh_friend *frnd, uint8_t md) -{ - struct bt_mesh_ctl_friend_update *upd; - struct os_mbuf *sdu = NET_BUF_SIMPLE(1 + sizeof(*upd)); - struct os_mbuf *buf; - - __ASSERT_NO_MSG(frnd->subnet); - - BT_DBG("lpn 0x%04x md 0x%02x", frnd->lpn, md); - - net_buf_simple_init(sdu, 1); - - upd = net_buf_simple_add(sdu, sizeof(*upd)); - upd->flags = bt_mesh_net_flags(frnd->subnet); - upd->iv_index = sys_cpu_to_be32(bt_mesh.iv_index); - upd->md = md; - - buf = encode_friend_ctl(frnd, TRANS_CTL_OP_FRIEND_UPDATE, sdu); - - os_mbuf_free_chain(sdu); - return buf; -} - -static void enqueue_sub_cfm(struct bt_mesh_friend *frnd, uint8_t xact) -{ - struct bt_mesh_ctl_friend_sub_confirm *cfm; - struct os_mbuf *sdu = NET_BUF_SIMPLE(1 + sizeof(*cfm)); - struct os_mbuf *buf; - - BT_DBG("lpn 0x%04x xact 0x%02x", frnd->lpn, xact); - - net_buf_simple_init(sdu, 1); - - cfm = net_buf_simple_add(sdu, sizeof(*cfm)); - cfm->xact = xact; - - buf = encode_friend_ctl(frnd, TRANS_CTL_OP_FRIEND_SUB_CFM, sdu); - if (!buf) { - BT_ERR("Unable to encode Subscription List Confirmation"); - goto done; - } - - if (encrypt_friend_pdu(frnd, buf, false)) { - return; - } - - if (frnd->last) { - BT_DBG("Discarding last PDU"); - net_buf_unref(frnd->last); - } - - frnd->last = buf; - frnd->send_last = 1; - -done: - os_mbuf_free_chain(sdu); -} - -static void friend_recv_delay(struct bt_mesh_friend *frnd) -{ - int32_t delay = recv_delay(frnd); - - frnd->pending_req = 1; - k_delayed_work_submit(&frnd->timer, K_MSEC(delay)); - BT_DBG("Waiting RecvDelay of %d ms", delay); -} - -int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf) -{ - struct bt_mesh_friend *frnd; - uint8_t xact; - - if (buf->om_len < BT_MESH_FRIEND_SUB_MIN_LEN) { - BT_WARN("Too short Friend Subscription Add"); - return -EINVAL; - } - - frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, true); - if (!frnd) { - BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr); - return 0; - } - - if (frnd->pending_buf) { - BT_WARN("Previous buffer not yet sent!"); - return 0; - } - - friend_recv_delay(frnd); - - xact = net_buf_simple_pull_u8(buf); - - while (buf->om_len >= 2) { - friend_sub_add(frnd, net_buf_simple_pull_be16(buf)); - } - - enqueue_sub_cfm(frnd, xact); - - return 0; -} - -int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf) -{ - struct bt_mesh_friend *frnd; - uint8_t xact; - - if (buf->om_len < BT_MESH_FRIEND_SUB_MIN_LEN) { - BT_WARN("Too short Friend Subscription Remove"); - return -EINVAL; - } - - frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, true); - if (!frnd) { - BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr); - return 0; - } - - if (frnd->pending_buf) { - BT_WARN("Previous buffer not yet sent!"); - return 0; - } - - friend_recv_delay(frnd); - - xact = net_buf_simple_pull_u8(buf); - - while (buf->om_len >= 2) { - friend_sub_rem(frnd, net_buf_simple_pull_be16(buf)); - } - - enqueue_sub_cfm(frnd, xact); - - return 0; -} - -static void enqueue_buf(struct bt_mesh_friend *frnd, struct os_mbuf *buf) -{ - net_buf_slist_put(&frnd->queue, buf); - frnd->queue_size++; -} - -static void enqueue_update(struct bt_mesh_friend *frnd, uint8_t md) -{ - struct os_mbuf *buf; - - buf = encode_update(frnd, md); - if (!buf) { - BT_ERR("Unable to encode Friend Update"); - return; - } - - enqueue_buf(frnd, buf); -} - -int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) -{ - struct bt_mesh_ctl_friend_poll *msg = (void *)buf->om_data; - struct bt_mesh_friend *frnd; - - if (buf->om_len < sizeof(*msg)) { - BT_WARN("Too short Friend Poll"); - return -EINVAL; - } - - frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, false); - if (!frnd) { - BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr); - return 0; - } - - if (msg->fsn & ~1) { - BT_WARN("Prohibited (non-zero) padding bits"); - return -EINVAL; - } - - if (frnd->pending_buf) { - BT_WARN("Previous buffer not yet sent"); - return 0; - } - - BT_DBG("msg->fsn %u frnd->fsn %u", (msg->fsn & 1), frnd->fsn); - - friend_recv_delay(frnd); - - if (!frnd->established) { - BT_DBG("Friendship established with 0x%04x", frnd->lpn); - frnd->established = 1; - } - - if (msg->fsn == frnd->fsn && frnd->last) { - BT_DBG("Re-sending last PDU"); - frnd->send_last = 1; - } else { - if (frnd->last) { - net_buf_unref(frnd->last); - frnd->last = NULL; - } - - frnd->fsn = msg->fsn; - - if (net_buf_slist_is_empty(&frnd->queue)) { - enqueue_update(frnd, 0); - BT_DBG("Enqueued Friend Update to empty queue"); - } - } - - return 0; -} - -static struct bt_mesh_friend *find_clear(uint16_t prev_friend) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { - struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - - if (frnd->clear.frnd == prev_friend) { - return frnd; - } - } - - return NULL; -} - -static void friend_clear_sent(int err, void *user_data) -{ - struct bt_mesh_friend *frnd = user_data; - - k_delayed_work_submit(&frnd->clear.timer, - K_SECONDS(frnd->clear.repeat_sec)); - frnd->clear.repeat_sec *= 2; -} - -static const struct bt_mesh_send_cb clear_sent_cb = { - .end = friend_clear_sent, -}; - -static void send_friend_clear(struct bt_mesh_friend *frnd) -{ - struct bt_mesh_msg_ctx ctx = { - .net_idx = frnd->subnet->net_idx, - .app_idx = BT_MESH_KEY_UNUSED, - .addr = frnd->clear.frnd, - .send_ttl = BT_MESH_TTL_MAX, - }; - struct bt_mesh_net_tx tx = { - .sub = frnd->subnet, - .ctx = &ctx, - .src = bt_mesh_primary_addr(), - .xmit = bt_mesh_net_transmit_get(), - }; - struct bt_mesh_ctl_friend_clear req = { - .lpn_addr = sys_cpu_to_be16(frnd->lpn), - .lpn_counter = sys_cpu_to_be16(frnd->lpn_counter), - }; - - BT_DBG(""); - - bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req, - sizeof(req), &clear_sent_cb, frnd); -} - -static void clear_timeout(struct ble_npl_event *work) -{ - struct bt_mesh_friend *frnd = ble_npl_event_get_arg(work); - uint32_t duration; - - BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd); - - duration = k_uptime_get_32() - frnd->clear.start; - if (duration > 2 * frnd->poll_to) { - BT_DBG("Clear Procedure timer expired"); - frnd->clear.frnd = BT_MESH_ADDR_UNASSIGNED; - return; - } - - send_friend_clear(frnd); -} - -static void clear_procedure_start(struct bt_mesh_friend *frnd) -{ - BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd); - - frnd->clear.start = k_uptime_get_32(); - frnd->clear.repeat_sec = 1U; - - send_friend_clear(frnd); -} - -int bt_mesh_friend_clear_cfm(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf) -{ - struct bt_mesh_ctl_friend_clear_confirm *msg = (void *)buf->om_data; - struct bt_mesh_friend *frnd; - uint16_t lpn_addr, lpn_counter; - - BT_DBG(""); - - if (buf->om_len < sizeof(*msg)) { - BT_WARN("Too short Friend Clear Confirm"); - return -EINVAL; - } - - frnd = find_clear(rx->ctx.addr); - if (!frnd) { - BT_WARN("No pending clear procedure for 0x%02x", rx->ctx.addr); - return 0; - } - - lpn_addr = sys_be16_to_cpu(msg->lpn_addr); - if (lpn_addr != frnd->lpn) { - BT_WARN("LPN address mismatch (0x%04x != 0x%04x)", - lpn_addr, frnd->lpn); - return 0; - } - - lpn_counter = sys_be16_to_cpu(msg->lpn_counter); - if (lpn_counter != frnd->lpn_counter) { - BT_WARN("LPN counter mismatch (0x%04x != 0x%04x)", - lpn_counter, frnd->lpn_counter); - return 0; - } - - k_delayed_work_cancel(&frnd->clear.timer); - frnd->clear.frnd = BT_MESH_ADDR_UNASSIGNED; - - return 0; -} - -static void enqueue_offer(struct bt_mesh_friend *frnd, int8_t rssi) -{ - struct bt_mesh_ctl_friend_offer *off; - struct os_mbuf *sdu = NET_BUF_SIMPLE(1 + sizeof(*off)); - struct os_mbuf *buf; - - BT_DBG(""); - - net_buf_simple_init(sdu, 1); - - off = net_buf_simple_add(sdu, sizeof(*off)); - - off->recv_win = CONFIG_BT_MESH_FRIEND_RECV_WIN, - off->queue_size = CONFIG_BT_MESH_FRIEND_QUEUE_SIZE, - off->sub_list_size = ARRAY_SIZE(frnd->sub_list), - off->rssi = rssi, - off->frnd_counter = sys_cpu_to_be16(frnd->counter); - - buf = encode_friend_ctl(frnd, TRANS_CTL_OP_FRIEND_OFFER, sdu); - if (!buf) { - BT_ERR("Unable to encode Friend Offer"); - goto done; - } - - if (encrypt_friend_pdu(frnd, buf, true)) { - goto done; - } - - if (frnd->last) { - net_buf_unref(frnd->last); - } - - frnd->last = buf; - frnd->send_last = 1; - -done: - os_mbuf_free_chain(sdu); -} - -#define RECV_WIN CONFIG_BT_MESH_FRIEND_RECV_WIN -#define RSSI_FACT(crit) (((crit) >> 5) & (uint8_t)BIT_MASK(2)) -#define RECV_WIN_FACT(crit) (((crit) >> 3) & (uint8_t)BIT_MASK(2)) -#define MIN_QUEUE_SIZE_LOG(crit) ((crit) & (uint8_t)BIT_MASK(3)) -#define MIN_QUEUE_SIZE(crit) ((uint32_t)BIT(MIN_QUEUE_SIZE_LOG(crit))) - -static int32_t offer_delay(struct bt_mesh_friend *frnd, int8_t rssi, uint8_t crit) -{ - /* Scaling factors. The actual values are 1, 1.5, 2 & 2.5, but we - * want to avoid floating-point arithmetic. - */ - static const uint8_t fact[] = { 10, 15, 20, 25 }; - int32_t delay; - - BT_DBG("ReceiveWindowFactor %u ReceiveWindow %u RSSIFactor %u RSSI %d", - fact[RECV_WIN_FACT(crit)], RECV_WIN, - fact[RSSI_FACT(crit)], rssi); - - /* Delay = ReceiveWindowFactor * ReceiveWindow - RSSIFactor * RSSI */ - delay = (int32_t)fact[RECV_WIN_FACT(crit)] * RECV_WIN; - delay -= (int32_t)fact[RSSI_FACT(crit)] * rssi; - delay /= 10; - - BT_DBG("Local Delay calculated as %d ms", (int) delay); - - return MAX(delay, 100); -} - -int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) -{ - struct bt_mesh_ctl_friend_req *msg = (void *)buf->om_data; - struct bt_mesh_friend *frnd = NULL; - uint32_t poll_to; - int32_t delay; - int i, err; - - if (rx->net_if == BT_MESH_NET_IF_LOCAL) { - BT_WARN("Ignoring Friend request from local interface"); - return 0; - } - - if (buf->om_len < sizeof(*msg)) { - BT_WARN("Too short Friend Request"); - return -EINVAL; - } - - if (msg->recv_delay <= 0x09) { - BT_WARN("Prohibited ReceiveDelay (0x%02x)", msg->recv_delay); - return -EINVAL; - } - - poll_to = sys_get_be24(msg->poll_to); - - if (poll_to <= 0x000009 || poll_to >= 0x34bc00) { - BT_WARN("Prohibited PollTimeout (0x%06x)", (unsigned) poll_to); - return -EINVAL; - } - - if (msg->num_elem == 0x00) { - BT_WARN("Prohibited NumElements value (0x00)"); - return -EINVAL; - } - - if (!BT_MESH_ADDR_IS_UNICAST(rx->ctx.addr + msg->num_elem - 1)) { - BT_WARN("LPN elements stretch outside of unicast range"); - return -EINVAL; - } - - if (!MIN_QUEUE_SIZE_LOG(msg->criteria)) { - BT_WARN("Prohibited Minimum Queue Size in Friend Request"); - return -EINVAL; - } - - if (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE < MIN_QUEUE_SIZE(msg->criteria)) { - BT_WARN("We have a too small Friend Queue size (%u < %u)", - CONFIG_BT_MESH_FRIEND_QUEUE_SIZE, - (unsigned) MIN_QUEUE_SIZE(msg->criteria)); - return 0; - } - - frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, false); - if (frnd) { - BT_WARN("Existing LPN re-requesting Friendship"); - friend_clear(frnd); - goto init_friend; - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { - if (!bt_mesh.frnd[i].subnet) { - frnd = &bt_mesh.frnd[i]; - break; - } - } - - if (!frnd) { - BT_WARN("No free Friend contexts for new LPN"); - return -ENOMEM; - } - -init_friend: - frnd->lpn = rx->ctx.addr; - frnd->num_elem = msg->num_elem; - frnd->subnet = rx->sub; - frnd->recv_delay = msg->recv_delay; - frnd->poll_to = poll_to * 100; - frnd->lpn_counter = sys_be16_to_cpu(msg->lpn_counter); - frnd->clear.frnd = sys_be16_to_cpu(msg->prev_addr); - - err = friend_cred_create(frnd, SUBNET_KEY_TX_IDX(frnd->subnet)); - if (err) { - BT_ERR("Failed to create friend credentials"); - friend_clear(frnd); - return -EIO; - } - - BT_DBG("LPN 0x%04x rssi %d recv_delay %u poll_to %ums", - frnd->lpn, rx->ctx.recv_rssi, frnd->recv_delay, - (unsigned) frnd->poll_to); - - if (BT_MESH_ADDR_IS_UNICAST(frnd->clear.frnd) && - !bt_mesh_elem_find(frnd->clear.frnd)) { - clear_procedure_start(frnd); - } - - delay = offer_delay(frnd, rx->ctx.recv_rssi, msg->criteria); - k_delayed_work_submit(&frnd->timer, K_MSEC(delay)); - - enqueue_offer(frnd, rx->ctx.recv_rssi); - - return 0; -} - -static bool is_seg(struct bt_mesh_friend_seg *seg, uint16_t src, uint16_t seq_zero) -{ - struct os_mbuf *buf = (void *)net_buf_slist_peek_head(&seg->queue); - struct net_buf_simple_state state; - uint16_t buf_seq_zero; - uint16_t buf_src; - - if (!buf) { - return false; - } - - net_buf_simple_save(buf, &state); - net_buf_skip(buf, 5); /* skip IVI, NID, CTL, TTL, SEQ */ - buf_src = net_buf_pull_be16(buf); - net_buf_skip(buf, 3); /* skip DST, OP/AID */ - buf_seq_zero = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK); - net_buf_simple_restore(buf, &state); - - return ((src == buf_src) && (seq_zero == buf_seq_zero)); -} - -static struct bt_mesh_friend_seg *get_seg(struct bt_mesh_friend *frnd, - uint16_t src, uint16_t seq_zero, - uint8_t seg_count) -{ - struct bt_mesh_friend_seg *unassigned = NULL; - int i; - - for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) { - struct bt_mesh_friend_seg *seg = &frnd->seg[i]; - - if (is_seg(seg, src, seq_zero)) { - return seg; - } - - if (!unassigned && !net_buf_slist_peek_head(&seg->queue)) { - unassigned = seg; - } - } - - if (unassigned) { - unassigned->seg_count = seg_count; - } - - return unassigned; -} - -static void enqueue_friend_pdu(struct bt_mesh_friend *frnd, - enum bt_mesh_friend_pdu_type type, - uint16_t src, uint8_t seg_count, - struct os_mbuf *buf) -{ - struct bt_mesh_friend_seg *seg; - - BT_DBG("type %u", type); - - if (type == BT_MESH_FRIEND_PDU_SINGLE) { - enqueue_buf(frnd, buf); - return; - } - - uint16_t seq_zero = (((buf->om_data[10] << 8 | buf->om_data[11]) >> 2) & TRANS_SEQ_ZERO_MASK); - - seg = get_seg(frnd, src, seq_zero, seg_count); - if (!seg) { - BT_ERR("No free friend segment RX contexts for 0x%04x", src); - net_buf_unref(buf); - return; - } - - net_buf_slist_put(&seg->queue, buf); - - if (type == BT_MESH_FRIEND_PDU_COMPLETE) { - net_buf_slist_merge_slist(&frnd->queue, &seg->queue); - - frnd->queue_size += seg->seg_count; - seg->seg_count = 0U; - } else { - /* Mark the buffer as having more to come after it */ - BT_MESH_ADV(buf)->flags |= NET_BUF_FRAGS; - } -} - -static void buf_send_start(uint16_t duration, int err, void *user_data) -{ - struct bt_mesh_friend *frnd = user_data; - - BT_DBG("err %d", err); - - frnd->pending_buf = 0; - - /* Friend Offer doesn't follow the re-sending semantics */ - if (!frnd->established && frnd->last) { - net_buf_unref(frnd->last); - frnd->last = NULL; - } -} - -static void buf_send_end(int err, void *user_data) -{ - struct bt_mesh_friend *frnd = user_data; - - BT_DBG("err %d", err); - - if (frnd->pending_req) { - BT_WARN("Another request before previous completed sending"); - return; - } - - if (frnd->established) { - k_delayed_work_submit(&frnd->timer, frnd->poll_to); - BT_DBG("Waiting %u ms for next poll", - (unsigned) frnd->poll_to); - } else { - /* Friend offer timeout is 1 second */ - k_delayed_work_submit(&frnd->timer, K_SECONDS(1)); - BT_DBG("Waiting for first poll"); - } -} - -static void update_overwrite(struct os_mbuf *buf, uint8_t md) -{ - struct net_buf_simple_state state; - struct bt_mesh_ctl_friend_update *upd; - - if (buf->om_len != 16) { - return; - } - - net_buf_simple_save(buf, &state); - - net_buf_skip(buf, 1); /* skip IVI, NID */ - - if (!(net_buf_pull_u8(buf) >> 7)) { - goto end; - } - - net_buf_skip(buf, 7); /* skip seqnum src dec*/ - - if (TRANS_CTL_OP((uint8_t *) net_buf_pull_mem(buf, 1)) - != TRANS_CTL_OP_FRIEND_UPDATE) { - goto end; - } - - upd = net_buf_pull_mem(buf, sizeof(*upd)); - BT_DBG("Update Previous Friend Update MD 0x%02x -> 0x%02x", upd->md, md); - upd->md = md; - -end: - net_buf_simple_restore(buf, &state); -} - -static void friend_timeout(struct ble_npl_event *work) -{ - struct bt_mesh_friend *frnd = ble_npl_event_get_arg(work); - static const struct bt_mesh_send_cb buf_sent_cb = { - .start = buf_send_start, - .end = buf_send_end, - }; - - uint8_t md; - - __ASSERT_NO_MSG(frnd->pending_buf == 0); - - BT_DBG("lpn 0x%04x send_last %u last %p", frnd->lpn, - frnd->send_last, frnd->last); - - if (frnd->send_last && frnd->last) { - BT_DBG("Sending frnd->last %p", frnd->last); - frnd->send_last = 0; - goto send_last; - } - - if (frnd->established && !frnd->pending_req) { - BT_WARN("Friendship lost with 0x%04x", frnd->lpn); - friend_clear(frnd); - return; - } - - frnd->last = (void *)net_buf_slist_get(&frnd->queue); - if (!frnd->last) { - BT_WARN("Friendship not established with 0x%04x", - frnd->lpn); - friend_clear(frnd); - return; - } - - md = (uint8_t)(net_buf_slist_peek_head(&frnd->queue) != NULL); - - update_overwrite(frnd->last, md); - - if (encrypt_friend_pdu(frnd, frnd->last, false)) { - return; - } - - /* Clear the flag we use for segment tracking */ - BT_MESH_ADV(frnd->last)->flags &= ~NET_BUF_FRAGS; - BT_MESH_ADV(frnd->last)->flags = 0; - - BT_DBG("Sending buf %p from Friend Queue of LPN 0x%04x", - frnd->last, frnd->lpn); - frnd->queue_size--; - -send_last: - frnd->pending_req = 0; - frnd->pending_buf = 1; - bt_mesh_adv_send(frnd->last, &buf_sent_cb, frnd); -} - -static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) -{ - int i, err; - - if (evt == BT_MESH_KEY_ADDED) { - return; - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { - struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - - if (frnd->subnet != sub) { - continue; - } - - switch (evt) { - case BT_MESH_KEY_DELETED: - BT_DBG("Cleared network for 0x%04x", frnd->lpn); - friend_clear(frnd); - break; - case BT_MESH_KEY_UPDATED: - BT_DBG("Generating new keys for 0x%04x", frnd->lpn); - err = friend_cred_create(frnd, 1); - if (err) { - BT_ERR("Failed updating friend cred for 0x%04x", - frnd->lpn); - friend_clear(frnd); - } - break; - case BT_MESH_KEY_SWAPPED: - enqueue_update(frnd, 0); - break; - case BT_MESH_KEY_REVOKED: - BT_DBG("Revoking old keys for 0x%04x", frnd->lpn); - memcpy(&frnd->cred[0], &frnd->cred[1], - sizeof(frnd->cred[0])); - memset(&frnd->cred[1], 0, sizeof(frnd->cred[1])); - enqueue_update(frnd, 0); - break; - default: - break; - } - } -} - -int bt_mesh_friend_init(void) -{ - if (!bt_mesh_subnet_cb_list[3]) { - bt_mesh_subnet_cb_list[3] = subnet_evt; - } - int rc; - int i; - - rc = os_mempool_init(&friend_buf_mempool, FRIEND_BUF_COUNT, - BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, - friend_buf_mem, "friend_buf_pool"); - assert(rc == 0); - - rc = os_mbuf_pool_init(&friend_os_mbuf_pool, &friend_buf_mempool, - BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, - FRIEND_BUF_COUNT); - assert(rc == 0); - - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { - struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - int j; - - net_buf_slist_init(&frnd->queue); - - k_delayed_work_init(&frnd->timer, friend_timeout); - k_delayed_work_add_arg(&frnd->timer, frnd); - k_delayed_work_init(&frnd->clear.timer, clear_timeout); - k_delayed_work_add_arg(&frnd->clear.timer, frnd); - - for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) { - net_buf_slist_init(&frnd->seg[j].queue); - } - } - - return 0; -} - -static bool is_segack(struct os_mbuf *buf, uint64_t *seqauth, uint16_t src) -{ - struct net_buf_simple_state state; - bool found = false; - - if (buf->om_len != 16) { - return false; - } - - net_buf_simple_save(buf, &state); - - net_buf_skip(buf, 1); /* skip IVI, NID */ - - if (!(net_buf_pull_u8(buf) >> 7)) { - goto end; - } - - net_buf_pull(buf, 3); /* skip SEQNUM */ - - if (src != net_buf_pull_be16(buf)) { - goto end; - } - - net_buf_skip(buf, 2); /* skip dst */ - - if (TRANS_CTL_OP((uint8_t *) net_buf_pull_mem(buf, 1)) != TRANS_CTL_OP_ACK) { - goto end; - } - - found = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK) == - (*seqauth & TRANS_SEQ_ZERO_MASK); -end: - net_buf_simple_restore(buf, &state); - return found; -} - -static void friend_purge_old_ack(struct bt_mesh_friend *frnd, uint64_t *seq_auth, - uint16_t src) -{ - struct os_mbuf *cur, *prev = NULL; - - BT_DBG("SeqAuth %llx src 0x%04x", *seq_auth, src); - - for (cur = net_buf_slist_peek_head(&frnd->queue); - cur != NULL; prev = cur, cur = net_buf_slist_peek_next(cur)) { - struct os_mbuf *buf = (void *)cur; - - if (is_segack(buf, seq_auth, src)) { - BT_DBG("Removing old ack from Friend Queue"); - - net_buf_slist_remove(&frnd->queue, prev, cur); - frnd->queue_size--; - - net_buf_unref(buf); - break; - } - } -} - -static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd, - struct bt_mesh_net_rx *rx, - enum bt_mesh_friend_pdu_type type, - uint64_t *seq_auth, uint8_t seg_count, - struct os_mbuf *sbuf) -{ - struct friend_pdu_info info; - struct os_mbuf *buf; - - /* Because of network loopback, tx packets will also be passed into - * this rx function. These packets have already been added to the - * queue, and should be ignored. - */ - if (bt_mesh_elem_find(rx->ctx.addr)) { - return; - } - - BT_DBG("LPN 0x%04x queue_size %u", frnd->lpn, - (unsigned) frnd->queue_size); - - if (type == BT_MESH_FRIEND_PDU_SINGLE && seq_auth) { - friend_purge_old_ack(frnd, seq_auth, rx->ctx.addr); - } - - info.src = rx->ctx.addr; - info.dst = rx->ctx.recv_dst; - - if (rx->net_if == BT_MESH_NET_IF_LOCAL) { - info.ttl = rx->ctx.recv_ttl; - } else { - info.ttl = rx->ctx.recv_ttl - 1; - } - - info.ctl = rx->ctl; - - sys_put_be24(rx->seq, info.seq); - - info.iv_index = BT_MESH_NET_IVI_RX(rx); - - buf = create_friend_pdu(frnd, &info, sbuf); - if (!buf) { - BT_ERR("Failed to encode Friend buffer"); - return; - } - - enqueue_friend_pdu(frnd, type, info.src, seg_count, buf); - - BT_DBG("Queued message for LPN 0x%04x, queue_size %u", - frnd->lpn, (unsigned) frnd->queue_size); -} - -static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd, - struct bt_mesh_net_tx *tx, - enum bt_mesh_friend_pdu_type type, - uint64_t *seq_auth, uint8_t seg_count, - struct os_mbuf *sbuf) -{ - struct friend_pdu_info info; - struct os_mbuf *buf; - - BT_DBG("LPN 0x%04x", frnd->lpn); - - if (type == BT_MESH_FRIEND_PDU_SINGLE && seq_auth) { - friend_purge_old_ack(frnd, seq_auth, tx->src); - } - - info.src = tx->src; - info.dst = tx->ctx->addr; - - info.ttl = tx->ctx->send_ttl; - info.ctl = (tx->ctx->app_idx == BT_MESH_KEY_UNUSED); - - sys_put_be24(bt_mesh.seq, info.seq); - - info.iv_index = BT_MESH_NET_IVI_TX; - - buf = create_friend_pdu(frnd, &info, sbuf); - if (!buf) { - BT_ERR("Failed to encode Friend buffer"); - return; - } - - if (type == BT_MESH_FRIEND_PDU_SINGLE && !info.ctl) { - /* Unsegmented application packets may be reencrypted later, - * as they depend on the the sequence number being the same - * when encrypting in transport and network. - */ - FRIEND_ADV(buf)->app_idx = tx->ctx->app_idx; - } - - enqueue_friend_pdu(frnd, type, info.src, seg_count, buf); - - BT_DBG("Queued message for LPN 0x%04x", frnd->lpn); -} - -static bool friend_lpn_matches(struct bt_mesh_friend *frnd, uint16_t net_idx, - uint16_t addr) -{ - int i; - - if (!frnd->established) { - return false; - } - - if (net_idx != frnd->subnet->net_idx) { - return false; - } - - if (BT_MESH_ADDR_IS_UNICAST(addr)) { - return is_lpn_unicast(frnd, addr); - } - - for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { - if (frnd->sub_list[i] == addr) { - return true; - } - } - - return false; -} - -bool bt_mesh_friend_match(uint16_t net_idx, uint16_t addr) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { - struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - - if (friend_lpn_matches(frnd, net_idx, addr)) { - BT_DBG("LPN 0x%04x matched address 0x%04x", - frnd->lpn, addr); - return true; - } - } - - BT_DBG("No matching LPN for address 0x%04x", addr); - - return false; -} - -static bool friend_queue_has_space(struct bt_mesh_friend *frnd, uint16_t addr, - uint64_t *seq_auth, uint8_t seg_count) -{ - uint32_t total = 0; - int i; - - if (seg_count > CONFIG_BT_MESH_FRIEND_QUEUE_SIZE) { - return false; - } - - for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) { - struct bt_mesh_friend_seg *seg = &frnd->seg[i]; - - if (seq_auth && is_seg(seg, addr, *seq_auth & TRANS_SEQ_ZERO_MASK)) { - /* If there's a segment queue for this message then the - * space verification has already happened. - */ - return true; - } - - total += seg->seg_count; - } - - /* If currently pending segments combined with this segmented message - * are more than the Friend Queue Size, then there's no space. This - * is because we don't have a mechanism of aborting already pending - * segmented messages to free up buffers. - */ - return (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - total) > seg_count; -} - -bool bt_mesh_friend_queue_has_space(uint16_t net_idx, uint16_t src, uint16_t dst, - uint64_t *seq_auth, uint8_t seg_count) -{ - bool someone_has_space = false, friend_match = false; - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { - struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - - if (!friend_lpn_matches(frnd, net_idx, dst)) { - continue; - } - - friend_match = true; - - if (friend_queue_has_space(frnd, src, seq_auth, seg_count)) { - someone_has_space = true; - } - } - - /* If there were no matched LPNs treat this as success, so the - * transport layer can continue its work. - */ - if (!friend_match) { - return true; - } - - /* From the transport layers perspective it's good enough that at - * least one Friend Queue has space. If there were multiple Friend - * matches then the destination must be a group address, in which - * case e.g. segment acks are not sent. - */ - return someone_has_space; -} - -static bool friend_queue_prepare_space(struct bt_mesh_friend *frnd, uint16_t addr, - uint64_t *seq_auth, uint8_t seg_count) -{ - bool pending_segments; - uint8_t avail_space; - - if (!friend_queue_has_space(frnd, addr, seq_auth, seg_count)) { - return false; - } - - avail_space = CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - frnd->queue_size; - pending_segments = false; - - while (pending_segments || avail_space < seg_count) { - struct os_mbuf *buf = (void *)net_buf_slist_get(&frnd->queue); - - if (!buf) { - BT_ERR("Unable to free up enough buffers"); - return false; - } - - frnd->queue_size--; - avail_space++; - - pending_segments = (BT_MESH_ADV(buf)->flags & NET_BUF_FRAGS); - BT_DBG("PENDING SEGMENTS %d", pending_segments); - - /* Make sure old slist entry state doesn't remain */ - BT_MESH_ADV(buf)->flags &= ~NET_BUF_FRAGS; - - net_buf_unref(buf); - } - - return true; -} - -void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx, - enum bt_mesh_friend_pdu_type type, - uint64_t *seq_auth, uint8_t seg_count, - struct os_mbuf *sbuf) -{ - int i; - - if (!rx->friend_match || - (rx->ctx.recv_ttl <= 1 && rx->net_if != BT_MESH_NET_IF_LOCAL) || - bt_mesh_friend_get() != BT_MESH_FRIEND_ENABLED) { - return; - } - - BT_DBG("recv_ttl %u net_idx 0x%04x src 0x%04x dst 0x%04x", - rx->ctx.recv_ttl, rx->sub->net_idx, rx->ctx.addr, - rx->ctx.recv_dst); - - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { - struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - - if (!friend_lpn_matches(frnd, rx->sub->net_idx, - rx->ctx.recv_dst)) { - continue; - } - - if (friend_lpn_matches(frnd, rx->sub->net_idx, - rx->ctx.addr)) { - continue; - } - - if (!friend_queue_prepare_space(frnd, rx->ctx.addr, seq_auth, - seg_count)) { - continue; - } - - friend_lpn_enqueue_rx(frnd, rx, type, seq_auth, seg_count, - sbuf); - } -} - -bool bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx, - enum bt_mesh_friend_pdu_type type, - uint64_t *seq_auth, uint8_t seg_count, - struct os_mbuf *sbuf) -{ - bool matched = false; - int i; - - if (!bt_mesh_friend_match(tx->sub->net_idx, tx->ctx->addr) || - bt_mesh_friend_get() != BT_MESH_FRIEND_ENABLED) { - return matched; - } - - BT_DBG("net_idx 0x%04x dst 0x%04x src 0x%04x", tx->sub->net_idx, - tx->ctx->addr, tx->src); - - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { - struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - - if (!friend_lpn_matches(frnd, tx->sub->net_idx, - tx->ctx->addr)) { - continue; - } - - if (!friend_queue_prepare_space(frnd, tx->src, seq_auth, - seg_count)) { - continue; - } - - friend_lpn_enqueue_tx(frnd, tx, type, seq_auth, seg_count, - sbuf); - matched = true; - } - - return matched; -} - -int bt_mesh_friend_terminate(uint16_t lpn_addr) -{ - struct bt_mesh_friend *frnd; - - frnd = bt_mesh_friend_find(BT_MESH_KEY_ANY, lpn_addr, false, false); - if (!frnd) { - return -ENOENT; - } - - friend_clear(frnd); - - return 0; -} - -void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, uint16_t src, - uint16_t dst, uint64_t *seq_auth) -{ - int i; - - BT_DBG(""); - - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { - struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - int j; - - if (!friend_lpn_matches(frnd, sub->net_idx, dst)) { - continue; - } - - for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) { - struct bt_mesh_friend_seg *seg = &frnd->seg[j]; - - if (!is_seg(seg, src, *seq_auth & TRANS_SEQ_ZERO_MASK)) { - continue; - } - - BT_WARN("Clearing incomplete segments for 0x%04x", src); - - purge_buffers(&seg->queue); - seg->seg_count = 0U; - break; - } - } -} - -#endif /* MYNEWT_VAL(BLE_MESH_FRIEND) */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/friend.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/friend.h deleted file mode 100644 index 04998c2e3..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/friend.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __FRIEND_H__ -#define __FRIEND_H__ - -#include "../include/mesh/mesh.h" - -enum bt_mesh_friend_pdu_type { - BT_MESH_FRIEND_PDU_SINGLE, - BT_MESH_FRIEND_PDU_PARTIAL, - BT_MESH_FRIEND_PDU_COMPLETE, -}; - -bool bt_mesh_friend_match(uint16_t net_idx, uint16_t addr); - -struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr, - bool valid, bool established); - -bool bt_mesh_friend_queue_has_space(uint16_t net_idx, uint16_t src, uint16_t dst, - uint64_t *seq_auth, uint8_t seg_count); - -void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx, - enum bt_mesh_friend_pdu_type type, - uint64_t *seq_auth, uint8_t seg_count, - struct os_mbuf *sbuf); -bool bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx, - enum bt_mesh_friend_pdu_type type, - uint64_t *seq_auth, uint8_t seg_count, - struct os_mbuf *sbuf); - -void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, uint16_t src, - uint16_t dst, uint64_t *seq_auth); - -void bt_mesh_friend_sec_update(uint16_t net_idx); - -void bt_mesh_friends_clear(void); - -int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct os_mbuf *buf); -int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct os_mbuf *buf); -int bt_mesh_friend_clear(struct bt_mesh_net_rx *rx, struct os_mbuf *buf); -int bt_mesh_friend_clear_cfm(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf); -int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf); -int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf); - -int bt_mesh_friend_init(void); - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/glue.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/glue.c deleted file mode 100644 index 34d46cfd2..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/glue.c +++ /dev/null @@ -1,971 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_LOG - -#if MYNEWT_VAL(BLE_MESH) - -#include "../include/mesh/glue.h" -#include "adv.h" -#ifndef MYNEWT -#include "nimble/porting/nimble/include/nimble/nimble_port.h" -#endif - -#if MYNEWT_VAL(BLE_MESH_SETTINGS) -#include "base64/base64.h" -#endif - -extern uint8_t g_mesh_addr_type; - -#if MYNEWT_VAL(BLE_EXT_ADV) -/* Store configuration for different bearers */ -#define BT_MESH_ADV_IDX (0) -#define BT_MESH_GATT_IDX (1) -static struct ble_gap_adv_params ble_adv_cur_conf[2]; -#endif - -const char * -bt_hex(const void *buf, size_t len) -{ - static const char hex[] = "0123456789abcdef"; - static char hexbufs[4][137]; - static uint8_t curbuf; - const uint8_t *b = buf; - char *str; - int i; - - str = hexbufs[curbuf++]; - curbuf %= ARRAY_SIZE(hexbufs); - - len = min(len, (sizeof(hexbufs[0]) - 1) / 2); - - for (i = 0; i < len; i++) { - str[i * 2] = hex[b[i] >> 4]; - str[i * 2 + 1] = hex[b[i] & 0xf]; - } - - str[i * 2] = '\0'; - - return str; -} - -void -net_buf_put(struct ble_npl_eventq *fifo, struct os_mbuf *om) -{ - struct ble_npl_event *ev; - - assert(OS_MBUF_IS_PKTHDR(om)); - ev = &BT_MESH_ADV(om)->ev; - assert(ev); - assert(ble_npl_event_get_arg(ev)); - - ble_npl_eventq_put(fifo, ev); -} - -void * -net_buf_ref(struct os_mbuf *om) -{ - struct bt_mesh_adv *adv; - - /* For bufs with header we count refs*/ - if (OS_MBUF_USRHDR_LEN(om) == 0) { - return om; - } - - adv = BT_MESH_ADV(om); - adv->ref_cnt++; - - return om; -} - -void -net_buf_unref(struct os_mbuf *om) -{ - struct bt_mesh_adv *adv; - - /* For bufs with header we count refs*/ - if (OS_MBUF_USRHDR_LEN(om) == 0) { - goto free; - } - - adv = BT_MESH_ADV(om); - if (--adv->ref_cnt > 0) { - return; - } - -free: - os_mbuf_free_chain(om); -} - -#if MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS) -int -bt_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data) -{ - mbedtls_aes_context s = {0}; - mbedtls_aes_init(&s); - - if (mbedtls_aes_setkey_enc(&s, key, 128) != 0) { - mbedtls_aes_free(&s); - return BLE_HS_EUNKNOWN; - } - - if (mbedtls_aes_crypt_ecb(&s, MBEDTLS_AES_ENCRYPT, plaintext, enc_data) != 0) { - mbedtls_aes_free(&s); - return BLE_HS_EUNKNOWN; - } - - mbedtls_aes_free(&s); - return 0; -} - -#else -int -bt_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data) -{ - struct tc_aes_key_sched_struct s = {0}; - - if (tc_aes128_set_encrypt_key(&s, key) == TC_CRYPTO_FAIL) { - return BLE_HS_EUNKNOWN; - } - - if (tc_aes_encrypt(enc_data, plaintext, &s) == TC_CRYPTO_FAIL) { - return BLE_HS_EUNKNOWN; - } - - return 0; -} -#endif - -uint16_t -net_buf_simple_pull_le16(struct os_mbuf *om) -{ - uint16_t val; - struct os_mbuf *old = om; - - om = os_mbuf_pullup(om, sizeof(val)); - assert(om == old); - val = get_le16(om->om_data); - os_mbuf_adj(om, sizeof(val)); - - return val; -} - -uint16_t -net_buf_simple_pull_be16(struct os_mbuf *om) -{ - uint16_t val; - struct os_mbuf *old = om; - - om = os_mbuf_pullup(om, sizeof(val)); - assert(om == old); - val = get_be16(om->om_data); - os_mbuf_adj(om, sizeof(val)); - - return val; -} - -uint32_t -net_buf_simple_pull_be32(struct os_mbuf *om) -{ - uint32_t val; - struct os_mbuf *old = om; - - om = os_mbuf_pullup(om, sizeof(val)); - assert(om == old); - val = get_be32(om->om_data); - os_mbuf_adj(om, sizeof(val)); - - return val; -} - -uint32_t -net_buf_simple_pull_le32(struct os_mbuf *om) -{ - uint32_t val; - struct os_mbuf *old = om; - - om = os_mbuf_pullup(om, sizeof(val)); - assert(om == old); - val = get_le32(om->om_data); - os_mbuf_adj(om, sizeof(val)); - - return val; -} - -uint8_t -net_buf_simple_pull_u8(struct os_mbuf *om) -{ - uint8_t val; - struct os_mbuf *old = om; - - om = os_mbuf_pullup(om, sizeof(val)); - assert(om == old); - val = om->om_data[0]; - os_mbuf_adj(om, 1); - - return val; -} - -void -net_buf_simple_add_le16(struct os_mbuf *om, uint16_t val) -{ - val = htole16(val); - os_mbuf_append(om, &val, sizeof(val)); - ASSERT_NOT_CHAIN(om); -} - -void -net_buf_simple_add_be16(struct os_mbuf *om, uint16_t val) -{ - val = htobe16(val); - os_mbuf_append(om, &val, sizeof(val)); - ASSERT_NOT_CHAIN(om); -} - -void -net_buf_simple_add_le24(struct os_mbuf *om, uint32_t val) -{ - val = htole32(val); - os_mbuf_append(om, &val, 3); - ASSERT_NOT_CHAIN(om); -} - -void -net_buf_simple_add_be32(struct os_mbuf *om, uint32_t val) -{ - val = htobe32(val); - os_mbuf_append(om, &val, sizeof(val)); - ASSERT_NOT_CHAIN(om); -} - -void -net_buf_simple_add_le32(struct os_mbuf *om, uint32_t val) -{ - val = htole32(val); - os_mbuf_append(om, &val, sizeof(val)); - ASSERT_NOT_CHAIN(om); -} - -void -net_buf_simple_add_u8(struct os_mbuf *om, uint8_t val) -{ - os_mbuf_append(om, &val, 1); - ASSERT_NOT_CHAIN(om); -} - -void -net_buf_simple_push_le16(struct os_mbuf *om, uint16_t val) -{ - uint8_t headroom = om->om_data - &om->om_databuf[om->om_pkthdr_len]; - - assert(headroom >= 2); - om->om_data -= 2; - put_le16(om->om_data, val); - om->om_len += 2; - - if (om->om_pkthdr_len) { - OS_MBUF_PKTHDR(om)->omp_len += 2; - } - ASSERT_NOT_CHAIN(om); -} - -void -net_buf_simple_push_be16(struct os_mbuf *om, uint16_t val) -{ - uint8_t headroom = om->om_data - &om->om_databuf[om->om_pkthdr_len]; - - assert(headroom >= 2); - om->om_data -= 2; - put_be16(om->om_data, val); - om->om_len += 2; - - if (om->om_pkthdr_len) { - OS_MBUF_PKTHDR(om)->omp_len += 2; - } - ASSERT_NOT_CHAIN(om); -} - -void -net_buf_simple_push_be24(struct os_mbuf *om, uint32_t val) -{ - uint8_t headroom = om->om_data - &om->om_databuf[om->om_pkthdr_len]; - - assert(headroom >= 3); - om->om_data -= 3; - put_be24(om->om_data, val); - om->om_len += 3; - - if (om->om_pkthdr_len) { - OS_MBUF_PKTHDR(om)->omp_len += 3; - } - ASSERT_NOT_CHAIN(om); -} - -void -net_buf_simple_push_u8(struct os_mbuf *om, uint8_t val) -{ - uint8_t headroom = om->om_data - &om->om_databuf[om->om_pkthdr_len]; - - assert(headroom >= 1); - om->om_data -= 1; - om->om_data[0] = val; - om->om_len += 1; - - if (om->om_pkthdr_len) { - OS_MBUF_PKTHDR(om)->omp_len += 1; - } - ASSERT_NOT_CHAIN(om); -} - -void -net_buf_add_zeros(struct os_mbuf *om, uint8_t len) -{ - uint8_t z[len]; - int rc; - - memset(z, 0, len); - - rc = os_mbuf_append(om, z, len); - if(rc) { - assert(0); - } - ASSERT_NOT_CHAIN(om); -} - -void * -net_buf_simple_pull(struct os_mbuf *om, uint8_t len) -{ - os_mbuf_adj(om, len); - return om->om_data; -} - -void * -net_buf_simple_pull_mem(struct os_mbuf *om, uint8_t len) -{ - void *data = om->om_data; - - net_buf_simple_pull(om, len); - return data; -} - -void* -net_buf_simple_add(struct os_mbuf *om, uint8_t len) -{ - void * tmp; - - tmp = os_mbuf_extend(om, len); - ASSERT_NOT_CHAIN(om); - - return tmp; -} - -bool -k_fifo_is_empty(struct ble_npl_eventq *q) -{ - return ble_npl_eventq_is_empty(q); -} - -void * net_buf_get(struct ble_npl_eventq *fifo, int32_t t) -{ - struct ble_npl_event *ev = ble_npl_eventq_get(fifo, 0); - - if (ev) { - return ble_npl_event_get_arg(ev); - } - - return NULL; -} - -uint8_t * -net_buf_simple_push(struct os_mbuf *om, uint8_t len) -{ - uint8_t headroom = om->om_data - &om->om_databuf[om->om_pkthdr_len]; - - assert(headroom >= len); - om->om_data -= len; - om->om_len += len; - - return om->om_data; -} - -void -net_buf_reserve(struct os_mbuf *om, size_t reserve) -{ - /* We need reserve to be done on fresh buf */ - assert(om->om_len == 0); - om->om_data += reserve; -} - -void -k_work_init(struct ble_npl_callout *work, ble_npl_event_fn handler) -{ -#ifndef MYNEWT - ble_npl_callout_init(work, nimble_port_get_dflt_eventq(), handler, NULL); -#else - ble_npl_callout_init(work, ble_npl_eventq_dflt_get(), handler, NULL); -#endif -} - -void -k_delayed_work_init(struct k_delayed_work *w, ble_npl_event_fn *f) -{ -#ifndef MYNEWT - ble_npl_callout_init(&w->work, nimble_port_get_dflt_eventq(), f, NULL); -#else - ble_npl_callout_init(&w->work, ble_npl_eventq_dflt_get(), f, NULL); -#endif -} - -bool -k_delayed_work_pending(struct k_delayed_work *w) -{ - return ble_npl_callout_is_active(&w->work); -} - -void -k_delayed_work_cancel(struct k_delayed_work *w) -{ - ble_npl_callout_stop(&w->work); -} - -void -k_delayed_work_submit(struct k_delayed_work *w, uint32_t ms) -{ - uint32_t ticks; - - if (ble_npl_time_ms_to_ticks(ms, &ticks) != 0) { - assert(0); - } - ble_npl_callout_reset(&w->work, ticks); -} - -void -k_work_submit(struct ble_npl_callout *w) -{ - ble_npl_callout_reset(w, 0); -} - -void -k_work_add_arg(struct ble_npl_callout *w, void *arg) -{ - ble_npl_callout_set_arg(w, arg); -} - -void -k_delayed_work_add_arg(struct k_delayed_work *w, void *arg) -{ - k_work_add_arg(&w->work, arg); -} - -uint32_t -k_delayed_work_remaining_get (struct k_delayed_work *w) -{ - int sr; - ble_npl_time_t t; - - OS_ENTER_CRITICAL(sr); - - t = ble_npl_callout_remaining_ticks(&w->work, ble_npl_time_get()); - - OS_EXIT_CRITICAL(sr); - - return ble_npl_time_ticks_to_ms32(t); -} - -int64_t k_uptime_get(void) -{ - /* We should return ms */ - return ble_npl_time_ticks_to_ms32(ble_npl_time_get()); -} - -uint32_t k_uptime_get_32(void) -{ - return k_uptime_get(); -} - -void k_sleep(int32_t duration) -{ - uint32_t ticks; - - ticks = ble_npl_time_ms_to_ticks32(duration); - - ble_npl_time_delay(ticks); -} - -static uint8_t pub[64]; -static uint8_t priv[32]; -static bool has_pub = false; - -int -bt_dh_key_gen(const uint8_t remote_pk[64], bt_dh_key_cb_t cb) -{ - uint8_t dh[32]; - - if (ble_sm_alg_gen_dhkey((uint8_t *)&remote_pk[0], (uint8_t *)&remote_pk[32], - priv, dh)) { - return -1; - } - - cb(dh); - return 0; -} - -int -bt_rand(void *buf, size_t len) -{ - int rc; - rc = ble_hs_hci_util_rand(buf, len); - if (rc != 0) { - return -1; - } - - return 0; -} - -int -bt_pub_key_gen(struct bt_pub_key_cb *new_cb) -{ - - if (ble_sm_alg_gen_key_pair(pub, priv)) { - assert(0); - return -1; - } - - new_cb->func(pub); - has_pub = true; - - return 0; -} - -uint8_t * -bt_pub_key_get(void) -{ - if (!has_pub) { - return NULL; - } - - return pub; -} - -static int -set_ad(const struct bt_data *ad, size_t ad_len, uint8_t *buf, uint8_t *buf_len) -{ - int i; - - for (i = 0; i < ad_len; i++) { - buf[(*buf_len)++] = ad[i].data_len + 1; - buf[(*buf_len)++] = ad[i].type; - - memcpy(&buf[*buf_len], ad[i].data, - ad[i].data_len); - *buf_len += ad[i].data_len; - } - - return 0; -} - -#if MYNEWT_VAL(BLE_EXT_ADV) -static void -ble_adv_copy_to_ext_param(struct ble_gap_ext_adv_params *ext_param, - const struct ble_gap_adv_params *param) -{ - memset(ext_param, 0, sizeof(*ext_param)); - - ext_param->legacy_pdu = 1; - - if (param->conn_mode != BLE_GAP_CONN_MODE_NON) { - ext_param->connectable = 1; - ext_param->scannable = 1; - } - - ext_param->itvl_max = param->itvl_max; - ext_param->itvl_min = param->itvl_min; - ext_param->channel_map = param->channel_map; - ext_param->high_duty_directed = param->high_duty_cycle; - ext_param->own_addr_type = g_mesh_addr_type; -} - -static int -ble_adv_conf_adv_instance(const struct ble_gap_adv_params *param, int *instance) -{ - struct ble_gap_ext_adv_params ext_params; - struct ble_gap_adv_params *cur_conf; - int err = 0; - - if (param->conn_mode == BLE_GAP_CONN_MODE_NON) { - *instance = BT_MESH_ADV_INST; - cur_conf = &ble_adv_cur_conf[BT_MESH_ADV_IDX]; - } else { -#if MYNEWT_VAL(BLE_MESH_PROXY) - *instance = BT_MESH_ADV_GATT_INST; - cur_conf = &ble_adv_cur_conf[BT_MESH_GATT_IDX]; -#else - assert(0); -#endif - } - - /* Checking interval max as it has to be in place if instance was configured - * before. - */ - if (cur_conf->itvl_max == 0) { - goto configure; - } - - if (memcmp(param, cur_conf, sizeof(*cur_conf)) == 0) { - /* Same parameters - skip reconfiguring */ - goto done; - } - - ble_gap_ext_adv_stop(*instance); - err = ble_gap_ext_adv_remove(*instance); - if (err) { - assert(0); - goto done; - } - -configure: - ble_adv_copy_to_ext_param(&ext_params, param); - - err = ble_gap_ext_adv_configure(*instance, &ext_params, 0, - ble_adv_gap_mesh_cb, NULL); - if (!err) { - memcpy(cur_conf, param, sizeof(*cur_conf)); - } - -done: - return err; -} - -int -bt_le_adv_start(const struct ble_gap_adv_params *param, - const struct bt_data *ad, size_t ad_len, - const struct bt_data *sd, size_t sd_len) -{ - struct os_mbuf *data; - int instance; - int err; - uint8_t buf[BLE_HS_ADV_MAX_SZ]; - uint8_t buf_len = 0; - - err = ble_adv_conf_adv_instance(param, &instance); - if (err) { - return err; - } - - if (ad_len > 0) { - err = set_ad(ad, ad_len, buf, &buf_len); - if (err) { - return err; - } - - /* For now let's use msys pool. We are not putting more then legacy */ - data = os_msys_get_pkthdr(BLE_HS_ADV_MAX_SZ, 0); - if (!data) { - return OS_ENOMEM; - } - - err = os_mbuf_append(data, buf, buf_len); - if (err) { - goto error; - } - - err = ble_gap_ext_adv_set_data(instance, data); - if (err) { - return err; - } - - data = NULL; - } - - if (sd_len > 0) { - buf_len = 0; - - err = set_ad(sd, sd_len, buf, &buf_len); - if (err) { - return err; - } - - /* For now let's use msys pool. We are not putting more then legace*/ - data = os_msys_get_pkthdr(BLE_HS_ADV_MAX_SZ, 0); - if (!data) { - return OS_ENOMEM; - } - - err = os_mbuf_append(data, buf, buf_len); - if (err) { - goto error; - } - - err = ble_gap_ext_adv_rsp_set_data(instance, data); - if (err) { - goto error; - } - } - - /*TODO: We could use duration and max events in the future */ - err = ble_gap_ext_adv_start(instance, 0, 0); - return err; - -error: - if (data) { - os_mbuf_free_chain(data); - } - - return err; -} - -int bt_le_adv_stop(bool proxy) -{ -#if MYNEWT_VAL(BLE_MESH_PROXY) - int rc; - - if (proxy) { - rc = ble_gap_ext_adv_stop(BT_MESH_ADV_GATT_INST); - } else { - rc = ble_gap_ext_adv_stop(BT_MESH_ADV_INST); - } - - return rc; -#else - return ble_gap_ext_adv_stop(BT_MESH_ADV_INST); -#endif -} - -#else - -int -bt_le_adv_start(const struct ble_gap_adv_params *param, - const struct bt_data *ad, size_t ad_len, - const struct bt_data *sd, size_t sd_len) -{ - uint8_t buf[BLE_HS_ADV_MAX_SZ]; - uint8_t buf_len = 0; - int err; - - err = set_ad(ad, ad_len, buf, &buf_len); - if (err) { - return err; - } - - err = ble_gap_adv_set_data(buf, buf_len); - if (err != 0) { - return err; - } - - if (sd) { - buf_len = 0; - - err = set_ad(sd, sd_len, buf, &buf_len); - if (err) { - BT_ERR("Advertising failed: err %d", err); - return err; - } - - err = ble_gap_adv_rsp_set_data(buf, buf_len); - if (err != 0) { - BT_ERR("Advertising failed: err %d", err); - return err; - } - } - - err = ble_gap_adv_start(g_mesh_addr_type, NULL, BLE_HS_FOREVER, param, - NULL, NULL); - if (err) { - BT_ERR("Advertising failed: err %d", err); - return err; - } - - return 0; -} - -int bt_le_adv_stop(bool proxy) -{ - return ble_gap_adv_stop(); -} - -#endif - -#if MYNEWT_VAL(BLE_MESH_PROXY) -int bt_mesh_proxy_svcs_register(void); -#endif - -void -bt_mesh_register_gatt(void) -{ -#if MYNEWT_VAL(BLE_MESH_PROXY) - bt_mesh_proxy_svcs_register(); -#endif -} - -void net_buf_slist_init(struct net_buf_slist_t *list) -{ - STAILQ_INIT(list); -} - -bool net_buf_slist_is_empty(struct net_buf_slist_t *list) -{ - return STAILQ_EMPTY(list); -} - -struct os_mbuf *net_buf_slist_peek_head(struct net_buf_slist_t *list) -{ - struct os_mbuf_pkthdr *pkthdr; - - /* Get mbuf pointer from packet header pointer */ - pkthdr = STAILQ_FIRST(list); - if (!pkthdr) { - return NULL; - } - - return OS_MBUF_PKTHDR_TO_MBUF(pkthdr); -} - -struct os_mbuf *net_buf_slist_peek_next(struct os_mbuf *buf) -{ - struct os_mbuf_pkthdr *pkthdr; - - /* Get mbuf pointer from packet header pointer */ - pkthdr = OS_MBUF_PKTHDR(buf); - pkthdr = STAILQ_NEXT(pkthdr, omp_next); - if (!pkthdr) { - return NULL; - } - - return OS_MBUF_PKTHDR_TO_MBUF(pkthdr); -} - -struct os_mbuf *net_buf_slist_get(struct net_buf_slist_t *list) -{ - os_sr_t sr; - struct os_mbuf *m; - - m = net_buf_slist_peek_head(list); - if (!m) { - return NULL; - } - - /* Remove from queue */ - OS_ENTER_CRITICAL(sr); - STAILQ_REMOVE_HEAD(list, omp_next); - OS_EXIT_CRITICAL(sr); - return m; -} - -void net_buf_slist_put(struct net_buf_slist_t *list, struct os_mbuf *buf) -{ - struct os_mbuf_pkthdr *pkthdr; - - pkthdr = OS_MBUF_PKTHDR(buf); - STAILQ_INSERT_TAIL(list, pkthdr, omp_next); -} - -void net_buf_slist_remove(struct net_buf_slist_t *list, struct os_mbuf *prev, - struct os_mbuf *cur) -{ - struct os_mbuf_pkthdr *pkthdr, *cur_pkthdr; - - cur_pkthdr = OS_MBUF_PKTHDR(cur); - - STAILQ_FOREACH(pkthdr, list, omp_next) { - if (cur_pkthdr == pkthdr) { - STAILQ_REMOVE(list, cur_pkthdr, os_mbuf_pkthdr, omp_next); - break; - } - } -} - -void net_buf_slist_merge_slist(struct net_buf_slist_t *list, - struct net_buf_slist_t *list_to_append) -{ - if (!STAILQ_EMPTY(list_to_append)) { - *(list)->stqh_last = list_to_append->stqh_first; - (list)->stqh_last = list_to_append->stqh_last; - STAILQ_INIT(list_to_append); - } -} - -/** Memory slab methods */ -extern void k_mem_slab_free(struct k_mem_slab *slab, void **mem) -{ - **(char ***)mem = slab->free_list; - slab->free_list = *(char **)mem; - slab->num_used--; -} - -extern int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem) -{ - int result; - - if (slab->free_list != NULL) { - /* take a free block */ - *mem = slab->free_list; - slab->free_list = *(char **)(slab->free_list); - slab->num_used++; - result = 0; - } else { - *mem = NULL; - result = -ENOMEM; - } - return result; -} - -int create_free_list(struct k_mem_slab *slab) -{ - uint32_t j; - char *p; - - if(((slab->block_size | (uintptr_t)slab->buffer) & - (sizeof(void *) - 1)) != 0) { - return -EINVAL; - } - - slab->free_list = NULL; - p = slab->buffer; - - for (j = 0U; j < slab->num_blocks; j++) { - *(char **)p = slab->free_list; - slab->free_list = p; - p += slab->block_size; - } - return 0; -} - -#if MYNEWT_VAL(BLE_MESH_SETTINGS) - -int settings_bytes_from_str(char *val_str, void *vp, int *len) -{ - *len = base64_decode(val_str, vp); - return 0; -} - -char *settings_str_from_bytes(const void *vp, int vp_len, - char *buf, int buf_len) -{ - if (BASE64_ENCODE_SIZE(vp_len) > buf_len) { - return NULL; - } - - base64_encode(vp, vp_len, buf, 1); - - return buf; -} - -#endif /* MYNEWT_VAL(BLE_MESH_SETTINGS) */ -#endif /* MYNEWT_VAL(BLE_MESH) */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/health_cli.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/health_cli.c deleted file mode 100644 index 40da8de6d..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/health_cli.c +++ /dev/null @@ -1,551 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG - -#include -#include -#include - -#include "../include/mesh/mesh.h" -#include "mesh_priv.h" -#include "adv.h" -#include "net.h" -#include "transport.h" -#include "foundation.h" -#include "../include/mesh/health_cli.h" - -static int32_t msg_timeout = K_SECONDS(5); - -static struct bt_mesh_health_cli *health_cli; - -struct health_fault_param { - uint16_t cid; - uint8_t *expect_test_id; - uint8_t *test_id; - uint8_t *faults; - size_t *fault_count; -}; - -static void health_fault_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct health_fault_param *param; - uint8_t test_id; - uint16_t cid; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (health_cli->op_pending != OP_HEALTH_FAULT_STATUS) { - BT_WARN("Unexpected Health Fault Status message"); - return; - } - - param = health_cli->op_param; - - test_id = net_buf_simple_pull_u8(buf); - if (param->expect_test_id && test_id != *param->expect_test_id) { - BT_WARN("Health fault with unexpected Test ID"); - return; - } - - cid = net_buf_simple_pull_le16(buf); - if (cid != param->cid) { - BT_WARN("Health fault with unexpected Company ID"); - return; - } - - if (param->test_id) { - *param->test_id = test_id; - } - - if (buf->om_len > *param->fault_count) { - BT_WARN("Got more faults than there's space for"); - } else { - *param->fault_count = buf->om_len; - } - - memcpy(param->faults, buf->om_data, *param->fault_count); - - k_sem_give(&health_cli->op_sync); -} - -static void health_current_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct bt_mesh_health_cli *cli = model->user_data; - uint8_t test_id; - uint16_t cid; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - test_id = net_buf_simple_pull_u8(buf); - cid = net_buf_simple_pull_le16(buf); - - BT_DBG("Test ID 0x%02x Company ID 0x%04x Fault Count %u", - test_id, cid, buf->om_len); - - if (!cli->current_status) { - BT_WARN("No Current Status callback available"); - return; - } - - cli->current_status(cli, ctx->addr, test_id, cid, buf->om_data, buf->om_len); -} - -struct health_period_param { - uint8_t *divisor; -}; - -static void health_period_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct health_period_param *param; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (health_cli->op_pending != OP_HEALTH_PERIOD_STATUS) { - BT_WARN("Unexpected Health Period Status message"); - return; - } - - param = health_cli->op_param; - - *param->divisor = net_buf_simple_pull_u8(buf); - - k_sem_give(&health_cli->op_sync); -} - -struct health_attention_param { - uint8_t *attention; -}; - -static void health_attention_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct health_attention_param *param; - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (health_cli->op_pending != OP_ATTENTION_STATUS) { - BT_WARN("Unexpected Health Attention Status message"); - return; - } - - param = health_cli->op_param; - - if (param->attention) { - *param->attention = net_buf_simple_pull_u8(buf); - } - - k_sem_give(&health_cli->op_sync); -} - -const struct bt_mesh_model_op bt_mesh_health_cli_op[] = { - { OP_HEALTH_FAULT_STATUS, 3, health_fault_status }, - { OP_HEALTH_CURRENT_STATUS, 3, health_current_status }, - { OP_HEALTH_PERIOD_STATUS, 1, health_period_status }, - { OP_ATTENTION_STATUS, 1, health_attention_status }, - BT_MESH_MODEL_OP_END, -}; - -static int cli_prepare(void *param, uint32_t op) -{ - if (!health_cli) { - BT_ERR("No available Health Client context!"); - return -EINVAL; - } - - if (health_cli->op_pending) { - BT_WARN("Another synchronous operation pending"); - return -EBUSY; - } - - health_cli->op_param = param; - health_cli->op_pending = op; - - return 0; -} - -static void cli_reset(void) -{ - health_cli->op_pending = 0; - health_cli->op_param = NULL; -} - -static int cli_wait(void) -{ - int err; - - err = k_sem_take(&health_cli->op_sync, msg_timeout); - - cli_reset(); - - return err; -} - -int bt_mesh_health_attention_get(uint16_t addr, uint16_t app_idx, uint8_t *attention) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_ATTENTION_GET, 0); - struct bt_mesh_msg_ctx ctx = { - .app_idx = app_idx, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct health_attention_param param = { - .attention = attention, - }; - int err; - - err = cli_prepare(¶m, OP_ATTENTION_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_ATTENTION_GET); - - err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_health_attention_set(uint16_t addr, uint16_t app_idx, uint8_t attention, - uint8_t *updated_attention) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_ATTENTION_SET, 1); - struct bt_mesh_msg_ctx ctx = { - .app_idx = app_idx, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct health_attention_param param = { - .attention = updated_attention, - }; - int err; - - err = cli_prepare(¶m, OP_ATTENTION_STATUS); - if (err) { - goto done; - } - - if (updated_attention) { - bt_mesh_model_msg_init(msg, OP_ATTENTION_SET); - } else { - bt_mesh_model_msg_init(msg, OP_ATTENTION_SET_UNREL); - } - - net_buf_simple_add_u8(msg, attention); - - err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!updated_attention) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_health_period_get(uint16_t addr, uint16_t app_idx, uint8_t *divisor) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_PERIOD_GET, 0); - struct bt_mesh_msg_ctx ctx = { - .app_idx = app_idx, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct health_period_param param = { - .divisor = divisor, - }; - int err; - - err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_HEALTH_PERIOD_GET); - - err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_health_period_set(uint16_t addr, uint16_t app_idx, uint8_t divisor, - uint8_t *updated_divisor) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_PERIOD_SET, 1); - struct bt_mesh_msg_ctx ctx = { - .app_idx = app_idx, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct health_period_param param = { - .divisor = updated_divisor, - }; - int err; - - err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS); - if (err) { - goto done; - } - - if (updated_divisor) { - bt_mesh_model_msg_init(msg, OP_HEALTH_PERIOD_SET); - } else { - bt_mesh_model_msg_init(msg, OP_HEALTH_PERIOD_SET_UNREL); - } - - net_buf_simple_add_u8(msg, divisor); - - err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!updated_divisor) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_health_fault_test(uint16_t addr, uint16_t app_idx, uint16_t cid, - uint8_t test_id, uint8_t *faults, - size_t *fault_count) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_FAULT_TEST, 3); - struct bt_mesh_msg_ctx ctx = { - .app_idx = app_idx, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct health_fault_param param = { - .cid = cid, - .expect_test_id = &test_id, - .faults = faults, - .fault_count = fault_count, - }; - int err; - - err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS); - if (err) { - goto done; - } - - if (faults) { - bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_TEST); - } else { - bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_TEST_UNREL); - } - - net_buf_simple_add_u8(msg, test_id); - net_buf_simple_add_le16(msg, cid); - - err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!faults) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_health_fault_clear(uint16_t addr, uint16_t app_idx, uint16_t cid, - uint8_t *test_id, uint8_t *faults, - size_t *fault_count) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_FAULT_CLEAR, 2); - struct bt_mesh_msg_ctx ctx = { - .app_idx = app_idx, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct health_fault_param param = { - .cid = cid, - .test_id = test_id, - .faults = faults, - .fault_count = fault_count, - }; - int err; - - err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS); - if (err) { - goto done; - } - - if (test_id) { - bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_CLEAR); - } else { - bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_CLEAR_UNREL); - } - - net_buf_simple_add_le16(msg, cid); - - err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - if (!test_id) { - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_health_fault_get(uint16_t addr, uint16_t app_idx, uint16_t cid, - uint8_t *test_id, uint8_t *faults, - size_t *fault_count) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_FAULT_GET, 2); - struct bt_mesh_msg_ctx ctx = { - .app_idx = app_idx, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct health_fault_param param = { - .cid = cid, - .test_id = test_id, - .faults = faults, - .fault_count = fault_count, - }; - int err; - - err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS); - if (err) { - goto done; - } - - bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_GET); - net_buf_simple_add_le16(msg, cid); - - err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - cli_reset(); - goto done; - } - - err = cli_wait(); -done: - os_mbuf_free_chain(msg); - return err; -} - -int32_t bt_mesh_health_cli_timeout_get(void) -{ - return msg_timeout; -} - -void bt_mesh_health_cli_timeout_set(int32_t timeout) -{ - msg_timeout = timeout; -} - -int bt_mesh_health_cli_set(struct bt_mesh_model *model) -{ - if (!model->user_data) { - BT_ERR("No Health Client context for given model"); - return -EINVAL; - } - - health_cli = model->user_data; - msg_timeout = 2 * MSEC_PER_SEC; - - return 0; -} - -static int health_cli_init(struct bt_mesh_model *model) -{ - struct bt_mesh_health_cli *cli = model->user_data; - - BT_DBG("primary %u", bt_mesh_model_in_primary(model)); - - if (!cli) { - BT_ERR("No Health Client context provided"); - return -EINVAL; - } - - cli = model->user_data; - cli->model = model; - - k_sem_init(&cli->op_sync, 0, 1); - - /* Set the default health client pointer */ - if (!health_cli) { - health_cli = cli; - } - - return 0; -} - -const struct bt_mesh_model_cb bt_mesh_health_cli_cb = { - .init = health_cli_init, -}; -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/health_srv.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/health_srv.c deleted file mode 100644 index d8951939a..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/health_srv.c +++ /dev/null @@ -1,452 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG - -#include -#include -#include - -#include "../include/mesh/mesh.h" -#include "mesh_priv.h" -#include "adv.h" -#include "net.h" -#include "transport.h" -#include "access.h" -#include "foundation.h" - -#define HEALTH_TEST_STANDARD 0x00 - -/* Health Server context of the primary element */ -struct bt_mesh_health_srv *health_srv; - -static void health_get_registered(struct bt_mesh_model *mod, - uint16_t company_id, - struct os_mbuf *msg) -{ - struct bt_mesh_health_srv *srv = mod->user_data; - uint8_t *test_id; - - BT_DBG("Company ID 0x%04x", company_id); - - bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_STATUS); - - test_id = net_buf_simple_add(msg, 1); - net_buf_simple_add_le16(msg, company_id); - - if (srv->cb && srv->cb->fault_get_reg) { - uint8_t fault_count = net_buf_simple_tailroom(msg) - 4; - int err; - - err = srv->cb->fault_get_reg(mod, company_id, test_id, - net_buf_simple_tail(msg), - &fault_count); - if (err) { - BT_ERR("Failed to get faults (err %d)", err); - *test_id = HEALTH_TEST_STANDARD; - } else { - net_buf_simple_add(msg, fault_count); - } - } else { - BT_WARN("No callback for getting faults"); - *test_id = HEALTH_TEST_STANDARD; - } -} - -static size_t health_get_current(struct bt_mesh_model *mod, - struct os_mbuf *msg) -{ - struct bt_mesh_health_srv *srv = mod->user_data; - const struct bt_mesh_comp *comp; - uint8_t *test_id, *company_ptr; - uint16_t company_id; - uint8_t fault_count; - int err; - - bt_mesh_model_msg_init(msg, OP_HEALTH_CURRENT_STATUS); - - test_id = net_buf_simple_add(msg, 1); - company_ptr = net_buf_simple_add(msg, sizeof(company_id)); - comp = bt_mesh_comp_get(); - - if (srv->cb && srv->cb->fault_get_cur) { - fault_count = net_buf_simple_tailroom(msg); - err = srv->cb->fault_get_cur(mod, test_id, &company_id, - net_buf_simple_tail(msg), - &fault_count); - if (err) { - BT_ERR("Failed to get faults (err %d)", err); - sys_put_le16(comp->cid, company_ptr); - *test_id = HEALTH_TEST_STANDARD; - fault_count = 0; - } else { - sys_put_le16(company_id, company_ptr); - net_buf_simple_add(msg, fault_count); - } - } else { - BT_WARN("No callback for getting faults"); - sys_put_le16(comp->cid, company_ptr); - *test_id = HEALTH_TEST_STANDARD; - fault_count = 0; - } - - return fault_count; -} - -static void health_fault_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); - uint16_t company_id; - - company_id = net_buf_simple_pull_le16(buf); - - BT_DBG("company_id 0x%04x", company_id); - - health_get_registered(model, company_id, sdu); - - if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) { - BT_ERR("Unable to send Health Current Status response"); - } - - os_mbuf_free_chain(sdu); -} - -static void health_fault_clear_unrel(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct bt_mesh_health_srv *srv = model->user_data; - uint16_t company_id; - - company_id = net_buf_simple_pull_le16(buf); - - BT_DBG("company_id 0x%04x", company_id); - - if (srv->cb && srv->cb->fault_clear) { - srv->cb->fault_clear(model, company_id); - } -} - -static void health_fault_clear(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); - struct bt_mesh_health_srv *srv = model->user_data; - uint16_t company_id; - - company_id = net_buf_simple_pull_le16(buf); - - BT_DBG("company_id 0x%04x", company_id); - - if (srv->cb && srv->cb->fault_clear) { - srv->cb->fault_clear(model, company_id); - } - - health_get_registered(model, company_id, sdu); - - if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) { - BT_ERR("Unable to send Health Current Status response"); - } - - os_mbuf_free_chain(sdu); -} - -static void health_fault_test_unrel(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct bt_mesh_health_srv *srv = model->user_data; - uint16_t company_id; - uint8_t test_id; - - test_id = net_buf_simple_pull_u8(buf); - company_id = net_buf_simple_pull_le16(buf); - - BT_DBG("test 0x%02x company 0x%04x", test_id, company_id); - - if (srv->cb && srv->cb->fault_test) { - srv->cb->fault_test(model, test_id, company_id); - } -} - -static void health_fault_test(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); - struct bt_mesh_health_srv *srv = model->user_data; - uint16_t company_id; - uint8_t test_id; - - BT_DBG(""); - - test_id = net_buf_simple_pull_u8(buf); - company_id = net_buf_simple_pull_le16(buf); - - BT_DBG("test 0x%02x company 0x%04x", test_id, company_id); - - if (srv->cb && srv->cb->fault_test) { - int err; - - err = srv->cb->fault_test(model, test_id, company_id); - if (err) { - BT_WARN("Running fault test failed with err %d", err); - goto done; - } - } - - health_get_registered(model, company_id, sdu); - - if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) { - BT_ERR("Unable to send Health Current Status response"); - } - -done: - os_mbuf_free_chain(sdu); -} - -static void send_attention_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_ATTENTION_STATUS, 1); - struct bt_mesh_health_srv *srv = model->user_data; - uint8_t time; - - time = k_delayed_work_remaining_get(&srv->attn_timer) / 1000; - BT_DBG("%u second%s", time, (time == 1) ? "" : "s"); - - bt_mesh_model_msg_init(msg, OP_ATTENTION_STATUS); - - net_buf_simple_add_u8(msg, time); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Attention Status"); - } - - os_mbuf_free_chain(msg); -} - -static void attention_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG(""); - - send_attention_status(model, ctx); -} - -static void attention_set_unrel(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint8_t time; - - time = net_buf_simple_pull_u8(buf); - - BT_DBG("%u second%s", time, (time == 1) ? "" : "s"); - - bt_mesh_attention(model, time); -} - -static void attention_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG(""); - - attention_set_unrel(model, ctx, buf); - - send_attention_status(model, ctx); -} - -static void send_health_period_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx) -{ - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_PERIOD_STATUS, 1); - - bt_mesh_model_msg_init(msg, OP_HEALTH_PERIOD_STATUS); - - net_buf_simple_add_u8(msg, model->pub->period_div); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Unable to send Health Period Status"); - } - - os_mbuf_free_chain(msg); -} - -static void health_period_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG(""); - - send_health_period_status(model, ctx); -} - -static void health_period_set_unrel(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - uint8_t period; - - period = net_buf_simple_pull_u8(buf); - if (period > 15) { - BT_WARN("Prohibited period value %u", period); - return; - } - - BT_DBG("period %u", period); - - model->pub->period_div = period; -} - -static void health_period_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG(""); - - health_period_set_unrel(model, ctx, buf); - - send_health_period_status(model, ctx); -} - -const struct bt_mesh_model_op bt_mesh_health_srv_op[] = { - { OP_HEALTH_FAULT_GET, 2, health_fault_get }, - { OP_HEALTH_FAULT_CLEAR, 2, health_fault_clear }, - { OP_HEALTH_FAULT_CLEAR_UNREL, 2, health_fault_clear_unrel }, - { OP_HEALTH_FAULT_TEST, 3, health_fault_test }, - { OP_HEALTH_FAULT_TEST_UNREL, 3, health_fault_test_unrel }, - { OP_HEALTH_PERIOD_GET, 0, health_period_get }, - { OP_HEALTH_PERIOD_SET, 1, health_period_set }, - { OP_HEALTH_PERIOD_SET_UNREL, 1, health_period_set_unrel }, - { OP_ATTENTION_GET, 0, attention_get }, - { OP_ATTENTION_SET, 1, attention_set }, - { OP_ATTENTION_SET_UNREL, 1, attention_set_unrel }, - BT_MESH_MODEL_OP_END, -}; - -static int health_pub_update(struct bt_mesh_model *mod) -{ - struct bt_mesh_model_pub *pub = mod->pub; - size_t count; - - BT_DBG(""); - - count = health_get_current(mod, pub->msg); - if (count) { - pub->fast_period = 1U; - } else { - pub->fast_period = 0U; - } - - return 0; -} - -int bt_mesh_fault_update(struct bt_mesh_elem *elem) -{ - struct bt_mesh_model *mod; - - mod = bt_mesh_model_find(elem, BT_MESH_MODEL_ID_HEALTH_SRV); - if (!mod) { - return -EINVAL; - } - - /* Let periodic publishing, if enabled, take care of sending the - * Health Current Status. - */ - if (bt_mesh_model_pub_period_get(mod)) { - return 0; - } - - health_pub_update(mod); - - return bt_mesh_model_publish(mod); -} - -static void attention_off(struct ble_npl_event *work) -{ - struct bt_mesh_health_srv *srv = ble_npl_event_get_arg(work); - BT_DBG(""); - - if (srv->cb && srv->cb->attn_off) { - srv->cb->attn_off(srv->model); - } -} - -static int health_srv_init(struct bt_mesh_model *model) -{ - struct bt_mesh_health_srv *srv = model->user_data; - - if (!srv) { - BT_ERR("No Health Server context provided"); - return -EINVAL; - } - - if (!model->pub) { - BT_ERR("Health Server has no publication support"); - return -EINVAL; - } - - model->pub->update = health_pub_update; - - k_delayed_work_init(&srv->attn_timer, attention_off); - k_delayed_work_add_arg(&srv->attn_timer, srv); - - srv->model = model; - - if (bt_mesh_model_in_primary(model)) { - health_srv = srv; - } - - return 0; -} - -const struct bt_mesh_model_cb bt_mesh_health_srv_cb = { - .init = health_srv_init, -}; - -void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time) -{ - struct bt_mesh_health_srv *srv; - - BT_DBG("bt_mesh_attention"); - if (!model) { - srv = health_srv; - if (!srv) { - BT_WARN("No Health Server available"); - return; - } - - model = srv->model; - } else { - srv = model->user_data; - } - - if (time) { - if (srv->cb && srv->cb->attn_on) { - srv->cb->attn_on(model); - } - - k_delayed_work_submit(&srv->attn_timer, time * 1000); - } else { - k_delayed_work_cancel(&srv->attn_timer); - - if (srv->cb && srv->cb->attn_off) { - srv->cb->attn_off(model); - } - } -} -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/heartbeat.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/heartbeat.c deleted file mode 100644 index 6948f20d0..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/heartbeat.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_HEARTBEAT_LOG - -#include "mesh_priv.h" -#include "net.h" -#include "rpl.h" -#include "access.h" -#include "lpn.h" -#include "settings.h" -#include "transport.h" -#include "heartbeat.h" -#include "foundation.h" -#include "../include/mesh/glue.h" - -struct bt_mesh_hb_cb hb_cb; - -static struct bt_mesh_hb_pub pub; -static struct bt_mesh_hb_sub sub; -static struct k_delayed_work sub_timer; -static struct k_delayed_work pub_timer; - -static int64_t sub_remaining(void) -{ - if (sub.dst == BT_MESH_ADDR_UNASSIGNED) { - return 0U; - } - - return k_delayed_work_remaining_get(&sub_timer) / MSEC_PER_SEC; -} - -static void hb_publish_end_cb(int err, void *cb_data) -{ - if (pub.period && pub.count > 1) { - k_delayed_work_submit(&pub_timer, K_SECONDS(pub.period)); - } - - if (pub.count != 0xffff) { - pub.count--; - } -} - -static void notify_recv(uint8_t hops, uint16_t feat) -{ - sub.remaining = sub_remaining(); - - if (hb_cb.recv != NULL) { - hb_cb.recv(&sub, hops, feat); - } -} - -static void notify_sub_end(void) -{ - sub.remaining = 0; - - if (hb_cb.sub_end != NULL) { - hb_cb.sub_end(&sub); - } -} - -static void sub_end(struct ble_npl_event *work) -{ - notify_sub_end(); -} - -static int heartbeat_send(const struct bt_mesh_send_cb *cb, void *cb_data) -{ - uint16_t feat = 0U; - struct __packed { - uint8_t init_ttl; - uint16_t feat; - } hb; - struct bt_mesh_msg_ctx ctx = { - .net_idx = pub.net_idx, - .app_idx = BT_MESH_KEY_UNUSED, - .addr = pub.dst, - .send_ttl = pub.ttl, - }; - struct bt_mesh_net_tx tx = { - .sub = bt_mesh_subnet_get(pub.net_idx), - .ctx = &ctx, - .src = bt_mesh_primary_addr(), - .xmit = bt_mesh_net_transmit_get(), - }; - - /* Do nothing if heartbeat publication is not enabled */ - if (pub.dst == BT_MESH_ADDR_UNASSIGNED) { - return 0U; - } - - hb.init_ttl = pub.ttl; - - if (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED) { - feat |= BT_MESH_FEAT_RELAY; - } - - if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) { - feat |= BT_MESH_FEAT_PROXY; - } - - if (bt_mesh_friend_get() == BT_MESH_FRIEND_ENABLED) { - feat |= BT_MESH_FEAT_FRIEND; - } - - if (bt_mesh_lpn_established()) { - feat |= BT_MESH_FEAT_LOW_POWER; - } - - hb.feat = sys_cpu_to_be16(feat); - - BT_DBG("InitTTL %u feat 0x%04x", pub.ttl, feat); - - return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_HEARTBEAT, &hb, sizeof(hb), - cb, cb_data); -} - -static void hb_publish_start_cb(uint16_t duration, int err, void *cb_data) -{ - if (err) { - hb_publish_end_cb(err, cb_data); - } -} - -static void hb_publish(struct ble_npl_event *work) -{ - static const struct bt_mesh_send_cb publish_cb = { - .start = hb_publish_start_cb, - .end = hb_publish_end_cb, - }; - struct bt_mesh_subnet *sub; - int err; - - BT_DBG("hb_pub.count: %u", pub.count); - - sub = bt_mesh_subnet_get(pub.net_idx); - if (!sub) { - BT_ERR("No matching subnet for idx 0x%02x", pub.net_idx); - pub.dst = BT_MESH_ADDR_UNASSIGNED; - return; - } - - if (pub.count == 0U) { - return; - } - - err = heartbeat_send(&publish_cb, NULL); - if (err) { - hb_publish_end_cb(err, NULL); - } -} - -int bt_mesh_hb_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) -{ - uint8_t init_ttl, hops; - uint16_t feat; - - if (buf->om_len < 3) { - BT_ERR("Too short heartbeat message"); - return -EINVAL; - } - - init_ttl = (net_buf_simple_pull_u8(buf) & 0x7f); - feat = net_buf_simple_pull_be16(buf); - - hops = (init_ttl - rx->ctx.recv_ttl + 1); - - if (rx->ctx.addr != sub.src || rx->ctx.recv_dst != sub.dst) { - BT_DBG("No subscription for received heartbeat"); - return 0; - } - - if (!k_delayed_work_pending(&sub_timer)) { - BT_DBG("Heartbeat subscription period expired"); - return 0; - } - - sub.min_hops = MIN(sub.min_hops, hops); - sub.max_hops = MAX(sub.max_hops, hops); - - if (sub.count < 0xffff) { - sub.count++; - } - - BT_DBG("src 0x%04x TTL %u InitTTL %u (%u hop%s) feat 0x%04x", - rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, - (hops == 1U) ? "" : "s", feat); - - notify_recv(hops, feat); - - return 0; -} - -static void pub_disable(void) -{ - BT_DBG(""); - - pub.dst = BT_MESH_ADDR_UNASSIGNED; - pub.count = 0U; - pub.ttl = 0U; - pub.period = 0U; - - k_delayed_work_cancel(&pub_timer); -} - -uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *new_pub) -{ - if (!new_pub || new_pub->dst == BT_MESH_ADDR_UNASSIGNED) { - pub_disable(); - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && - bt_mesh_is_provisioned()) { - bt_mesh_store_hb_pub(); - } - - return STATUS_SUCCESS; - } - - if (!bt_mesh_subnet_get(new_pub->net_idx)) { - BT_ERR("Unknown NetKey 0x%04x", new_pub->net_idx); - return STATUS_INVALID_NETKEY; - } - - new_pub->feat &= BT_MESH_FEAT_SUPPORTED; - pub = *new_pub; - - if (!bt_mesh_is_provisioned()) { - return STATUS_SUCCESS; - } - - /* The first Heartbeat message shall be published as soon as possible - * after the Heartbeat Publication Period state has been configured for - * periodic publishing. - */ - if (pub.period && pub.count) { - k_delayed_work_submit(&pub_timer, K_NO_WAIT); - } else { - k_delayed_work_cancel(&pub_timer); - } - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_hb_pub(); - } - - return STATUS_SUCCESS; -} - -void bt_mesh_hb_pub_get(struct bt_mesh_hb_pub *get) -{ - *get = pub; -} - -uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period) -{ - if (src != BT_MESH_ADDR_UNASSIGNED && !BT_MESH_ADDR_IS_UNICAST(src)) { - BT_WARN("Prohibited source address"); - return STATUS_INVALID_ADDRESS; - } - - if (BT_MESH_ADDR_IS_VIRTUAL(dst) || BT_MESH_ADDR_IS_RFU(dst) || - (BT_MESH_ADDR_IS_UNICAST(dst) && dst != bt_mesh_primary_addr())) { - BT_WARN("Prohibited destination address"); - return STATUS_INVALID_ADDRESS; - } - - if (period > (1U << 16)) { - BT_WARN("Prohibited subscription period %u s", period); - return STATUS_CANNOT_SET; - } - - /* Only an explicit address change to unassigned should trigger clearing - * of the values according to MESH/NODE/CFG/HBS/BV-02-C. - */ - if (src == BT_MESH_ADDR_UNASSIGNED || dst == BT_MESH_ADDR_UNASSIGNED) { - sub.src = BT_MESH_ADDR_UNASSIGNED; - sub.dst = BT_MESH_ADDR_UNASSIGNED; - sub.min_hops = 0U; - sub.max_hops = 0U; - sub.count = 0U; - sub.period = sub.period - sub_remaining(); - k_delayed_work_cancel(&sub_timer); - notify_sub_end(); - } else if (period) { - sub.src = src; - sub.dst = dst; - sub.min_hops = BT_MESH_TTL_MAX; - sub.max_hops = 0U; - sub.count = 0U; - sub.period = period; - k_delayed_work_submit(&sub_timer, K_SECONDS(period)); - } else { - /* Clearing the period should stop heartbeat subscription - * without clearing the parameters, so we can still read them. - */ - sub.period = sub.period - sub_remaining(); - k_delayed_work_cancel(&sub_timer); - notify_sub_end(); - } - - return STATUS_SUCCESS; -} - -void bt_mesh_hb_sub_get(struct bt_mesh_hb_sub *get) -{ - *get = sub; - get->remaining = sub_remaining(); -} - -void bt_mesh_hb_feature_changed(uint16_t features) -{ - if (pub.dst == BT_MESH_ADDR_UNASSIGNED) { - return; - } - - if (!(pub.feat & features)) { - return; - } - - heartbeat_send(NULL, NULL); -} - -void bt_mesh_hb_init(void) -{ - pub.net_idx = BT_MESH_KEY_UNUSED; - k_delayed_work_init(&pub_timer, hb_publish); - k_delayed_work_init(&sub_timer, sub_end); -} - -void bt_mesh_hb_start(void) -{ - if (pub.count && pub.period) { - BT_DBG("Starting heartbeat publication"); - k_delayed_work_submit(&pub_timer, K_NO_WAIT); - } -} - -void bt_mesh_hb_suspend(void) -{ - k_delayed_work_cancel(&pub_timer); -} - -void bt_mesh_hb_resume(void) -{ - if (pub.period && pub.count) { - BT_DBG("Starting heartbeat publication"); - k_delayed_work_submit(&pub_timer, K_NO_WAIT); - } -} - -#endif /* MYNEWT_VAL(BLE_MESH) */ \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/heartbeat.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/heartbeat.h deleted file mode 100644 index 9cb0ca17e..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/heartbeat.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "../include/mesh/heartbeat.h" - -static inline uint16_t bt_mesh_hb_pwr2(uint8_t val) -{ - if (!val) { - return 0x0000; - } else if (val == 0xff || val == 0x11) { - return 0xffff; - } else { - return (1 << (val - 1)); - } -} - -static inline uint8_t bt_mesh_hb_log(uint32_t val) -{ - if (!val) { - return 0x00; - } else if (val == 0xffff) { - return 0xff; - } else { - return 32 - __builtin_clz(val); - } -} - -void bt_mesh_hb_init(void); -void bt_mesh_hb_start(void); -void bt_mesh_hb_suspend(void); -void bt_mesh_hb_resume(void); - -int bt_mesh_hb_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf); -void bt_mesh_hb_feature_changed(uint16_t features); - -uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *hb_pub); -uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period); diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/light_model.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/light_model.c deleted file mode 100644 index fc8f66180..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/light_model.c +++ /dev/null @@ -1,59 +0,0 @@ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#include "../include/mesh/mesh.h" -#include "nimble/console/console.h" -#include "light_model.h" - - -static uint8_t gen_onoff_state; -static int16_t gen_level_state; - -static void update_light_state(void) -{ - console_printf("Light state: onoff=%d lvl=0x%04x\n", gen_onoff_state, (uint16_t)gen_level_state); -} - -int light_model_gen_onoff_get(struct bt_mesh_model *model, uint8_t *state) -{ - *state = gen_onoff_state; - return 0; -} - -int light_model_gen_onoff_set(struct bt_mesh_model *model, uint8_t state) -{ - gen_onoff_state = state; - update_light_state(); - return 0; -} - -int light_model_gen_level_get(struct bt_mesh_model *model, int16_t *level) -{ - *level = gen_level_state; - return 0; -} - -int light_model_gen_level_set(struct bt_mesh_model *model, int16_t level) -{ - gen_level_state = level; - if ((uint16_t)gen_level_state > 0x0000) { - gen_onoff_state = 1; - } - if ((uint16_t)gen_level_state == 0x0000) { - gen_onoff_state = 0; - } - update_light_state(); - return 0; -} - -int light_model_light_lightness_get(struct bt_mesh_model *model, int16_t *lightness) -{ - return light_model_gen_level_get(model, lightness); -} - -int light_model_light_lightness_set(struct bt_mesh_model *model, int16_t lightness) -{ - return light_model_gen_level_set(model, lightness); -} -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/light_model.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/light_model.h deleted file mode 100644 index 574db5484..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/light_model.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __BT_MESH_LIGHT_MODEL_H -#define __BT_MESH_LIGHT_MODEL_H - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#include "../include/mesh/mesh.h" - -int light_model_gen_onoff_get(struct bt_mesh_model *model, uint8_t *state); -int light_model_gen_onoff_set(struct bt_mesh_model *model, uint8_t state); -int light_model_gen_level_get(struct bt_mesh_model *model, int16_t *level); -int light_model_gen_level_set(struct bt_mesh_model *model, int16_t level); -int light_model_light_lightness_get(struct bt_mesh_model *model, int16_t *lightness); -int light_model_light_lightness_set(struct bt_mesh_model *model, int16_t lightness); - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/lpn.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/lpn.c deleted file mode 100644 index cf0841507..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/lpn.c +++ /dev/null @@ -1,1104 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_LOW_POWER_LOG - -#if MYNEWT_VAL(BLE_MESH_LOW_POWER) - -#include - -#include "../include/mesh/mesh.h" -#include "mesh_priv.h" -#include "crypto.h" -#include "adv.h" -#include "net.h" -#include "transport.h" -#include "heartbeat.h" -#include "access.h" -#include "beacon.h" -#include "foundation.h" -#include "lpn.h" - -#if MYNEWT_VAL(BLE_MESH_LPN_AUTO) -#define LPN_AUTO_TIMEOUT K_SECONDS(MYNEWT_VAL(BLE_MESH_LPN_AUTO_TIMEOUT)) -#else -#define LPN_AUTO_TIMEOUT 0 -#endif - -#define LPN_RECV_DELAY MYNEWT_VAL(BLE_MESH_LPN_RECV_DELAY) -#define SCAN_LATENCY min(MYNEWT_VAL(BLE_MESH_LPN_SCAN_LATENCY), \ - LPN_RECV_DELAY) - -#define FRIEND_REQ_RETRY_TIMEOUT K_SECONDS(MYNEWT_VAL(BLE_MESH_LPN_RETRY_TIMEOUT)) - -#define FRIEND_REQ_WAIT K_MSEC(100) -#define FRIEND_REQ_SCAN K_SECONDS(1) -#define FRIEND_REQ_TIMEOUT (FRIEND_REQ_WAIT + FRIEND_REQ_SCAN) - -#define POLL_RETRY_TIMEOUT K_MSEC(100) - -#define REQ_RETRY_DURATION(lpn) (LPN_RECV_DELAY + (lpn)->adv_duration + \ - (lpn)->recv_win + POLL_RETRY_TIMEOUT) - -#define POLL_TIMEOUT_INIT (MYNEWT_VAL(BLE_MESH_LPN_INIT_POLL_TIMEOUT) * 100) - -#define POLL_TIMEOUT (MYNEWT_VAL(BLE_MESH_LPN_RECV_DELAY) * 100) - -#define REQ_ATTEMPTS_MAX 6 -#define REQ_ATTEMPTS(lpn) MIN(REQ_ATTEMPTS_MAX, \ - POLL_TIMEOUT / REQ_RETRY_DURATION(lpn)) - -#define POLL_TIMEOUT_MAX(lpn) (POLL_TIMEOUT - \ - (REQ_ATTEMPTS(lpn) * REQ_RETRY_DURATION(lpn))) - -#define CLEAR_ATTEMPTS 3 - -#define LPN_CRITERIA ((MYNEWT_VAL(BLE_MESH_LPN_MIN_QUEUE_SIZE)) | \ - (MYNEWT_VAL(BLE_MESH_LPN_RSSI_FACTOR) << 3) | \ - (MYNEWT_VAL(BLE_MESH_LPN_RECV_WIN_FACTOR) << 5)) - -#define POLL_TO(to) { (uint8_t)((to) >> 16), (uint8_t)((to) >> 8), (uint8_t)(to) } -#define LPN_POLL_TO POLL_TO(MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT)) - -/* 2 transmissions, 20ms interval */ -#define POLL_XMIT BT_MESH_TRANSMIT(1, 20) - -static void (*lpn_cb)(uint16_t friend_addr, bool established); - -#if MYNEWT_VAL(BLE_MESH_LOW_POWER_LOG_LVL) == LOG_LEVEL_DEBUG -static const char *state2str(int state) -{ - switch (state) { - case BT_MESH_LPN_DISABLED: - return "disabled"; - case BT_MESH_LPN_CLEAR: - return "clear"; - case BT_MESH_LPN_TIMER: - return "timer"; - case BT_MESH_LPN_ENABLED: - return "enabled"; - case BT_MESH_LPN_REQ_WAIT: - return "req wait"; - case BT_MESH_LPN_WAIT_OFFER: - return "wait offer"; - case BT_MESH_LPN_ESTABLISHED: - return "established"; - case BT_MESH_LPN_RECV_DELAY: - return "recv delay"; - case BT_MESH_LPN_WAIT_UPDATE: - return "wait update"; - default: - return "(unknown)"; - } -} -#endif - -static inline void lpn_set_state(int state) -{ -#if MYNEWT_VAL(BLE_MESH_LOW_POWER_LOG_LVL) == LOG_LEVEL_DEBUG - BT_DBG("%s -> %s", state2str(bt_mesh.lpn.state), state2str(state)); -#endif - bt_mesh.lpn.state = state; -} - -static inline void group_zero(atomic_t *target) -{ -#if CONFIG_BT_MESH_LPN_GROUPS > 32 - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { - atomic_set(&target[i], 0); - } -#else - atomic_set(target, 0); -#endif -} - -static inline void group_set(atomic_t *target, atomic_t *source) -{ -#if CONFIG_BT_MESH_LPN_GROUPS > 32 - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { - atomic_or(&target[i], atomic_get(&source[i])); - } -#else - atomic_or(target, atomic_get(source)); -#endif -} - -static inline void group_clear(atomic_t *target, atomic_t *source) -{ -#if CONFIG_BT_MESH_LPN_GROUPS > 32 - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { - atomic_and(&target[i], ~atomic_get(&source[i])); - } -#else - atomic_and(target, ~atomic_get(source)); -#endif -} - -static void clear_friendship(bool force, bool disable); - -static void friend_clear_sent(int err, void *user_data) -{ - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - - /* Scanning will enable if lpn state still enabled */ - - lpn->req_attempts++; - - if (err) { - BT_ERR("Sending Friend Request failed (err %d)", err); - lpn_set_state(BT_MESH_LPN_ENABLED); - clear_friendship(false, lpn->disable); - return; - } - - lpn_set_state(BT_MESH_LPN_CLEAR); - k_delayed_work_submit(&lpn->timer, FRIEND_REQ_TIMEOUT); -} - -static const struct bt_mesh_send_cb clear_sent_cb = { - .end = friend_clear_sent, -}; - -static int send_friend_clear(void) -{ - struct bt_mesh_msg_ctx ctx = { - .net_idx = bt_mesh.lpn.sub->net_idx, - .app_idx = BT_MESH_KEY_UNUSED, - .addr = bt_mesh.lpn.frnd, - .send_ttl = 0, - }; - struct bt_mesh_net_tx tx = { - .sub = bt_mesh.lpn.sub, - .ctx = &ctx, - .src = bt_mesh_primary_addr(), - .xmit = bt_mesh_net_transmit_get(), - }; - struct bt_mesh_ctl_friend_clear req = { - .lpn_addr = sys_cpu_to_be16(tx.src), - .lpn_counter = sys_cpu_to_be16(bt_mesh.lpn.lpn_counter), - }; - - BT_DBG(""); - - return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req, - sizeof(req), &clear_sent_cb, NULL); -} - -static void clear_friendship(bool force, bool disable) -{ - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - - BT_DBG("force %u disable %u", force, disable); - - if (!force && lpn->established && !lpn->clear_success && - lpn->req_attempts < CLEAR_ATTEMPTS) { - send_friend_clear(); - lpn->disable = disable; - return; - } - - bt_mesh_rx_reset(); - - k_delayed_work_cancel(&lpn->timer); - - if (lpn->clear_success) { - lpn->old_friend = BT_MESH_ADDR_UNASSIGNED; - } else { - lpn->old_friend = lpn->frnd; - } - - if (lpn_cb && lpn->frnd != BT_MESH_ADDR_UNASSIGNED) { - lpn_cb(lpn->frnd, false); - } - - lpn->frnd = BT_MESH_ADDR_UNASSIGNED; - lpn->fsn = 0; - lpn->req_attempts = 0; - lpn->recv_win = 0; - lpn->queue_size = 0; - lpn->disable = 0; - lpn->sent_req = 0; - lpn->established = 0; - lpn->clear_success = 0; - lpn->sub = NULL; - - group_zero(lpn->added); - group_zero(lpn->pending); - group_zero(lpn->to_remove); - - /* Set this to 1 to force group subscription when the next - * Friendship is created, in case lpn->groups doesn't get - * modified meanwhile. - */ - lpn->groups_changed = 1; - - bt_mesh_hb_feature_changed(BT_MESH_FEAT_LOW_POWER); - - if (disable) { - lpn_set_state(BT_MESH_LPN_DISABLED); - return; - } - - lpn_set_state(BT_MESH_LPN_ENABLED); - k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); -} - -static void friend_req_sent(uint16_t duration, int err, void *user_data) -{ - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - - if (err) { - BT_ERR("Sending Friend Request failed (err %d)", err); - return; - } - - lpn->adv_duration = duration; - - if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { - k_delayed_work_submit(&lpn->timer, FRIEND_REQ_WAIT); - lpn_set_state(BT_MESH_LPN_REQ_WAIT); - } else { - k_delayed_work_submit(&lpn->timer, - duration + FRIEND_REQ_TIMEOUT); - lpn_set_state(BT_MESH_LPN_WAIT_OFFER); - } -} - -static const struct bt_mesh_send_cb friend_req_sent_cb = { - .start = friend_req_sent, -}; - -static int send_friend_req(struct bt_mesh_lpn *lpn) -{ - const struct bt_mesh_comp *comp = bt_mesh_comp_get(); - struct bt_mesh_msg_ctx ctx = { - .app_idx = BT_MESH_KEY_UNUSED, - .addr = BT_MESH_ADDR_FRIENDS, - .send_ttl = 0, - }; - struct bt_mesh_net_tx tx = { - .ctx = &ctx, - .src = bt_mesh_primary_addr(), - .xmit = POLL_XMIT, - }; - - lpn->lpn_counter++; - - struct bt_mesh_ctl_friend_req req = { - .criteria = LPN_CRITERIA, - .recv_delay = LPN_RECV_DELAY, - .poll_to = LPN_POLL_TO, - .prev_addr = sys_cpu_to_be16(lpn->old_friend), - .num_elem = comp->elem_count, - .lpn_counter = sys_cpu_to_be16(lpn->lpn_counter), - }; - - BT_DBG(""); - - lpn->sub = bt_mesh_subnet_next(NULL); - if (!lpn->sub) { - BT_ERR("No subnets, can't start LPN mode"); - return -ENOENT; - } - - ctx.net_idx = lpn->sub->net_idx; - tx.sub = lpn->sub; - - return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_REQ, &req, - sizeof(req), &friend_req_sent_cb, NULL); -} - -static void req_sent(uint16_t duration, int err, void *user_data) -{ - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - -#if MYNEWT_VAL(BLE_MESH_LOW_POWER_LOG_LVL) == LOG_LEVEL_DEBUG - BT_DBG("req 0x%02x duration %u err %d state %s", - lpn->sent_req, duration, err, state2str(lpn->state)); -#endif - - if (err) { - BT_ERR("Sending request failed (err %d)", err); - lpn->sent_req = 0; - group_zero(lpn->pending); - return; - } - - lpn->req_attempts++; - lpn->adv_duration = duration; - - if (lpn->established || IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { - lpn_set_state(BT_MESH_LPN_RECV_DELAY); - /* We start scanning a bit early to elimitate risk of missing - * response data due to HCI and other latencies. - */ - k_delayed_work_submit(&lpn->timer, - LPN_RECV_DELAY - SCAN_LATENCY); - } else { - lpn_set_state(BT_MESH_LPN_WAIT_UPDATE); - k_delayed_work_submit(&lpn->timer, - LPN_RECV_DELAY + duration + - lpn->recv_win); - } -} - -static const struct bt_mesh_send_cb req_sent_cb = { - .start = req_sent, -}; - -static int send_friend_poll(void) -{ - struct bt_mesh_msg_ctx ctx = { - .net_idx = bt_mesh.lpn.sub->net_idx, - .app_idx = BT_MESH_KEY_UNUSED, - .addr = bt_mesh.lpn.frnd, - .send_ttl = 0, - }; - struct bt_mesh_net_tx tx = { - .sub = bt_mesh.lpn.sub, - .ctx = &ctx, - .src = bt_mesh_primary_addr(), - .xmit = POLL_XMIT, - .friend_cred = true, - }; - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - uint8_t fsn = lpn->fsn; - int err; - - BT_DBG("lpn->sent_req 0x%02x", lpn->sent_req); - - if (lpn->sent_req) { - if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) { - lpn->pending_poll = 1; - } - - return 0; - } - - err = bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_POLL, &fsn, 1, - &req_sent_cb, NULL); - if (err == 0) { - lpn->pending_poll = 0; - lpn->sent_req = TRANS_CTL_OP_FRIEND_POLL; - } - - return err; -} - -void bt_mesh_lpn_disable(bool force) -{ - if (bt_mesh.lpn.state == BT_MESH_LPN_DISABLED) { - return; - } - - clear_friendship(force, true); -} - -int bt_mesh_lpn_set(bool enable) -{ - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - - if (enable) { - if (lpn->state != BT_MESH_LPN_DISABLED) { - return 0; - } - } else { - if (lpn->state == BT_MESH_LPN_DISABLED) { - return 0; - } - } - - if (!bt_mesh_is_provisioned()) { - if (enable) { - lpn_set_state(BT_MESH_LPN_ENABLED); - } else { - lpn_set_state(BT_MESH_LPN_DISABLED); - } - - return 0; - } - - if (enable) { - lpn_set_state(BT_MESH_LPN_ENABLED); - - if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { - bt_mesh_scan_disable(); - } - - send_friend_req(lpn); - } else { - if (IS_ENABLED(CONFIG_BT_MESH_LPN_AUTO) && - lpn->state == BT_MESH_LPN_TIMER) { - k_delayed_work_cancel(&lpn->timer); - lpn_set_state(BT_MESH_LPN_DISABLED); - } else { - bt_mesh_lpn_disable(false); - } - } - - return 0; -} - -static void friend_response_received(struct bt_mesh_lpn *lpn) -{ - BT_DBG("lpn->sent_req 0x%02x", lpn->sent_req); - - if (lpn->sent_req == TRANS_CTL_OP_FRIEND_POLL) { - lpn->fsn++; - } - - k_delayed_work_cancel(&lpn->timer); - bt_mesh_scan_disable(); - lpn_set_state(BT_MESH_LPN_ESTABLISHED); - lpn->req_attempts = 0; - lpn->sent_req = 0; -} - -void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx) -{ - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - - if (lpn->state == BT_MESH_LPN_TIMER) { - BT_DBG("Restarting establishment timer"); - k_delayed_work_submit(&lpn->timer, LPN_AUTO_TIMEOUT); - return; - } - - if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) { - BT_WARN("Unexpected message withouth a preceding Poll"); - return; - } - - friend_response_received(lpn); - - BT_DBG("Requesting more messages from Friend"); - - send_friend_poll(); -} - -static int friend_cred_create(struct bt_mesh_net_cred *cred, - const uint8_t key[16]) -{ - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - - return bt_mesh_friend_cred_create(cred, bt_mesh_primary_addr(), - lpn->frnd, lpn->lpn_counter, - lpn->frnd_counter, key); -} - -int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf) -{ - struct bt_mesh_ctl_friend_offer *msg = (void *)buf->om_data; - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - uint16_t frnd_counter; - int err; - - if (buf->om_len < sizeof(*msg)) { - BT_WARN("Too short Friend Offer"); - return -EINVAL; - } - - if (lpn->state != BT_MESH_LPN_WAIT_OFFER) { - BT_WARN("Ignoring unexpected Friend Offer"); - return 0; - } - - if (!msg->recv_win) { - BT_WARN("Prohibited ReceiveWindow value"); - return -EINVAL; - } - - frnd_counter = sys_be16_to_cpu(msg->frnd_counter); - - BT_DBG("recv_win %u queue_size %u sub_list_size %u rssi %d counter %u", - msg->recv_win, msg->queue_size, msg->sub_list_size, msg->rssi, - frnd_counter); - - lpn->frnd_counter = frnd_counter; - lpn->frnd = rx->ctx.addr; - - /* Create friend credentials for each of the valid keys in the - * friendship subnet: - */ - for (int i = 0; i < ARRAY_SIZE(lpn->cred); i++) { - if (!lpn->sub->keys[i].valid) { - continue; - } - - err = friend_cred_create(&lpn->cred[i], lpn->sub->keys[i].net); - if (err) { - lpn->frnd = BT_MESH_ADDR_UNASSIGNED; - return err; - } - } - /* TODO: Add offer acceptance criteria check */ - k_delayed_work_cancel(&lpn->timer); - - lpn->recv_win = msg->recv_win; - lpn->queue_size = msg->queue_size; - - err = send_friend_poll(); - if (err) { - lpn->sub = NULL; - lpn->frnd = BT_MESH_ADDR_UNASSIGNED; - lpn->recv_win = 0; - lpn->queue_size = 0; - return err; - } - - return 0; -} - -int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf) -{ - struct bt_mesh_ctl_friend_clear_confirm *msg = (void *)buf->om_data; - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - uint16_t addr, counter; - - if (buf->om_len < sizeof(*msg)) { - BT_WARN("Too short Friend Clear Confirm"); - return -EINVAL; - } - - if (lpn->state != BT_MESH_LPN_CLEAR) { - BT_WARN("Ignoring unexpected Friend Clear Confirm"); - return 0; - } - - addr = sys_be16_to_cpu(msg->lpn_addr); - counter = sys_be16_to_cpu(msg->lpn_counter); - - BT_DBG("LPNAddress 0x%04x LPNCounter 0x%04x", addr, counter); - - if (addr != bt_mesh_primary_addr() || counter != lpn->lpn_counter) { - BT_WARN("Invalid parameters in Friend Clear Confirm"); - return 0; - } - - lpn->clear_success = 1; - clear_friendship(false, lpn->disable); - - return 0; -} - -static void lpn_group_add(uint16_t group) -{ - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - uint16_t *free_slot = NULL; - int i; - - for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) { - if (lpn->groups[i] == group) { - atomic_clear_bit(lpn->to_remove, i); - return; - } - - if (!free_slot && lpn->groups[i] == BT_MESH_ADDR_UNASSIGNED) { - free_slot = &lpn->groups[i]; - } - } - - if (!free_slot) { - BT_WARN("Friend Subscription List exceeded!"); - return; - } - - *free_slot = group; - lpn->groups_changed = 1; -} - -static void lpn_group_del(uint16_t group) -{ - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - int i; - - for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) { - if (lpn->groups[i] == group) { - if (atomic_test_bit(lpn->added, i) || - atomic_test_bit(lpn->pending, i)) { - atomic_set_bit(lpn->to_remove, i); - lpn->groups_changed = 1; - } else { - lpn->groups[i] = BT_MESH_ADDR_UNASSIGNED; - } - } - } -} - -static inline int group_popcount(atomic_t *target) -{ -#if CONFIG_BT_MESH_LPN_GROUPS > 32 - int i, count = 0; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { - count += popcount(atomic_get(&target[i])); - } -#else - return popcount(atomic_get(target)); -#endif -} - -static bool sub_update(uint8_t op) -{ - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - int added_count = group_popcount(lpn->added); - struct bt_mesh_msg_ctx ctx = { - .net_idx = lpn->sub->net_idx, - .app_idx = BT_MESH_KEY_UNUSED, - .addr = lpn->frnd, - .send_ttl = 0, - }; - struct bt_mesh_net_tx tx = { - .sub = lpn->sub, - .ctx = &ctx, - .src = bt_mesh_primary_addr(), - .xmit = POLL_XMIT, - .friend_cred = true, - }; - struct bt_mesh_ctl_friend_sub req; - size_t i, g; - - BT_DBG("op 0x%02x sent_req 0x%02x", op, lpn->sent_req); - - if (lpn->sent_req) { - return false; - } - - for (i = 0, g = 0; i < ARRAY_SIZE(lpn->groups); i++) { - if (lpn->groups[i] == BT_MESH_ADDR_UNASSIGNED) { - continue; - } - - if (op == TRANS_CTL_OP_FRIEND_SUB_ADD) { - if (atomic_test_bit(lpn->added, i)) { - continue; - } - } else { - if (!atomic_test_bit(lpn->to_remove, i)) { - continue; - } - } - - if (added_count + g >= lpn->queue_size) { - BT_WARN("Friend Queue Size exceeded"); - break; - } - - req.addr_list[g++] = sys_cpu_to_be16(lpn->groups[i]); - atomic_set_bit(lpn->pending, i); - - if (g == ARRAY_SIZE(req.addr_list)) { - break; - } - } - - if (g == 0) { - group_zero(lpn->pending); - return false; - } - - req.xact = lpn->xact_next++; - - if (bt_mesh_ctl_send(&tx, op, &req, 1 + g * 2, - &req_sent_cb, NULL) < 0) { - group_zero(lpn->pending); - return false; - } - - lpn->xact_pending = req.xact; - lpn->sent_req = op; - return true; -} - -static void update_timeout(struct bt_mesh_lpn *lpn) -{ - if (lpn->established) { - BT_WARN("No response from Friend during ReceiveWindow"); - bt_mesh_scan_disable(); - lpn_set_state(BT_MESH_LPN_ESTABLISHED); - k_delayed_work_submit(&lpn->timer, POLL_RETRY_TIMEOUT); - } else { - if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { - bt_mesh_scan_disable(); - } - - if (lpn->req_attempts < REQ_ATTEMPTS(lpn)) { - BT_WARN("Retrying first Friend Poll"); - lpn->sent_req = 0; - if (send_friend_poll() == 0) { - return; - } - } - - BT_ERR("Timed out waiting for first Friend Update"); - clear_friendship(false, false); - } -} - -static void lpn_timeout(struct ble_npl_event *work) -{ - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - -#if MYNEWT_VAL(BLE_MESH_LOW_POWER_LOG_LVL) == LOG_LEVEL_DEBUG - BT_DBG("state: %s", state2str(lpn->state)); -#endif - - switch (lpn->state) { - case BT_MESH_LPN_DISABLED: - break; - case BT_MESH_LPN_CLEAR: - clear_friendship(false, bt_mesh.lpn.disable); - break; - case BT_MESH_LPN_TIMER: - BT_DBG("Starting to look for Friend nodes"); - lpn_set_state(BT_MESH_LPN_ENABLED); - if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { - bt_mesh_scan_disable(); - } - /* fall through */ - case BT_MESH_LPN_ENABLED: - send_friend_req(lpn); - break; - case BT_MESH_LPN_REQ_WAIT: - bt_mesh_scan_enable(); - k_delayed_work_submit(&lpn->timer, - lpn->adv_duration + FRIEND_REQ_SCAN); - lpn_set_state(BT_MESH_LPN_WAIT_OFFER); - break; - case BT_MESH_LPN_WAIT_OFFER: - BT_WARN("No acceptable Friend Offers received"); - if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { - bt_mesh_scan_disable(); - } - lpn->lpn_counter++; - lpn_set_state(BT_MESH_LPN_ENABLED); - lpn->sent_req = 0U; - k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); - break; - case BT_MESH_LPN_ESTABLISHED: - if (lpn->req_attempts < REQ_ATTEMPTS(lpn)) { - uint8_t req = lpn->sent_req; - - lpn->sent_req = 0; - - if (!req || req == TRANS_CTL_OP_FRIEND_POLL) { - send_friend_poll(); - } else { - sub_update(req); - } - - break; - } - - BT_ERR("No response from Friend after %u retries", - lpn->req_attempts); - lpn->req_attempts = 0; - clear_friendship(false, false); - break; - case BT_MESH_LPN_RECV_DELAY: - k_delayed_work_submit(&lpn->timer, - lpn->adv_duration + SCAN_LATENCY + - lpn->recv_win); - bt_mesh_scan_enable(); - lpn_set_state(BT_MESH_LPN_WAIT_UPDATE); - break; - case BT_MESH_LPN_WAIT_UPDATE: - update_timeout(lpn); - break; - default: - __ASSERT(0, "Unhandled LPN state"); - break; - } -} - -void bt_mesh_lpn_group_add(uint16_t group) -{ - BT_DBG("group 0x%04x", group); - - lpn_group_add(group); - - if (!bt_mesh_lpn_established() || bt_mesh.lpn.sent_req) { - return; - } - - sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD); -} - -void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count) -{ - int i; - - for (i = 0; i < group_count; i++) { - if (groups[i] != BT_MESH_ADDR_UNASSIGNED) { - BT_DBG("group 0x%04x", groups[i]); - lpn_group_del(groups[i]); - } - } - - if (!bt_mesh_lpn_established() || bt_mesh.lpn.sent_req) { - return; - } - - sub_update(TRANS_CTL_OP_FRIEND_SUB_REM); -} - -static int32_t poll_timeout(struct bt_mesh_lpn *lpn) -{ - /* If we're waiting for segment acks keep polling at high freq */ - if (bt_mesh_tx_in_progress()) { - return min(POLL_TIMEOUT_MAX(lpn), K_SECONDS(1)); - } - - if (lpn->poll_timeout < POLL_TIMEOUT_MAX(lpn)) { - lpn->poll_timeout *= 2; - lpn->poll_timeout = min(lpn->poll_timeout, - POLL_TIMEOUT_MAX(lpn)); - } - - BT_DBG("Poll Timeout is %ums", (unsigned) lpn->poll_timeout); - - return lpn->poll_timeout; -} - -int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf) -{ - struct bt_mesh_ctl_friend_sub_confirm *msg = (void *)buf->om_data; - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - - if (buf->om_len < sizeof(*msg)) { - BT_WARN("Too short Friend Subscription Confirm"); - return -EINVAL; - } - - BT_DBG("xact 0x%02x", msg->xact); - - if (!lpn->sent_req) { - BT_WARN("No pending subscription list message"); - return 0; - } - - if (msg->xact != lpn->xact_pending) { - BT_WARN("Transaction mismatch (0x%02x != 0x%02x)", - msg->xact, lpn->xact_pending); - return 0; - } - - if (lpn->sent_req == TRANS_CTL_OP_FRIEND_SUB_ADD) { - group_set(lpn->added, lpn->pending); - group_zero(lpn->pending); - } else if (lpn->sent_req == TRANS_CTL_OP_FRIEND_SUB_REM) { - int i; - - group_clear(lpn->added, lpn->pending); - - for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) { - if (atomic_test_and_clear_bit(lpn->pending, i) && - atomic_test_and_clear_bit(lpn->to_remove, i)) { - lpn->groups[i] = BT_MESH_ADDR_UNASSIGNED; - } - } - } else { - BT_WARN("Unexpected Friend Subscription Confirm"); - return 0; - } - - friend_response_received(lpn); - - if (lpn->groups_changed) { - sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD); - sub_update(TRANS_CTL_OP_FRIEND_SUB_REM); - - if (!lpn->sent_req) { - lpn->groups_changed = 0; - } - } - - if (lpn->pending_poll) { - send_friend_poll(); - } - - if (!lpn->sent_req) { - int32_t timeout = poll_timeout(lpn); - - k_delayed_work_submit(&lpn->timer, K_MSEC(timeout)); - } - - return 0; -} - -int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf) -{ - struct bt_mesh_ctl_friend_update *msg = (void *)buf->om_data; - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - struct bt_mesh_subnet *sub = rx->sub; - uint32_t iv_index; - - if (buf->om_len < sizeof(*msg)) { - BT_WARN("Too short Friend Update"); - return -EINVAL; - } - - if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) { - BT_WARN("Unexpected friend update"); - return 0; - } - - if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !rx->new_key) { - BT_WARN("Ignoring Phase 2 KR Update secured using old key"); - return 0; - } - - if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) && - (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) == - BT_MESH_IV_UPDATE(msg->flags))) { - bt_mesh_beacon_ivu_initiator(false); - } - - if (!lpn->established) { - /* This is normally checked on the transport layer, however - * in this state we're also still accepting master - * credentials so we need to ensure the right ones (Friend - * Credentials) were used for this message. - */ - if (!rx->friend_cred) { - BT_WARN("Friend Update with wrong credentials"); - return -EINVAL; - } - - lpn->established = 1; - - BT_INFO("Friendship established with 0x%04x", lpn->frnd); - - bt_mesh_hb_feature_changed(BT_MESH_FEAT_LOW_POWER); - - if (lpn_cb) { - lpn_cb(lpn->frnd, true); - } - - /* Set initial poll timeout */ - lpn->poll_timeout = min(POLL_TIMEOUT_MAX(lpn), - POLL_TIMEOUT_INIT); - } - - friend_response_received(lpn); - - iv_index = sys_be32_to_cpu(msg->iv_index); - - BT_DBG("flags 0x%02x iv_index 0x%08x md %u", msg->flags, - (unsigned) iv_index, msg->md); - - bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(msg->flags), rx->new_key); - bt_mesh_net_iv_update(iv_index, BT_MESH_IV_UPDATE(msg->flags)); - - if (lpn->groups_changed) { - sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD); - sub_update(TRANS_CTL_OP_FRIEND_SUB_REM); - - if (!lpn->sent_req) { - lpn->groups_changed = 0; - } - } - - if (msg->md) { - BT_DBG("Requesting for more messages"); - send_friend_poll(); - } - - if (!lpn->sent_req) { - int32_t timeout = poll_timeout(lpn); - - k_delayed_work_submit(&lpn->timer, K_MSEC(timeout)); - } - - return 0; -} - -int bt_mesh_lpn_poll(void) -{ - if (!bt_mesh.lpn.established) { - return -EAGAIN; - } - - BT_DBG("Requesting more messages"); - - return send_friend_poll(); -} - -void bt_mesh_lpn_set_cb(void (*cb)(uint16_t friend_addr, bool established)) -{ - lpn_cb = cb; -} - -static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) -{ - switch (evt) { - case BT_MESH_KEY_DELETED: - if (sub == bt_mesh.lpn.sub) { - BT_DBG("NetKey deleted"); - clear_friendship(true, false); - } - break; - case BT_MESH_KEY_UPDATED: - BT_DBG("NetKey updated"); - friend_cred_create(&bt_mesh.lpn.cred[1], sub->keys[1].net); - break; - default: - break; - } -} - -int bt_mesh_lpn_init(void) -{ - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - - if (!bt_mesh_subnet_cb_list[2]) { - bt_mesh_subnet_cb_list[2] = subnet_evt; - } - - BT_DBG(""); - - lpn->groups_changed = 0; - - k_delayed_work_init(&lpn->timer, lpn_timeout); - - if (lpn->state == BT_MESH_LPN_ENABLED) { - if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { - bt_mesh_scan_disable(); - } else { - bt_mesh_scan_enable(); - } - - send_friend_req(lpn); - } else { - bt_mesh_scan_enable(); - - if (IS_ENABLED(CONFIG_BT_MESH_LPN_AUTO)) { - BT_DBG("Waiting %u ms for messages", LPN_AUTO_TIMEOUT); - lpn_set_state(BT_MESH_LPN_TIMER); - k_delayed_work_submit(&lpn->timer, LPN_AUTO_TIMEOUT); - } - } - - return 0; -} - -#endif /* MYNEWT_VAL(BLE_MESH_LOW_POWER) */ -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/lpn.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/lpn.h deleted file mode 100644 index 34f339052..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/lpn.h +++ /dev/null @@ -1,68 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __LPN_H__ -#define __LPN_H__ - -#include "../include/mesh/mesh.h" - -int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf); -int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf); -int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf); -int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx, - struct os_mbuf *buf); - -static inline bool bt_mesh_lpn_established(void) -{ -#if (MYNEWT_VAL(BLE_MESH_LOW_POWER)) - return bt_mesh.lpn.established; -#else - return false; -#endif -} - -static inline bool bt_mesh_lpn_match(uint16_t addr) -{ -#if (MYNEWT_VAL(BLE_MESH_LOW_POWER)) - if (bt_mesh_lpn_established()) { - return (addr == bt_mesh.lpn.frnd); - } -#endif - return false; -} - -static inline bool bt_mesh_lpn_waiting_update(void) -{ -#if (MYNEWT_VAL(BLE_MESH_LOW_POWER)) - return (bt_mesh.lpn.state == BT_MESH_LPN_WAIT_UPDATE); -#else - return false; -#endif -} - -static inline bool bt_mesh_lpn_timer(void) -{ -#if MYNEWT_VAL(BLE_MESH_LOW_POWER) && MYNEWT_VAL(BLE_MESH_LPN_AUTO) - return (bt_mesh.lpn.state == BT_MESH_LPN_TIMER); -#else - return false; -#endif -} - -void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx); - -void bt_mesh_lpn_group_add(uint16_t group); -void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count); - -void bt_mesh_lpn_disable(bool force); - -int bt_mesh_lpn_init(void); - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/mesh.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/mesh.c deleted file mode 100644 index c896f0157..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/mesh.c +++ /dev/null @@ -1,405 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_LOG - -#include -#include - -#include "nimble/porting/nimble/include/os/os_mbuf.h" -#include "../include/mesh/mesh.h" -#include "nimble/nimble/host/include/host/ble_uuid.h" - -#include "adv.h" -#include "prov.h" -#include "provisioner.h" -#include "net.h" -#include "subnet.h" -#include "app_keys.h" -#include "rpl.h" -#include "cfg.h" -#include "beacon.h" -#include "lpn.h" -#include "friend.h" -#include "transport.h" -#include "access.h" -#include "foundation.h" -#include "proxy.h" -#include "heartbeat.h" -#include "shell.h" -#include "mesh_priv.h" -#include "settings.h" - - -uint8_t g_mesh_addr_type; -static struct ble_gap_event_listener mesh_event_listener; - -int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, - uint8_t flags, uint32_t iv_index, uint16_t addr, - const uint8_t dev_key[16]) -{ - bool pb_gatt_enabled; - int err; - - BT_INFO("Primary Element: 0x%04x", addr); - BT_DBG("net_idx 0x%04x flags 0x%02x iv_index 0x%04x", - net_idx, flags, (unsigned) iv_index); - - if (atomic_test_and_set_bit(bt_mesh.flags, BT_MESH_VALID)) { - return -EALREADY; - } - - if ((MYNEWT_VAL(BLE_MESH_PB_GATT))) { - if (bt_mesh_proxy_prov_disable(false) == 0) { - pb_gatt_enabled = true; - } else { - pb_gatt_enabled = false; - } - } else { - pb_gatt_enabled = false; - } - - /* - * FIXME: - * Should net_key and iv_index be over-ridden? - */ - if (IS_ENABLED(BLE_MESH_CDB)) { - const struct bt_mesh_comp *comp; - const struct bt_mesh_prov *prov; - struct bt_mesh_cdb_node *node; - - if (!atomic_test_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_VALID)) { - BT_ERR("No valid network"); - atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID); - return -EINVAL; - } - - comp = bt_mesh_comp_get(); - if (comp == NULL) { - BT_ERR("Failed to get node composition"); - atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID); - return -EINVAL; - } - - if (!bt_mesh_cdb_subnet_get(net_idx)) { - BT_ERR("No subnet with idx %d", net_idx); - atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID); - return -ENOENT; - } - - prov = bt_mesh_prov_get(); - node = bt_mesh_cdb_node_alloc(prov->uuid, addr, - comp->elem_count, net_idx); - if (node == NULL) { - BT_ERR("Failed to allocate database node"); - atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID); - return -ENOMEM; - } - - addr = node->addr; - iv_index = bt_mesh_cdb.iv_index; - memcpy(node->dev_key, dev_key, 16); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb_node(node); - } - } - - err = bt_mesh_net_create(net_idx, flags, net_key, iv_index); - if (err) { - atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID); - - if (MYNEWT_VAL(BLE_MESH_PB_GATT) && pb_gatt_enabled) { - bt_mesh_proxy_prov_enable(); - } - - return err; - } - - bt_mesh.seq = 0; - - bt_mesh_comp_provision(addr); - - memcpy(bt_mesh.dev_key, dev_key, 16); - - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && - IS_ENABLED(CONFIG_BT_MESH_LPN_SUB_ALL_NODES_ADDR)) { - bt_mesh_lpn_group_add(BT_MESH_ADDR_ALL_NODES); - } - - bt_mesh_start(); - - return 0; -} - -int bt_mesh_provision_adv(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr, - uint8_t attention_duration) -{ - if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - return -EINVAL; - } - - if (bt_mesh_subnet_get(net_idx) == NULL) { - return -EINVAL; - } - - if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) && - IS_ENABLED(CONFIG_BT_MESH_PB_ADV)) { - return bt_mesh_pb_adv_open(uuid, net_idx, addr, - attention_duration); - } - - return -ENOTSUP; -} - -void bt_mesh_reset(void) -{ - if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - return; - } - - bt_mesh.iv_index = 0U; - bt_mesh.seq = 0U; - - memset(bt_mesh.flags, 0, sizeof(bt_mesh.flags)); - - k_delayed_work_cancel(&bt_mesh.ivu_timer); - - bt_mesh_cfg_reset(); - - bt_mesh_trans_reset(); - bt_mesh_app_keys_reset(); - bt_mesh_net_keys_reset(); - - bt_mesh_net_loopback_clear(BT_MESH_KEY_ANY); - - if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) { - if (IS_ENABLED(CONFIG_BT_MESH_LPN_SUB_ALL_NODES_ADDR)) { - uint16_t group = BT_MESH_ADDR_ALL_NODES; - - bt_mesh_lpn_group_del(&group, 1); - } - - bt_mesh_lpn_disable(true); - } - - if ((MYNEWT_VAL(BLE_MESH_FRIEND))) { - bt_mesh_friends_clear(); - } - - if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY))) { - bt_mesh_proxy_gatt_disable(); - } - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_clear_net(); - } - - memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key)); - - bt_mesh_scan_disable(); - bt_mesh_beacon_disable(); - - bt_mesh_comp_unprovision(); - - if (IS_ENABLED(CONFIG_BT_MESH_PROV)) { - bt_mesh_prov_reset(); - } -} - -bool bt_mesh_is_provisioned(void) -{ - return atomic_test_bit(bt_mesh.flags, BT_MESH_VALID); -} - - -static int bt_mesh_gap_event(struct ble_gap_event *event, void *arg) -{ - ble_adv_gap_mesh_cb(event, arg); - -#if (MYNEWT_VAL(BLE_MESH_PROXY)) - ble_mesh_proxy_gap_event(event, arg); -#endif - - return 0; -} - -static void model_suspend(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, - bool vnd, bool primary, void *user_data) -{ - if (mod->pub && mod->pub->update) { - mod->pub->count = 0; - k_delayed_work_cancel(&mod->pub->timer); - } -} - -int bt_mesh_suspend(void) -{ - int err; - - if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - return -EINVAL; - } - - if (atomic_test_and_set_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { - return -EALREADY; - } - - err = bt_mesh_scan_disable(); - if (err) { - atomic_clear_bit(bt_mesh.flags, BT_MESH_SUSPENDED); - BT_WARN("Disabling scanning failed (err %d)", err); - return err; - } - - bt_mesh_hb_suspend(); - - if (bt_mesh_beacon_enabled()) { - bt_mesh_beacon_disable(); - } - - bt_mesh_model_foreach(model_suspend, NULL); - - return 0; -} - -static void model_resume(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, - bool vnd, bool primary, void *user_data) -{ - if (mod->pub && mod->pub->update) { - int32_t period_ms = bt_mesh_model_pub_period_get(mod); - - if (period_ms) { - k_delayed_work_submit(&mod->pub->timer, period_ms); - } - } -} - -int bt_mesh_resume(void) -{ - int err; - - if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - return -EINVAL; - } - - if (!atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { - return -EALREADY; - } - - err = bt_mesh_scan_enable(); - if (err) { - BT_WARN("Re-enabling scanning failed (err %d)", err); - atomic_set_bit(bt_mesh.flags, BT_MESH_SUSPENDED); - return err; - } - - bt_mesh_hb_resume(); - - if (bt_mesh_beacon_enabled()) { - bt_mesh_beacon_enable(); - } - - bt_mesh_model_foreach(model_resume, NULL); - - return err; -} - -int bt_mesh_init(uint8_t own_addr_type, const struct bt_mesh_prov *prov, - const struct bt_mesh_comp *comp) -{ - int err; - - g_mesh_addr_type = own_addr_type; - - /* initialize SM alg ECC subsystem (it is used directly from mesh code) */ - ble_sm_alg_ecc_init(); - - err = bt_mesh_comp_register(comp); - if (err) { - return err; - } - -#if (MYNEWT_VAL(BLE_MESH_PROXY)) - bt_mesh_proxy_init(); -#endif - -#if (MYNEWT_VAL(BLE_MESH_PROV)) - err = bt_mesh_prov_init(prov); - if (err) { - return err; - } -#endif - - bt_mesh_cfg_init(); - bt_mesh_net_init(); - bt_mesh_trans_init(); - bt_mesh_hb_init(); - bt_mesh_beacon_init(); - bt_mesh_adv_init(); - -#if (MYNEWT_VAL(BLE_MESH_SETTINGS)) - bt_mesh_settings_init(); -#endif - - ble_gap_event_listener_register(&mesh_event_listener, - bt_mesh_gap_event, NULL); - - return 0; -} - -static void model_start(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, - bool vnd, bool primary, void *user_data) -{ - if (mod->cb && mod->cb->start) { - mod->cb->start(mod); - } -} - -int bt_mesh_start(void) -{ - if (bt_mesh_beacon_enabled()) { - bt_mesh_beacon_enable(); - } else { - bt_mesh_beacon_disable(); - } - - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && - bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_NOT_SUPPORTED) { - bt_mesh_proxy_gatt_enable(); - bt_mesh_adv_update(); - } - - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_init(); - } else { - bt_mesh_scan_enable(); - } - - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - bt_mesh_friend_init(); - } - - if (IS_ENABLED(CONFIG_BT_MESH_PROV)) { - struct bt_mesh_subnet *sub = bt_mesh_subnet_next(NULL); - uint16_t addr = bt_mesh_primary_addr(); - - bt_mesh_prov_complete(sub->net_idx, addr); - } - - bt_mesh_hb_start(); - - bt_mesh_model_foreach(model_start, NULL); - - return 0; -} -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/mesh_priv.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/mesh_priv.h deleted file mode 100644 index 213f54377..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/mesh_priv.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __MESH_PRIV_H -#define __MESH_PRIV_H - -#include -#include - -#define BT_MESH_KEY_PRIMARY 0x0000 -#define BT_MESH_KEY_ANY 0xffff - -enum bt_mesh_key_evt { - BT_MESH_KEY_ADDED, /* New key added */ - BT_MESH_KEY_DELETED, /* Existing key deleted */ - BT_MESH_KEY_UPDATED, /* KR phase 1, second key added */ - BT_MESH_KEY_SWAPPED, /* KR phase 2, now sending on second key */ - BT_MESH_KEY_REVOKED, /* KR phase 3, old key removed */ -}; - -/** Appkey callback. Instantiate with @ref BT_MESH_APP_KEY_CB */ -struct bt_mesh_app_key_cb { - void (*evt_handler)(uint16_t app_idx, uint16_t net_idx, - enum bt_mesh_key_evt evt); -}; - -struct bt_mesh_net; -int bt_mesh_start(void); - -#define OP_GEN_ONOFF_GET BT_MESH_MODEL_OP_2(0x82, 0x01) -#define OP_GEN_ONOFF_SET BT_MESH_MODEL_OP_2(0x82, 0x02) -#define OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03) -#define OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04) -#define OP_GEN_LEVEL_GET BT_MESH_MODEL_OP_2(0x82, 0x05) -#define OP_GEN_LEVEL_SET BT_MESH_MODEL_OP_2(0x82, 0x06) -#define OP_GEN_LEVEL_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x07) -#define OP_GEN_LEVEL_STATUS BT_MESH_MODEL_OP_2(0x82, 0x08) -#define OP_GEN_DELTA_SET BT_MESH_MODEL_OP_2(0x82, 0x09) -#define OP_GEN_DELTA_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x0a) -#define OP_GEN_MOVE_SET BT_MESH_MODEL_OP_2(0x82, 0x0b) -#define OP_GEN_MOVE_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x0c) -#define OP_LIGHT_LIGHTNESS_GET BT_MESH_MODEL_OP_2(0x82, 0x4b) -#define OP_LIGHT_LIGHTNESS_SET BT_MESH_MODEL_OP_2(0x82, 0x4c) -#define OP_LIGHT_LIGHTNESS_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x4d) -#define OP_LIGHT_LIGHTNESS_STATUS BT_MESH_MODEL_OP_2(0x82, 0x4e) - -bool bt_mesh_is_provisioned(void); - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/model_cli.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/model_cli.c deleted file mode 100644 index 41b03320d..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/model_cli.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG - -#include "../include/mesh/mesh.h" -#include "../include/mesh/model_cli.h" -#include "mesh_priv.h" - -static int32_t msg_timeout = K_SECONDS(5); - -static struct bt_mesh_gen_model_cli *gen_onoff_cli; -static struct bt_mesh_gen_model_cli *gen_level_cli; - -static uint8_t transaction_id = 0; - -struct gen_onoff_param { - uint8_t *state; -}; - -struct gen_level_param { - int16_t *level; -}; - -static void gen_onoff_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct bt_mesh_gen_model_cli *cli = model->user_data; - struct gen_onoff_param *param; - uint8_t state; - - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_GEN_ONOFF_STATUS) { - BT_WARN("Unexpected Generic OnOff Status message"); - return; - } - - param = cli->op_param; - - state = net_buf_simple_pull_u8(buf); - if (param->state) { - *param->state = state; - } - - BT_DBG("state: %d", state); - - k_sem_give(&cli->op_sync); -} - -static void gen_level_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct bt_mesh_gen_model_cli *cli = model->user_data; - struct gen_level_param *param; - int16_t level; - - - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - if (cli->op_pending != OP_GEN_LEVEL_STATUS) { - BT_WARN("Unexpected Generic LEVEL Status message"); - return; - } - - param = cli->op_param; - - level = net_buf_simple_pull_le16(buf); - if (param->level) { - *param->level = level; - } - - BT_DBG("level: %d", level); - - k_sem_give(&cli->op_sync); -} - -const struct bt_mesh_model_op gen_onoff_cli_op[] = { - { OP_GEN_ONOFF_STATUS, 1, gen_onoff_status }, - BT_MESH_MODEL_OP_END, -}; - -static int onoff_cli_init(struct bt_mesh_model *model) -{ - BT_DBG(""); - - if (!model->user_data) { - BT_ERR("No Generic OnOff Client context provided"); - return -EINVAL; - } - - gen_onoff_cli = model->user_data; - gen_onoff_cli->model = model; - - k_sem_init(&gen_onoff_cli->op_sync, 0, 1); - - return 0; -} - -const struct bt_mesh_model_cb bt_mesh_gen_onoff_cli_cb = { - .init = onoff_cli_init, -}; - -const struct bt_mesh_model_op gen_level_cli_op[] = { - { OP_GEN_LEVEL_STATUS, 2, gen_level_status }, - BT_MESH_MODEL_OP_END, -}; - -static int level_cli_init(struct bt_mesh_model *model) -{ - BT_DBG(""); - - if (!model->user_data) { - BT_ERR("No Generic Level Client context provided"); - return -EINVAL; - } - - gen_level_cli = model->user_data; - gen_level_cli->model = model; - - k_sem_init(&gen_level_cli->op_sync, 0, 1); - - return 0; -} - -const struct bt_mesh_model_cb bt_mesh_gen_level_cli_cb = { - .init = level_cli_init, -}; - -static int cli_wait(struct bt_mesh_gen_model_cli *cli, void *param, uint32_t op) -{ - int err; - - BT_DBG(""); - - cli->op_param = param; - cli->op_pending = op; - - err = k_sem_take(&cli->op_sync, msg_timeout); - - cli->op_pending = 0; - cli->op_param = NULL; - - return err; -} - -int bt_mesh_gen_onoff_get(uint16_t net_idx, uint16_t addr, uint16_t app_idx, - uint8_t *state) -{ - struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = app_idx, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct gen_onoff_param param = { - .state = state, - }; - int err; - - bt_mesh_model_msg_init(msg, OP_GEN_ONOFF_GET); - - err = bt_mesh_model_send(gen_onoff_cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - goto done; - } - - err = cli_wait(gen_onoff_cli, ¶m, OP_GEN_ONOFF_STATUS); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_gen_onoff_set(uint16_t net_idx, uint16_t addr, uint16_t app_idx, - uint8_t val, uint8_t *state) -{ - struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = app_idx, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct gen_onoff_param param = { - .state = state, - }; - int err; - - if (state) { - bt_mesh_model_msg_init(msg, OP_GEN_ONOFF_SET); - } else { - bt_mesh_model_msg_init(msg, OP_GEN_ONOFF_SET_UNACK); - } - - net_buf_simple_add_u8(msg, val); - net_buf_simple_add_u8(msg, transaction_id); - - err = bt_mesh_model_send(gen_onoff_cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - goto done; - } - - if (!state) { - goto done; - } - - err = cli_wait(gen_onoff_cli, ¶m, OP_GEN_ONOFF_STATUS); -done: - if (err == 0) { - transaction_id++; - } - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_gen_level_get(uint16_t net_idx, uint16_t addr, uint16_t app_idx, - int16_t *level) -{ - struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = app_idx, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct gen_level_param param = { - .level = level, - }; - int err; - - bt_mesh_model_msg_init(msg, OP_GEN_LEVEL_GET); - - err = bt_mesh_model_send(gen_level_cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - goto done; - } - - err = cli_wait(gen_level_cli, ¶m, OP_GEN_LEVEL_STATUS); -done: - os_mbuf_free_chain(msg); - return err; -} - -int bt_mesh_gen_level_set(uint16_t net_idx, uint16_t addr, uint16_t app_idx, - int16_t val, int16_t *state) -{ - struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 3 + 4); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = app_idx, - .addr = addr, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct gen_level_param param = { - .level = state, - }; - int err; - - if (state) { - bt_mesh_model_msg_init(msg, OP_GEN_LEVEL_SET); - } else { - bt_mesh_model_msg_init(msg, OP_GEN_LEVEL_SET_UNACK); - } - - net_buf_simple_add_le16(msg, val); - net_buf_simple_add_u8(msg, transaction_id); - - err = bt_mesh_model_send(gen_level_cli->model, &ctx, msg, NULL, NULL); - if (err) { - BT_ERR("model_send() failed (err %d)", err); - goto done; - } - - if (!state) { - goto done; - } - - err = cli_wait(gen_level_cli, ¶m, OP_GEN_LEVEL_STATUS); -done: - if (err == 0) { - transaction_id++; - } - os_mbuf_free_chain(msg); - return err; -} -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/model_srv.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/model_srv.c deleted file mode 100644 index db7407a38..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/model_srv.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG - -#include "../include/mesh/mesh.h" -#include "../include/mesh/model_srv.h" -#include "mesh_priv.h" - -static struct bt_mesh_gen_onoff_srv *gen_onoff_srv; -static struct bt_mesh_gen_level_srv *gen_level_srv; -static struct bt_mesh_light_lightness_srv *light_lightness_srv; - -static void gen_onoff_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx) -{ - struct bt_mesh_gen_onoff_srv *cb = model->user_data; - struct os_mbuf *msg = NET_BUF_SIMPLE(3); - uint8_t *state; - - bt_mesh_model_msg_init(msg, OP_GEN_ONOFF_STATUS); - state = net_buf_simple_add(msg, 1); - if (cb && cb->get) { - cb->get(model, state); - } - - BT_DBG("state: %d", *state); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Send status failed"); - } - - os_mbuf_free_chain(msg); -} - -static void gen_onoff_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG(""); - - gen_onoff_status(model, ctx); -} - -static void gen_onoff_set_unack(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - struct bt_mesh_gen_onoff_srv *cb = model->user_data; - uint8_t state; - - state = buf->om_data[0]; - - BT_DBG("state: %d", state); - - if (cb && cb->set) { - cb->set(model, state); - } -} - -static void gen_onoff_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG(""); - - gen_onoff_set_unack(model, ctx, buf); - gen_onoff_status(model, ctx); -} - -static void gen_level_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx) -{ - struct bt_mesh_gen_level_srv *cb = model->user_data; - struct os_mbuf *msg = NET_BUF_SIMPLE(4); - int16_t *level; - - bt_mesh_model_msg_init(msg, OP_GEN_LEVEL_STATUS); - level = net_buf_simple_add(msg, 2); - if (cb && cb->get) { - cb->get(model, level); - } - - BT_DBG("level: %d", *level); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Send status failed"); - } - - os_mbuf_free_chain(msg); -} - -static void gen_level_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG(""); - - gen_level_status(model, ctx); -} - -static void gen_level_set_unack(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) { - struct bt_mesh_gen_level_srv *cb = model->user_data; - int16_t level; - - level = (int16_t) net_buf_simple_pull_le16(buf); - BT_DBG("level: %d", level); - - if (cb && cb->set) { - cb->set(model, level); - } -} - -static void gen_level_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - gen_level_set_unack(model, ctx, buf); - gen_level_status(model, ctx); -} - -static void light_lightness_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx) -{ - struct bt_mesh_light_lightness_srv *cb = model->user_data; - struct os_mbuf *msg = NET_BUF_SIMPLE(4); - int16_t *lightness; - - bt_mesh_model_msg_init(msg, OP_LIGHT_LIGHTNESS_STATUS); - lightness = net_buf_simple_add(msg, 2); - if (cb && cb->get) { - cb->get(model, lightness); - } - - BT_DBG("lightness: %d", *lightness); - - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { - BT_ERR("Send status failed"); - } - - os_mbuf_free_chain(msg); -} - -static void light_lightness_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - BT_DBG(""); - - light_lightness_status(model, ctx); -} - -static void light_lightness_set_unack(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) { - struct bt_mesh_light_lightness_srv *cb = model->user_data; - int16_t lightness; - - lightness = (int16_t) net_buf_simple_pull_le16(buf); - BT_DBG("lightness: %d", lightness); - - if (cb && cb->set) { - cb->set(model, lightness); - } -} - -static void light_lightness_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - light_lightness_set_unack(model, ctx, buf); - light_lightness_status(model, ctx); -} - -const struct bt_mesh_model_op gen_onoff_srv_op[] = { - { OP_GEN_ONOFF_GET, 0, gen_onoff_get }, - { OP_GEN_ONOFF_SET, 2, gen_onoff_set }, - { OP_GEN_ONOFF_SET_UNACK, 2, gen_onoff_set_unack }, - BT_MESH_MODEL_OP_END, -}; - -const struct bt_mesh_model_op gen_level_srv_op[] = { - { OP_GEN_LEVEL_GET, 0, gen_level_get }, - { OP_GEN_LEVEL_SET, 3, gen_level_set }, - { OP_GEN_LEVEL_SET_UNACK, 3, gen_level_set_unack }, - BT_MESH_MODEL_OP_END, -}; - -const struct bt_mesh_model_op light_lightness_srv_op[] = { - { OP_LIGHT_LIGHTNESS_GET, 0, light_lightness_get }, - { OP_LIGHT_LIGHTNESS_SET, 3, light_lightness_set }, - { OP_LIGHT_LIGHTNESS_SET_UNACK, 3, light_lightness_set_unack }, - BT_MESH_MODEL_OP_END, -}; - -static int onoff_srv_init(struct bt_mesh_model *model) -{ - struct bt_mesh_gen_onoff_srv *cfg = model->user_data; - - BT_DBG(""); - - if (!cfg) { - BT_ERR("No Generic OnOff Server context provided"); - return -EINVAL; - } - - cfg->model = model; - - gen_onoff_srv = cfg; - - return 0; -} - -const struct bt_mesh_model_cb gen_onoff_srv_cb = { - .init = onoff_srv_init, -}; - -static int level_srv_init(struct bt_mesh_model *model) -{ - struct bt_mesh_gen_level_srv *cfg = model->user_data; - - BT_DBG(""); - - if (!cfg) { - BT_ERR("No Generic Level Server context provided"); - return -EINVAL; - } - - cfg->model = model; - - gen_level_srv = cfg; - - return 0; -} - -const struct bt_mesh_model_cb gen_level_srv_cb = { - .init = level_srv_init, -}; - -static int lightness_srv_init(struct bt_mesh_model *model) -{ - struct bt_mesh_light_lightness_srv *cfg = model->user_data; - - BT_DBG(""); - - if (!cfg) { - BT_ERR("No Light Lightness Server context provided"); - return -EINVAL; - } - - cfg->model = model; - - light_lightness_srv = cfg; - - return 0; -} - -const struct bt_mesh_model_cb light_lightness_srv_cb = { - .init = lightness_srv_init, -}; -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/net.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/net.c deleted file mode 100644 index 11728cf06..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/net.c +++ /dev/null @@ -1,864 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_NET_LOG - -#include -#include -#include - -#include "nimble/porting/nimble/include/os/os_mbuf.h" -#include "../include/mesh/mesh.h" - -#include "crypto.h" -#include "adv.h" -#include "mesh_priv.h" -#include "net.h" -#include "rpl.h" -#include "lpn.h" -#include "friend.h" -#include "proxy.h" -#include "transport.h" -#include "access.h" -#include "foundation.h" -#include "beacon.h" -#include "settings.h" -#include "prov.h" -#include "cfg.h" -#include "../include/mesh/glue.h" -#include "../include/mesh/slist.h" - -/* Minimum valid Mesh Network PDU length. The Network headers - * themselves take up 9 bytes. After that there is a minumum of 1 byte - * payload for both CTL=1 and CTL=0 PDUs (smallest OpCode is 1 byte). CTL=1 - * PDUs must use a 64-bit (8 byte) NetMIC, whereas CTL=0 PDUs have at least - * a 32-bit (4 byte) NetMIC and AppMIC giving again a total of 8 bytes. - */ -#define BT_MESH_NET_MIN_PDU_LEN (BT_MESH_NET_HDR_LEN + 1 + 8) - -#define LOOPBACK_MAX_PDU_LEN (BT_MESH_NET_HDR_LEN + 16) -#define LOOPBACK_USER_DATA_SIZE sizeof(struct bt_mesh_subnet *) -#define LOOPBACK_BUF_SUB(buf) (*(struct bt_mesh_subnet **)net_buf_user_data(buf)) - -/* Seq limit after IV Update is triggered */ -#define IV_UPDATE_SEQ_LIMIT 8000000 - -#define IVI(pdu) ((pdu)[0] >> 7) -#define NID(pdu) ((pdu)[0] & 0x7f) -#define CTL(pdu) ((pdu)[1] >> 7) -#define TTL(pdu) ((pdu)[1] & 0x7f) -#define SEQ(pdu) (sys_get_be24(&pdu[2])) -#define SRC(pdu) (sys_get_be16(&(pdu)[5])) -#define DST(pdu) (sys_get_be16(&(pdu)[7])) - -static struct { - uint32_t src : 15, /* MSb of source is always 0 */ - seq : 17; -} msg_cache[MYNEWT_VAL(BLE_MESH_MSG_CACHE_SIZE)]; -static uint16_t msg_cache_next; - -/* Singleton network context (the implementation only supports one) */ -struct bt_mesh_net bt_mesh = { - .local_queue = STAILQ_HEAD_INITIALIZER(bt_mesh.local_queue), -}; - -static struct os_mbuf_pool loopback_os_mbuf_pool; -static struct os_mempool loopback_buf_mempool; -os_membuf_t loopback_mbuf_membuf[ - OS_MEMPOOL_SIZE(LOOPBACK_MAX_PDU_LEN + BT_MESH_MBUF_HEADER_SIZE, - MYNEWT_VAL(BLE_MESH_LOOPBACK_BUFS))]; - -static uint32_t dup_cache[MYNEWT_VAL(BLE_MESH_MSG_CACHE_SIZE)]; -static int dup_cache_next; - -static bool check_dup(struct os_mbuf *data) -{ - const uint8_t *tail = net_buf_simple_tail(data); - uint32_t val; - int i; - - val = sys_get_be32(tail - 4) ^ sys_get_be32(tail - 8); - - for (i = 0; i < ARRAY_SIZE(dup_cache); i++) { - if (dup_cache[i] == val) { - return true; - } - } - - dup_cache[dup_cache_next++] = val; - dup_cache_next %= ARRAY_SIZE(dup_cache); - - return false; -} - -static bool msg_cache_match(struct os_mbuf *pdu) -{ - uint16_t i; - - for (i = 0; i < ARRAY_SIZE(msg_cache); i++) { - if (msg_cache[i].src == SRC(pdu->om_data) && - msg_cache[i].seq == (SEQ(pdu->om_data) & BIT_MASK(17))) { - return true; - } - } - - return false; -} - -static void msg_cache_add(struct bt_mesh_net_rx *rx) -{ - /* Add to the cache */ - rx->msg_cache_idx = msg_cache_next++; - msg_cache[rx->msg_cache_idx].src = rx->ctx.addr; - msg_cache[rx->msg_cache_idx].seq = rx->seq; - msg_cache_next %= ARRAY_SIZE(msg_cache); -} - -int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], - uint32_t iv_index) -{ - int err; - - BT_DBG("idx %u flags 0x%02x iv_index %u", idx, flags, iv_index); - - BT_DBG("NetKey %s", bt_hex(key, 16)); - - if (BT_MESH_KEY_REFRESH(flags)) { - err = bt_mesh_subnet_set(idx, BT_MESH_KR_PHASE_2, NULL, key); - } else { - err = bt_mesh_subnet_set(idx, BT_MESH_KR_NORMAL, key, NULL); - } - - if (err) { - BT_ERR("Failed creating subnet"); - return err; - } - - (void)memset(msg_cache, 0, sizeof(msg_cache)); - msg_cache_next = 0U; - - bt_mesh.iv_index = iv_index; - atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, - BT_MESH_IV_UPDATE(flags)); - - /* Set minimum required hours, since the 96-hour minimum requirement - * doesn't apply straight after provisioning (since we can't know how - * long has actually passed since the network changed its state). - */ - bt_mesh.ivu_duration = BT_MESH_IVU_MIN_HOURS; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - BT_DBG("Storing network information persistently"); - bt_mesh_store_net(); - bt_mesh_store_subnet(idx); - bt_mesh_store_iv(false); - } - - return 0; -} - -#if MYNEWT_VAL(BLE_MESH_IV_UPDATE_TEST) -void bt_mesh_iv_update_test(bool enable) -{ - atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_TEST, enable); - /* Reset the duration variable - needed for some PTS tests */ - bt_mesh.ivu_duration = 0; -} - -bool bt_mesh_iv_update(void) -{ - if (!bt_mesh_is_provisioned()) { - BT_ERR("Not yet provisioned"); - return false; - } - - if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)) { - bt_mesh_net_iv_update(bt_mesh.iv_index, false); - } else { - bt_mesh_net_iv_update(bt_mesh.iv_index + 1, true); - } - - return atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS); -} -#endif /* CONFIG_BT_MESH_IV_UPDATE_TEST */ - -bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) -{ - if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)) { - /* We're currently in IV Update mode */ - - if (iv_index != bt_mesh.iv_index) { - BT_WARN("IV Index mismatch: 0x%08x != 0x%08x", - (unsigned) iv_index, - (unsigned) bt_mesh.iv_index); - return false; - } - - if (iv_update) { - /* Nothing to do */ - BT_DBG("Already in IV Update in Progress state"); - return false; - } - } else { - /* We're currently in Normal mode */ - - if (iv_index == bt_mesh.iv_index) { - BT_DBG("Same IV Index in normal mode"); - return false; - } - - if (iv_index < bt_mesh.iv_index || - iv_index > bt_mesh.iv_index + 42) { - BT_ERR("IV Index out of sync: 0x%08x != 0x%08x", - (unsigned) iv_index, - (unsigned) bt_mesh.iv_index); - return false; - } - - if (iv_index > bt_mesh.iv_index + 1) { - BT_WARN("Performing IV Index Recovery"); - bt_mesh_rpl_clear(); - bt_mesh.iv_index = iv_index; - bt_mesh.seq = 0; - goto do_update; - } - - if (iv_index == bt_mesh.iv_index + 1 && !iv_update) { - BT_WARN("Ignoring new index in normal mode"); - return false; - } - - if (!iv_update) { - /* Nothing to do */ - BT_DBG("Already in Normal state"); - return false; - } - } - - if (!(IS_ENABLED(CONFIG_BT_MESH_IV_UPDATE_TEST) && - atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_TEST))) { - if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) { - BT_WARN("IV Update before minimum duration"); - return false; - } - } - - /* Defer change to Normal Operation if there are pending acks */ - if (!iv_update && bt_mesh_tx_in_progress()) { - BT_WARN("IV Update deferred because of pending transfer"); - atomic_set_bit(bt_mesh.flags, BT_MESH_IVU_PENDING); - return false; - } - -do_update: - atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, iv_update); - bt_mesh.ivu_duration = 0U; - - if (iv_update) { - bt_mesh.iv_index = iv_index; - BT_DBG("IV Update state entered. New index 0x%08x", - (unsigned) bt_mesh.iv_index); - - bt_mesh_rpl_reset(); - } else { - BT_DBG("Normal mode entered"); - bt_mesh.seq = 0; - } - - k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); - - /* Notify other modules */ - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - bt_mesh_friend_sec_update(BT_MESH_KEY_ANY); - } - - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && - bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) { - bt_mesh_proxy_beacon_send(NULL); - } - - bt_mesh_subnet_foreach(bt_mesh_beacon_update); - - if (MYNEWT_VAL(BLE_MESH_CDB)) { - bt_mesh_cdb_iv_update(iv_index, iv_update); - } - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_iv(false); - } - - return true; -} - -uint32_t bt_mesh_next_seq(void) -{ - uint32_t seq = bt_mesh.seq++; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_seq(); - } - - if (!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) && - bt_mesh.seq > IV_UPDATE_SEQ_LIMIT && - bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY)) { - bt_mesh_beacon_ivu_initiator(true); - bt_mesh_net_iv_update(bt_mesh.iv_index + 1, true); - } - - return seq; -} - -static void bt_mesh_net_local(struct ble_npl_event *work) -{ - struct os_mbuf *buf; - - while ((buf = net_buf_slist_get(&bt_mesh.local_queue))) { - struct bt_mesh_subnet *sub = LOOPBACK_BUF_SUB(buf); - struct bt_mesh_net_rx rx = { - .ctx = { - .net_idx = sub->net_idx, - /* Initialize AppIdx to a sane value */ - .app_idx = BT_MESH_KEY_UNUSED, - .recv_ttl = TTL(buf->om_data), - /* TTL=1 only goes to local IF */ - .send_ttl = 1U, - .addr = SRC(buf->om_data), - .recv_dst = DST(buf->om_data), - .recv_rssi = 0, - }, - .net_if = BT_MESH_NET_IF_LOCAL, - .sub = sub, - .old_iv = (IVI(buf->om_data) != (bt_mesh.iv_index & 0x01)), - .ctl = CTL(buf->om_data), - .seq = SEQ(buf->om_data), - .new_key = SUBNET_KEY_TX_IDX(sub), - .local_match = 1U, - .friend_match = 0U, - }; - - BT_DBG("src: 0x%04x dst: 0x%04x seq 0x%06x sub %p", rx.ctx.addr, - rx.ctx.addr, rx.seq, sub); - - (void) bt_mesh_trans_recv(buf, &rx); - net_buf_unref(buf); - } -} - -static const struct bt_mesh_net_cred *net_tx_cred_get(struct bt_mesh_net_tx *tx) -{ -#if defined(BLE_MESH_LOW_POWER) - if (tx->friend_cred && bt_mesh_lpn_established()) { - return &bt_mesh.lpn.cred[SUBNET_KEY_TX_IDX(tx->sub)]; - } -#endif - - tx->friend_cred = 0U; - return &tx->sub->keys[SUBNET_KEY_TX_IDX(tx->sub)].msg; -} - -static int net_header_encode(struct bt_mesh_net_tx *tx, uint8_t nid, - struct os_mbuf *buf) -{ - const bool ctl = (tx->ctx->app_idx == BT_MESH_KEY_UNUSED); - - if (ctl && net_buf_simple_tailroom(buf) < 8) { - BT_ERR("Insufficient MIC space for CTL PDU"); - return -EINVAL; - } else if (net_buf_simple_tailroom(buf) < 4) { - BT_ERR("Insufficient MIC space for PDU"); - return -EINVAL; - } - - BT_DBG("src 0x%04x dst 0x%04x ctl %u seq 0x%06x", - tx->src, tx->ctx->addr, ctl, bt_mesh.seq); - - net_buf_simple_push_be16(buf, tx->ctx->addr); - net_buf_simple_push_be16(buf, tx->src); - - net_buf_simple_push_be24(buf, bt_mesh_next_seq()); - - if (ctl) { - net_buf_simple_push_u8(buf, tx->ctx->send_ttl | 0x80); - } else { - net_buf_simple_push_u8(buf, tx->ctx->send_ttl); - } - - net_buf_simple_push_u8(buf, (nid | (BT_MESH_NET_IVI_TX & 1) << 7)); - - return 0; -} - -static int net_encrypt(struct os_mbuf *buf, - const struct bt_mesh_net_cred *cred, uint32_t iv_index, - bool proxy) -{ - int err; - - err = bt_mesh_net_encrypt(cred->enc, buf, iv_index, proxy); - if (err) { - return err; - } - - return bt_mesh_net_obfuscate(buf->om_data, iv_index, cred->privacy); -} - -int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct os_mbuf *buf, - bool proxy) -{ - const struct bt_mesh_net_cred *cred; - int err; - - cred = net_tx_cred_get(tx); - err = net_header_encode(tx, cred->nid, buf); - if (err) { - return err; - } - - return net_encrypt(buf, cred, BT_MESH_NET_IVI_TX, proxy); -} - -static int loopback(const struct bt_mesh_net_tx *tx, const uint8_t *data, - size_t len) -{ - struct os_mbuf *buf; - - buf = os_mbuf_get_pkthdr(&loopback_os_mbuf_pool, 0); - if (!buf) { - BT_WARN("Unable to allocate loopback"); - return -ENOMEM; - } - - BT_DBG(""); - - LOOPBACK_BUF_SUB(buf) = tx->sub; - - net_buf_add_mem(buf, data, len); - - net_buf_slist_put(&bt_mesh.local_queue, buf); - - k_work_submit(&bt_mesh.local_work); - - return 0; -} - -int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf, - const struct bt_mesh_send_cb *cb, void *cb_data) -{ - const struct bt_mesh_net_cred *cred; - int err; - - BT_DBG("src 0x%04x dst 0x%04x len %u headroom %zu tailroom %zu", - tx->src, tx->ctx->addr, buf->om_len, net_buf_headroom(buf), - net_buf_tailroom(buf)); - BT_DBG("Payload len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - BT_DBG("Seq 0x%06x", bt_mesh.seq); - - cred = net_tx_cred_get(tx); - err = net_header_encode(tx, cred->nid, buf); - if (err) { - goto done; - } - - BT_DBG("encoded %u bytes: %s", buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - /* Deliver to local network interface if necessary */ - if (bt_mesh_fixed_group_match(tx->ctx->addr) || - bt_mesh_elem_find(tx->ctx->addr)) { - err = loopback(tx, buf->om_data, buf->om_len); - - /* Local unicast messages should not go out to network */ - if (BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr) || - tx->ctx->send_ttl == 1U) { - if (!err) { - send_cb_finalize(cb, cb_data); - } - - goto done; - } - } - /* Mesh spec 3.4.5.2: "The output filter of the interface connected to - * advertising or GATT bearers shall drop all messages with TTL value - * set to 1." If a TTL=1 packet wasn't for a local interface, it is - * invalid. - */ - if (tx->ctx->send_ttl == 1U) { - err = -EINVAL; - goto done; - } - - err = net_encrypt(buf, cred, BT_MESH_NET_IVI_TX, false); - if (err) { - goto done; - } - - /* Deliver to GATT Proxy Clients if necessary. */ - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && - bt_mesh_proxy_relay(buf, tx->ctx->addr) && - BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { - /* Notify completion if this only went through the Mesh Proxy */ - send_cb_finalize(cb, cb_data); - - err = 0; - goto done; - } - - bt_mesh_adv_send(buf, cb, cb_data); - -done: - net_buf_unref(buf); - return err; -} - -void bt_mesh_net_loopback_clear(uint16_t net_idx) -{ - struct net_buf_slist_t new_list; - struct os_mbuf *buf; - - BT_DBG("0x%04x", net_idx); - - net_buf_slist_init(&new_list); - - while ((buf = net_buf_slist_get(&bt_mesh.local_queue))) { - struct bt_mesh_subnet *sub = LOOPBACK_BUF_SUB(buf); - - if (net_idx == BT_MESH_KEY_ANY || net_idx == sub->net_idx) { - BT_DBG("Dropped 0x%06x", SEQ(buf->om_data)); - net_buf_unref(buf); - } else { - net_buf_slist_put(&new_list, buf); - } - } - - bt_mesh.local_queue = new_list; -} - -static bool net_decrypt(struct bt_mesh_net_rx *rx, struct os_mbuf *in, - struct os_mbuf *out, - const struct bt_mesh_net_cred *cred) -{ - bool proxy = (rx->net_if == BT_MESH_NET_IF_PROXY_CFG); - - if (NID(in->om_data) != cred->nid) { - return false; - } - - BT_DBG("NID 0x%02x", NID(in->om_data)); - BT_DBG("IVI %u net->iv_index 0x%08x", IVI(in->om_data), bt_mesh.iv_index); - - rx->old_iv = (IVI(in->om_data) != (bt_mesh.iv_index & 0x01)); - net_buf_simple_reset(out); - net_buf_simple_add_mem(out, in->om_data, in->om_len); - - if (bt_mesh_net_obfuscate(out->om_data, BT_MESH_NET_IVI_RX(rx), - cred->privacy)) { - return false; - } - - rx->ctx.addr = SRC(out->om_data); - if (!BT_MESH_ADDR_IS_UNICAST(rx->ctx.addr)) { - BT_DBG("Ignoring non-unicast src addr 0x%04x", rx->ctx.addr); - return false; - } - - if (bt_mesh_elem_find(rx->ctx.addr)) { - BT_DBG("Dropping locally originated packet"); - return false; - } - - if (rx->net_if == BT_MESH_NET_IF_ADV && msg_cache_match(out)) { - BT_DBG("Duplicate found in Network Message Cache"); - return false; - } - - BT_DBG("src 0x%04x", rx->ctx.addr); - return bt_mesh_net_decrypt(cred->enc, out, BT_MESH_NET_IVI_RX(rx), - proxy) == 0; -} - -/* Relaying from advertising to the advertising bearer should only happen - * if the Relay state is set to enabled. Locally originated packets always - * get sent to the advertising bearer. If the packet came in through GATT, - * then we should only relay it if the GATT Proxy state is enabled. - */ -static bool relay_to_adv(enum bt_mesh_net_if net_if) -{ - switch (net_if) { - case BT_MESH_NET_IF_ADV: - return (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED); - case BT_MESH_NET_IF_PROXY: - return (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED); - default: - return false; - } -} - -static void bt_mesh_net_relay(struct os_mbuf *sbuf, - struct bt_mesh_net_rx *rx) -{ - const struct bt_mesh_net_cred *cred; - struct os_mbuf *buf; - uint8_t transmit; - - if (rx->ctx.recv_ttl <= 1U) { - return; - } - - if (rx->net_if == BT_MESH_NET_IF_ADV && - !rx->friend_cred && - bt_mesh_relay_get() != BT_MESH_RELAY_ENABLED && - bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_ENABLED) { - return; - } - - BT_DBG("TTL %u CTL %u dst 0x%04x", rx->ctx.recv_ttl, rx->ctl, - rx->ctx.recv_dst); - - /* The Relay Retransmit state is only applied to adv-adv relaying. - * Anything else (like GATT to adv, or locally originated packets) - * use the Network Transmit state. - */ - if (rx->net_if == BT_MESH_NET_IF_ADV && !rx->friend_cred) { - transmit = bt_mesh_relay_retransmit_get(); - } else { - transmit = bt_mesh_net_transmit_get(); - } - - buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, transmit, K_NO_WAIT); - if (!buf) { - BT_ERR("Out of relay buffers"); - return; - } - - /* Leave CTL bit intact */ - sbuf->om_data[1] &= 0x80; - sbuf->om_data[1] |= rx->ctx.recv_ttl - 1U; - - net_buf_add_mem(buf, sbuf->om_data, sbuf->om_len); - - cred = &rx->sub->keys[SUBNET_KEY_TX_IDX(rx->sub)].msg; - - BT_DBG("Relaying packet. TTL is now %u", TTL(buf->om_data)); - - /* Update NID if RX or RX was with friend credentials */ - if (rx->friend_cred) { - buf->om_data[0] &= 0x80; /* Clear everything except IVI */ - buf->om_data[0] |= cred->nid; - } - - /* We re-encrypt and obfuscate using the received IVI rather than - * the normal TX IVI (which may be different) since the transport - * layer nonce includes the IVI. - */ - if (net_encrypt(buf, cred, BT_MESH_NET_IVI_RX(rx), false)) { - BT_ERR("Re-encrypting failed"); - goto done; - } - - BT_DBG("encoded %u bytes: %s", buf->om_len, - bt_hex(buf->om_data, buf->om_len)); - - /* When the Friend node relays message for lpn, the message will be - * retransmitted using the managed master security credentials and - * the Network PDU shall be retransmitted to all network interfaces. - */ - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && - (rx->friend_cred || - bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED)) { - bt_mesh_proxy_relay(buf, rx->ctx.recv_dst); - } - - if (relay_to_adv(rx->net_if) || rx->friend_cred) { - bt_mesh_adv_send(buf, NULL, NULL); - } - -done: - net_buf_unref(buf); -} - -void bt_mesh_net_header_parse(struct os_mbuf *buf, - struct bt_mesh_net_rx *rx) -{ - rx->old_iv = (IVI(buf->om_data) != (bt_mesh.iv_index & 0x01)); - rx->ctl = CTL(buf->om_data); - rx->ctx.recv_ttl = TTL(buf->om_data); - rx->seq = SEQ(buf->om_data); - rx->ctx.addr = SRC(buf->om_data); - rx->ctx.recv_dst = DST(buf->om_data); -} - -int bt_mesh_net_decode(struct os_mbuf *in, enum bt_mesh_net_if net_if, - struct bt_mesh_net_rx *rx, struct os_mbuf *out) -{ - if (in->om_len < BT_MESH_NET_MIN_PDU_LEN) { - BT_WARN("Dropping too short mesh packet (len %u)", in->om_len); - BT_WARN("%s", bt_hex(in->om_data, in->om_len)); - return -EINVAL; - } - - if (net_if == BT_MESH_NET_IF_ADV && check_dup(in)) { - BT_DBG("duplicate packet; dropping %u bytes: %s", in->om_len, - bt_hex(in->om_data, in->om_len)); - return -EINVAL; - } - - BT_DBG("%u bytes: %s", in->om_len, bt_hex(in->om_data, in->om_len)); - - rx->net_if = net_if; - - if (!bt_mesh_net_cred_find(rx, in, out, net_decrypt)) { - BT_DBG("Unable to find matching net for packet"); - return -ENOENT; - } - - /* Initialize AppIdx to a sane value */ - rx->ctx.app_idx = BT_MESH_KEY_UNUSED; - - rx->ctx.recv_ttl = TTL(out->om_data); - - /* Default to responding with TTL 0 for non-routed messages */ - if (rx->ctx.recv_ttl == 0) { - rx->ctx.send_ttl = 0; - } else { - rx->ctx.send_ttl = BT_MESH_TTL_DEFAULT; - } - - rx->ctl = CTL(out->om_data); - rx->seq = SEQ(out->om_data); - rx->ctx.recv_dst = DST(out->om_data); - - BT_DBG("Decryption successful. Payload len %u: %s", out->om_len, - bt_hex(out->om_data, out->om_len)); - - if (net_if != BT_MESH_NET_IF_PROXY_CFG && - rx->ctx.recv_dst == BT_MESH_ADDR_UNASSIGNED) { - BT_ERR("Destination address is unassigned; dropping packet"); - return -EBADMSG; - } - - BT_DBG("src 0x%04x dst 0x%04x ttl %u", rx->ctx.addr, rx->ctx.recv_dst, - rx->ctx.recv_ttl); - BT_DBG("PDU: %s", bt_hex(out->om_data, out->om_len)); - - msg_cache_add(rx); - - return 0; -} - -void bt_mesh_net_recv(struct os_mbuf *data, int8_t rssi, - enum bt_mesh_net_if net_if) -{ - struct os_mbuf *buf = NET_BUF_SIMPLE(29); - struct bt_mesh_net_rx rx = { .ctx.recv_rssi = rssi }; - struct net_buf_simple_state state; - - BT_DBG("rssi %d net_if %u", rssi, net_if); - - if (!bt_mesh_is_provisioned()) { - BT_ERR("Not provisioned; dropping packet"); - goto done; - } - - if (bt_mesh_net_decode(data, net_if, &rx, buf)) { - goto done; - } - - /* Save the state so the buffer can later be relayed */ - net_buf_simple_save(buf, &state); - - rx.local_match = (bt_mesh_fixed_group_match(rx.ctx.recv_dst) || - bt_mesh_elem_find(rx.ctx.recv_dst)); - - if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY)) && - net_if == BT_MESH_NET_IF_PROXY) { - bt_mesh_proxy_addr_add(data, rx.ctx.addr); - - if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_DISABLED && - !rx.local_match) { - BT_INFO("Proxy is disabled; ignoring message"); - goto done; - } - } - - /* The transport layer has indicated that it has rejected the message, - * but would like to see it again if it is received in the future. - * This can happen if a message is received when the device is in - * Low Power mode, but the message was not encrypted with the friend - * credentials. Remove it from the message cache so that we accept - * it again in the future. - */ - if (bt_mesh_trans_recv(buf, &rx) == -EAGAIN) { - BT_WARN("Removing rejected message from Network Message Cache"); - msg_cache[rx.msg_cache_idx].src = BT_MESH_ADDR_UNASSIGNED; - /* Rewind the next index now that we're not using this entry */ - msg_cache_next = rx.msg_cache_idx; - } - - /* Relay if this was a group/virtual address, or if the destination - * was neither a local element nor an LPN we're Friends for. - */ - if (!BT_MESH_ADDR_IS_UNICAST(rx.ctx.recv_dst) || - (!rx.local_match && !rx.friend_match)) { - net_buf_simple_restore(buf, &state); - bt_mesh_net_relay(buf, &rx); - } - -done: - os_mbuf_free_chain(buf); -} - -static void ivu_refresh(struct ble_npl_event *work) -{ - bt_mesh.ivu_duration = MIN(UINT8_MAX, - bt_mesh.ivu_duration + BT_MESH_IVU_HOURS); - - BT_DBG("%s for %u hour%s", - atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) ? - "IVU in Progress" : "IVU Normal mode", - bt_mesh.ivu_duration, bt_mesh.ivu_duration == 1 ? "" : "s"); - - if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) { - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_iv(true); - } - - k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); - return; - } - - if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)) { - bt_mesh_beacon_ivu_initiator(true); - bt_mesh_net_iv_update(bt_mesh.iv_index, false); - } else if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_iv(true); - } -} - -void bt_mesh_net_init(void) -{ - int rc; - - k_delayed_work_init(&bt_mesh.ivu_timer, ivu_refresh); - - k_work_init(&bt_mesh.local_work, bt_mesh_net_local); - net_buf_slist_init(&bt_mesh.local_queue); - - rc = os_mempool_init(&loopback_buf_mempool, MYNEWT_VAL(BLE_MESH_LOOPBACK_BUFS), - LOOPBACK_MAX_PDU_LEN + BT_MESH_MBUF_HEADER_SIZE, - &loopback_mbuf_membuf[0], "loopback_buf_pool"); - assert(rc == 0); - - rc = os_mbuf_pool_init(&loopback_os_mbuf_pool, &loopback_buf_mempool, - LOOPBACK_MAX_PDU_LEN + BT_MESH_MBUF_HEADER_SIZE, - MYNEWT_VAL(BLE_MESH_LOOPBACK_BUFS)); - assert(rc == 0); -} -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/net.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/net.h deleted file mode 100644 index 91656f645..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/net.h +++ /dev/null @@ -1,317 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __NET_H__ -#define __NET_H__ - -#include "subnet.h" - -#define BT_MESH_IV_UPDATE(flags) ((flags >> 1) & 0x01) -#define BT_MESH_KEY_REFRESH(flags) (flags & 0x01) - -#include -#include "atomic.h" -#include "../include/mesh/mesh.h" -#include "../include/mesh/glue.h" - -/* How many hours in between updating IVU duration */ -#define BT_MESH_IVU_MIN_HOURS 96 -#define BT_MESH_IVU_HOURS (BT_MESH_IVU_MIN_HOURS / \ - CONFIG_BT_MESH_IVU_DIVIDER) -#define BT_MESH_IVU_TIMEOUT K_HOURS(BT_MESH_IVU_HOURS) - -struct bt_mesh_net_cred; - -struct bt_mesh_node { - uint16_t addr; - uint16_t net_idx; - uint8_t dev_key[16]; - uint8_t num_elem; -}; - -#if MYNEWT_VAL(BLE_MESH_FRIEND) -#define FRIEND_SEG_RX MYNEWT_VAL(BLE_MESH_FRIEND_SEG_RX) -#define FRIEND_SUB_LIST_SIZE MYNEWT_VAL(BLE_MESH_FRIEND_SUB_LIST_SIZE) -#else -#define FRIEND_SEG_RX 0 -#define FRIEND_SUB_LIST_SIZE 0 -#endif - -struct bt_mesh_friend { - uint16_t lpn; - uint8_t recv_delay; - uint8_t fsn:1, - send_last:1, - pending_req:1, - pending_buf:1, - established:1; - int32_t poll_to; - uint8_t num_elem; - uint16_t lpn_counter; - uint16_t counter; - - struct bt_mesh_subnet *subnet; - - struct bt_mesh_net_cred cred[2]; - - uint16_t sub_list[FRIEND_SUB_LIST_SIZE]; - - struct k_delayed_work timer; - - struct bt_mesh_friend_seg { - struct net_buf_slist_t queue; - - /* The target number of segments, i.e. not necessarily - * the current number of segments, in the queue. This is - * used for Friend Queue free space calculations. - */ - uint8_t seg_count; - } seg[FRIEND_SEG_RX]; - - struct os_mbuf *last; - - struct net_buf_slist_t queue; - uint32_t queue_size; - - /* Friend Clear Procedure */ - struct { - uint32_t start; /* Clear Procedure start */ - uint16_t frnd; /* Previous Friend's address */ - uint16_t repeat_sec; /* Repeat timeout in seconds */ - struct k_delayed_work timer; /* Repeat timer */ - } clear; -}; - -#if (MYNEWT_VAL(BLE_MESH_LOW_POWER)) -#define LPN_GROUPS CONFIG_BT_MESH_LPN_GROUPS -#else -#define LPN_GROUPS 0 -#endif - -/* Low Power Node state */ -struct bt_mesh_lpn { - enum __packed { - BT_MESH_LPN_DISABLED, /* LPN feature is disabled */ - BT_MESH_LPN_CLEAR, /* Clear in progress */ - BT_MESH_LPN_TIMER, /* Waiting for auto timer expiry */ - BT_MESH_LPN_ENABLED, /* LPN enabled, but no Friend */ - BT_MESH_LPN_REQ_WAIT, /* Wait before scanning for offers */ - BT_MESH_LPN_WAIT_OFFER, /* Friend Req sent */ - BT_MESH_LPN_ESTABLISHED, /* Friendship established */ - BT_MESH_LPN_RECV_DELAY, /* Poll sent, waiting ReceiveDelay */ - BT_MESH_LPN_WAIT_UPDATE, /* Waiting for Update or message */ - } state; - - /* Transaction Number (used for subscription list) */ - uint8_t xact_next; - uint8_t xact_pending; - uint8_t sent_req; - - /* Address of our Friend when we're a LPN. Unassigned if we don't - * have a friend yet. - */ - uint16_t frnd; - - /* Value from the friend offer */ - uint8_t recv_win; - - uint8_t req_attempts; /* Number of Request attempts */ - - int32_t poll_timeout; - - uint8_t groups_changed:1, /* Friend Subscription List needs updating */ - pending_poll:1, /* Poll to be sent after subscription */ - disable:1, /* Disable LPN after clearing */ - fsn:1, /* Friend Sequence Number */ - established:1, /* Friendship established */ - clear_success:1; /* Friend Clear Confirm received */ - - /* Friend Queue Size */ - uint8_t queue_size; - - /* FriendCounter */ - uint16_t frnd_counter; - - /* LPNCounter */ - uint16_t lpn_counter; - - /* Previous Friend of this LPN */ - uint16_t old_friend; - - /* Duration reported for last advertising packet */ - uint16_t adv_duration; - - /* Next LPN related action timer */ - struct k_delayed_work timer; - - /* Subscribed groups */ - uint16_t groups[LPN_GROUPS]; - - struct bt_mesh_subnet *sub; - - struct bt_mesh_net_cred cred[2]; - - /* Bit fields for tracking which groups the Friend knows about */ - ATOMIC_DEFINE(added, LPN_GROUPS); - ATOMIC_DEFINE(pending, LPN_GROUPS); - ATOMIC_DEFINE(to_remove, LPN_GROUPS); -}; - -/* bt_mesh_net.flags */ -enum { - BT_MESH_VALID, /* We have been provisioned */ - BT_MESH_SUSPENDED, /* Network is temporarily suspended */ - BT_MESH_IVU_IN_PROGRESS, /* IV Update in Progress */ - BT_MESH_IVU_INITIATOR, /* IV Update initiated by us */ - BT_MESH_IVU_TEST, /* IV Update test mode */ - BT_MESH_IVU_PENDING, /* Update blocked by SDU in progress */ - - /* pending storage actions, must reside within first 32 flags */ - BT_MESH_RPL_PENDING, - BT_MESH_KEYS_PENDING, - BT_MESH_NET_PENDING, - BT_MESH_IV_PENDING, - BT_MESH_SEQ_PENDING, - BT_MESH_HB_PUB_PENDING, - BT_MESH_CFG_PENDING, - BT_MESH_MOD_PENDING, - BT_MESH_VA_PENDING, - - /* Feature flags */ - BT_MESH_RELAY, - BT_MESH_BEACON, - BT_MESH_GATT_PROXY, - BT_MESH_FRIEND, - - /* Don't touch - intentionally last */ - BT_MESH_FLAG_COUNT, -}; - -struct bt_mesh_net { - uint32_t iv_index; /* Current IV Index */ - uint32_t seq; /* Next outgoing sequence number (24 bits) */ - - ATOMIC_DEFINE(flags, BT_MESH_FLAG_COUNT); - - /* Local network interface */ - struct ble_npl_callout local_work; - struct net_buf_slist_t local_queue; - -#if MYNEWT_VAL(BLE_MESH_FRIEND) - /* Friend state, unique for each LPN that we're Friends for */ - struct bt_mesh_friend frnd[MYNEWT_VAL(BLE_MESH_FRIEND_LPN_COUNT)]; -#endif - -#if (MYNEWT_VAL(BLE_MESH_LOW_POWER)) - struct bt_mesh_lpn lpn; /* Low Power Node state */ -#endif - - /* Number of hours in current IV Update state */ - uint8_t ivu_duration; - - uint8_t net_xmit; - uint8_t relay_xmit; - uint8_t default_ttl; - - /* Timer to track duration in current IV Update state */ - struct k_delayed_work ivu_timer; - - uint8_t dev_key[16]; -}; - -/* Network interface */ -enum bt_mesh_net_if { - BT_MESH_NET_IF_ADV, - BT_MESH_NET_IF_LOCAL, - BT_MESH_NET_IF_PROXY, - BT_MESH_NET_IF_PROXY_CFG, -}; - -/* Decoding context for Network/Transport data */ -struct bt_mesh_net_rx { - struct bt_mesh_subnet *sub; - struct bt_mesh_msg_ctx ctx; - uint32_t seq; /* Sequence Number */ - uint8_t old_iv:1, /* iv_index - 1 was used */ - new_key:1, /* Data was encrypted with updated key */ - friend_cred:1, /* Data was encrypted with friend cred */ - ctl:1, /* Network Control */ - net_if:2, /* Network interface */ - local_match:1, /* Matched a local element */ - friend_match:1; /* Matched an LPN we're friends for */ - uint16_t msg_cache_idx; /* Index of entry in message cache */ -}; - -/* Encoding context for Network/Transport data */ -struct bt_mesh_net_tx { - struct bt_mesh_subnet *sub; - struct bt_mesh_msg_ctx *ctx; - uint16_t src; - uint8_t xmit; - uint8_t friend_cred:1, - aszmic:1, - aid:6; -}; - -extern struct bt_mesh_net bt_mesh; - -#define BT_MESH_NET_IVI_TX (bt_mesh.iv_index - \ - atomic_test_bit(bt_mesh.flags, \ - BT_MESH_IVU_IN_PROGRESS)) -#define BT_MESH_NET_IVI_RX(rx) (bt_mesh.iv_index - (rx)->old_iv) - -#define BT_MESH_NET_HDR_LEN 9 - -static inline void *net_buf_user_data(const struct os_mbuf *buf) -{ - return (void *)buf->om_data; -} - -int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], - uint32_t iv_index); - -bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update); - -int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct os_mbuf *buf, - bool proxy); - -int bt_mesh_net_decode(struct os_mbuf *in, enum bt_mesh_net_if net_if, - struct bt_mesh_net_rx *rx, struct os_mbuf *out); - -int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf, - const struct bt_mesh_send_cb *cb, void *cb_data); - -void bt_mesh_net_recv(struct os_mbuf *data, int8_t rssi, - enum bt_mesh_net_if net_if); - -void bt_mesh_net_loopback_clear(uint16_t net_idx); - -uint32_t bt_mesh_next_seq(void); - -void bt_mesh_net_init(void); -void bt_mesh_net_header_parse(struct os_mbuf *buf, - struct bt_mesh_net_rx *rx); - - -static inline void send_cb_finalize(const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (!cb) { - return; - } - - if (cb->start) { - cb->start(0, 0, cb_data); - } - - if (cb->end) { - cb->end(0, cb_data); - } -} - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/nodes.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/nodes.c deleted file mode 100644 index 199550d99..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/nodes.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2019 Tobias Svehagen - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_PROV_LOG - -#if MYNEWT_VAL(BLE_MESH_PROVISIONER) - -#include "../include/mesh/mesh.h" - -#include "mesh_priv.h" -#include "net.h" -#include "access.h" -#include "settings.h" - -/* - * Check if an address range from addr_start for addr_start + num_elem - 1 is - * free for use. When a conflict is found, next will be set to the next address - * available after the conflicting range and -EAGAIN will be returned. - */ -static int addr_is_free(u16_t addr_start, u8_t num_elem, u16_t *next) -{ - const struct bt_mesh_comp *comp = bt_mesh_comp_get(); - u16_t addr_end = addr_start + num_elem - 1; - u16_t other_start, other_end; - int i; - - if (comp == NULL) { - return -EINVAL; - } - - if (!BT_MESH_ADDR_IS_UNICAST(addr_start) || - !BT_MESH_ADDR_IS_UNICAST(addr_end) || - num_elem == 0 || next == NULL) { - return -EINVAL; - } - - other_start = bt_mesh_primary_addr(); - other_end = other_start + comp->elem_count - 1; - - /* Compare with local element addresses */ - if (!(addr_end < other_start || addr_start > other_end)) { - *next = other_end + 1; - return -EAGAIN; - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) { - struct bt_mesh_node *node = &bt_mesh.nodes[i]; - - if (node->net_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - other_start = node->addr; - other_end = other_start + node->num_elem - 1; - - if (!(addr_end < other_start || addr_start > other_end)) { - *next = other_end + 1; - return -EAGAIN; - } - } - - return 0; -} - -/* - * Find the lowest possible starting address that can fit num_elem elements. If - * a free address range cannot be found, BT_MESH_ADDR_UNASSIGNED will be - * returned. Otherwise the first address in the range is returned. - * - * NOTE: This is quite an ineffective algorithm as it might need to look - * through the array of nodes N+2 times. A more effective algorithm - * could be used if the nodes were stored in a sorted list. - */ -static u16_t find_lowest_free_addr(u8_t num_elem) -{ - u16_t addr = 1, next; - int err, i; - - /* - * It takes a maximum of node count + 2 to find a free address if there - * is any. +1 for our own address and +1 for making sure that the - * address range is valid. - */ - for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes) + 2; ++i) { - err = addr_is_free(addr, num_elem, &next); - if (err == 0) { - break; - } else if (err != -EAGAIN) { - addr = BT_MESH_ADDR_UNASSIGNED; - break; - } - - addr = next; - } - - return addr; -} - -struct bt_mesh_node *bt_mesh_node_find(u16_t addr) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) { - struct bt_mesh_node *node = &bt_mesh.nodes[i]; - - if (addr >= node->addr && - addr <= node->addr + node->num_elem - 1) { - return node; - } - } - - return NULL; -} - -struct bt_mesh_node *bt_mesh_node_alloc(u16_t addr, u8_t num_elem, - u16_t net_idx) -{ - int i; - - BT_DBG(""); - - if (addr == BT_MESH_ADDR_UNASSIGNED) { - addr = find_lowest_free_addr(num_elem); - if (addr == BT_MESH_ADDR_UNASSIGNED) { - return NULL; - } - } else if (!addr_is_free(addr, num_elem, NULL)) { - return NULL; - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) { - struct bt_mesh_node *node = &bt_mesh.nodes[i]; - - if (node->addr == BT_MESH_ADDR_UNASSIGNED) { - node->addr = addr; - node->num_elem = num_elem; - node->net_idx = net_idx; - return node; - } - } - - return NULL; -} - -void bt_mesh_node_del(struct bt_mesh_node *node, bool store) -{ - BT_DBG("Node addr 0x%04x store %u", node->addr, store); - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_clear_node(node); - } - - node->addr = BT_MESH_ADDR_UNASSIGNED; - (void)memset(node->dev_key, 0, sizeof(node->dev_key)); -} - -#endif -#endif /* MYNEWT_VAL(BLE_MESH) */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/nodes.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/nodes.h deleted file mode 100644 index f86193d9e..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/nodes.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2019 Tobias Svehagen - * - * SPDX-License-Identifier: Apache-2.0 - */ - -struct bt_mesh_node *bt_mesh_node_find(u16_t addr); -struct bt_mesh_node *bt_mesh_node_alloc(u16_t addr, u8_t num_elem, - u16_t net_idx); -void bt_mesh_node_del(struct bt_mesh_node *node, bool store); \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/pb_adv.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/pb_adv.c deleted file mode 100644 index 9b20475a5..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/pb_adv.c +++ /dev/null @@ -1,891 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_PROV_LOG - -#if MYNEWT_VAL(BLE_MESH) - -#include -#include -#include "../include/mesh/mesh.h" -#include -#include "net.h" -#include "prov.h" -#include "adv.h" -#include "crypto.h" -#include "beacon.h" -#include "prov.h" -#include "../include/mesh/glue.h" - -#define GPCF(gpc) (gpc & 0x03) -#define GPC_START(last_seg) (((last_seg) << 2) | 0x00) -#define GPC_ACK 0x01 -#define GPC_CONT(seg_id) (((seg_id) << 2) | 0x02) -#define GPC_CTL(op) (((op) << 2) | 0x03) - -#define START_PAYLOAD_MAX 20 -#define CONT_PAYLOAD_MAX 23 - -#define START_LAST_SEG(gpc) (gpc >> 2) -#define CONT_SEG_INDEX(gpc) (gpc >> 2) - -#define BEARER_CTL(gpc) (gpc >> 2) -#define LINK_OPEN 0x00 -#define LINK_ACK 0x01 -#define LINK_CLOSE 0x02 - -#define XACT_SEG_DATA(_seg) (&link.rx.buf->om_data[20 + ((_seg - 1) * 23)]) -#define XACT_SEG_RECV(_seg) (link.rx.seg &= ~(1 << (_seg))) - -#define XACT_ID_MAX 0x7f -#define XACT_ID_NVAL 0xff -#define SEG_NVAL 0xff - -#define RETRANSMIT_TIMEOUT K_MSEC(MYNEWT_VAL(BLE_MESH_PB_ADV_RETRANS_TIMEOUT)) -#define BUF_TIMEOUT K_MSEC(400) -#define CLOSING_TIMEOUT K_SECONDS(3) -#define TRANSACTION_TIMEOUT K_SECONDS(30) - -/* Acked messages, will do retransmissions manually, taking acks into account: - */ -#define RETRANSMITS_RELIABLE 0 -/* Unacked messages: */ -#define RETRANSMITS_UNRELIABLE 2 -/* PDU acks: */ -#define RETRANSMITS_ACK 2 - -enum { - ADV_LINK_ACTIVE, /* Link has been opened */ - ADV_LINK_ACK_RECVD, /* Ack for link has been received */ - ADV_LINK_CLOSING, /* Link is closing down */ - ADV_LINK_INVALID, /* Error occurred during provisioning */ - ADV_ACK_PENDING, /* An acknowledgment is being sent */ - ADV_PROVISIONER, /* The link was opened as provisioner */ - - ADV_NUM_FLAGS, -}; - -struct pb_adv { - uint32_t id; /* Link ID */ - - ATOMIC_DEFINE(flags, ADV_NUM_FLAGS); - - const struct prov_bearer_cb *cb; - void *cb_data; - - struct { - uint8_t id; /* Most recent transaction ID */ - uint8_t seg; /* Bit-field of unreceived segments */ - uint8_t last_seg; /* Last segment (to check length) */ - uint8_t fcs; /* Expected FCS value */ - struct os_mbuf *buf; - } rx; - - struct { - /* Start timestamp of the transaction */ - int64_t start; - - /* Transaction id */ - uint8_t id; - - /* Current ack id */ - uint8_t pending_ack; - - /* Pending outgoing buffer(s) */ - struct os_mbuf *buf[3]; - - prov_bearer_send_complete_t cb; - - void *cb_data; - - /* Retransmit timer */ - struct k_delayed_work retransmit; - } tx; - - /* Protocol timeout */ - struct k_delayed_work prot_timer; -}; - -struct prov_rx { - uint32_t link_id; - uint8_t xact_id; - uint8_t gpc; -}; - -static struct os_mbuf *rx_buf; -static struct pb_adv link; - -static void gen_prov_ack_send(uint8_t xact_id); -static void link_open(struct prov_rx *rx, struct os_mbuf *buf); -static void link_ack(struct prov_rx *rx, struct os_mbuf *buf); -static void link_close(struct prov_rx *rx, struct os_mbuf *buf); - -static void buf_sent(int err, void *user_data) -{ - BT_DBG("buf_send"); - - if (!link.tx.buf[0]) { - return; - } - - BT_DBG("submit retransmit"); - k_delayed_work_submit(&link.tx.retransmit, RETRANSMIT_TIMEOUT); -} - -static struct bt_mesh_send_cb buf_sent_cb = { - .end = buf_sent, -}; - -static uint8_t last_seg(uint8_t len) -{ - if (len <= START_PAYLOAD_MAX) { - return 0; - } - - len -= START_PAYLOAD_MAX; - - return 1 + (len / CONT_PAYLOAD_MAX); -} - -static void free_segments(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { - struct os_mbuf *buf = link.tx.buf[i]; - - if (!buf) { - break; - } - - link.tx.buf[i] = NULL; - /* Mark as canceled */ - BT_MESH_ADV(buf)->busy = 0U; - net_buf_unref(buf); - } -} - -static uint8_t next_transaction_id(uint8_t id) -{ - return (((id + 1) & XACT_ID_MAX) | (id & (XACT_ID_MAX+1))); -} - -static void prov_clear_tx(void) -{ - BT_DBG(""); - - k_delayed_work_cancel(&link.tx.retransmit); - - free_segments(); -} - -static void reset_adv_link(void) -{ - BT_DBG(""); - prov_clear_tx(); - - k_delayed_work_cancel(&link.prot_timer); - - if (atomic_test_bit(link.flags, ADV_PROVISIONER)) { - /* Clear everything except the retransmit and protocol timer - * delayed work objects. - */ - (void)memset(&link, 0, offsetof(struct pb_adv, tx.retransmit)); - link.rx.id = XACT_ID_NVAL; - } else { - /* Accept another provisioning attempt */ - link.id = 0; - atomic_clear(link.flags); - link.rx.id = XACT_ID_MAX; - link.tx.id = XACT_ID_NVAL; - } - link.tx.pending_ack = XACT_ID_NVAL; - if (!rx_buf) { - rx_buf = NET_BUF_SIMPLE(65); - } - link.rx.buf = rx_buf; - net_buf_simple_reset(link.rx.buf); -} - -static void close_link(enum prov_bearer_link_status reason) -{ - const struct prov_bearer_cb *cb = link.cb; - void *cb_data = link.cb_data; - - reset_adv_link(); - cb->link_closed(&pb_adv, cb_data, reason); -} - -static struct os_mbuf *adv_buf_create(uint8_t retransmits) -{ - struct os_mbuf *buf; - - buf = bt_mesh_adv_create(BT_MESH_ADV_PROV, - BT_MESH_TRANSMIT(retransmits, 20), - BUF_TIMEOUT); - if (!buf) { - BT_ERR("Out of provisioning buffers"); - return NULL; - } - - return buf; -} - -static void ack_complete(uint16_t duration, int err, void *user_data) -{ - BT_DBG("xact 0x%x complete", (uint8_t)link.tx.pending_ack); - atomic_clear_bit(link.flags, ADV_ACK_PENDING); -} - -static bool ack_pending(void) -{ - return atomic_test_bit(link.flags, ADV_ACK_PENDING); -} - -static void prov_failed(uint8_t err) -{ - BT_DBG("%u", err); - link.cb->error(&pb_adv, link.cb_data, err); - atomic_set_bit(link.flags, ADV_LINK_INVALID); -} - -static void prov_msg_recv(void) -{ - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); - - if (!bt_mesh_fcs_check(link.rx.buf, link.rx.fcs)) { - BT_ERR("Incorrect FCS"); - return; - } - - gen_prov_ack_send(link.rx.id); - - if (atomic_test_bit(link.flags, ADV_LINK_INVALID)) { - BT_WARN("Unexpected msg 0x%02x on invalidated link", - link.rx.buf->om_data[0]); - prov_failed(PROV_ERR_UNEXP_PDU); - return; - } - - link.cb->recv(&pb_adv, link.cb_data, link.rx.buf); -} - -static void protocol_timeout(struct ble_npl_event *work) -{ - BT_DBG(""); - - link.rx.seg = 0U; - close_link(PROV_BEARER_LINK_STATUS_TIMEOUT); -} -/******************************************************************************* - * Generic provisioning - ******************************************************************************/ - -static void gen_prov_ack_send(uint8_t xact_id) -{ - static const struct bt_mesh_send_cb cb = { - .start = ack_complete, - }; - const struct bt_mesh_send_cb *complete; - struct os_mbuf *buf; - bool pending = atomic_test_and_set_bit(link.flags, ADV_ACK_PENDING); - - BT_DBG("xact_id 0x%x", xact_id); - - if (pending && link.tx.pending_ack == xact_id) { - BT_DBG("Not sending duplicate ack"); - return; - } - - buf = adv_buf_create(RETRANSMITS_ACK); - if (!buf) { - atomic_clear_bit(link.flags, ADV_ACK_PENDING); - return; - } - - if (pending) { - complete = NULL; - } else { - link.tx.pending_ack = xact_id; - complete = &cb; - } - - net_buf_add_be32(buf, link.id); - net_buf_add_u8(buf, xact_id); - net_buf_add_u8(buf, GPC_ACK); - - bt_mesh_adv_send(buf, complete, NULL); - net_buf_unref(buf); -} - -static void gen_prov_cont(struct prov_rx *rx, struct os_mbuf *buf) -{ - uint8_t seg = CONT_SEG_INDEX(rx->gpc); - - BT_DBG("len %u, seg_index %u", buf->om_len, seg); - - if (!link.rx.seg && link.rx.id == rx->xact_id) { - if (!ack_pending()) { - BT_DBG("Resending ack"); - gen_prov_ack_send(rx->xact_id); - } - - return; - } - - if (!link.rx.seg && - next_transaction_id(link.rx.id) == rx->xact_id) { - BT_DBG("Start segment lost"); - - link.rx.id = rx->xact_id; - - net_buf_simple_reset(link.rx.buf); - link.rx.seg = SEG_NVAL; - link.rx.last_seg = SEG_NVAL; - - prov_clear_tx(); - } else if (rx->xact_id != link.rx.id) { - BT_WARN("Data for unknown transaction (0x%x != 0x%x)", - rx->xact_id, link.rx.id); - return; - } - - if (seg > link.rx.last_seg) { - BT_ERR("Invalid segment index %u", seg); - prov_failed(PROV_ERR_NVAL_FMT); - return; - } - - if (!(link.rx.seg & BIT(seg))) { - BT_DBG("Ignoring already received segment"); - return; - } - - memcpy(XACT_SEG_DATA(seg), buf->om_data, buf->om_len); - XACT_SEG_RECV(seg); - - if (seg == link.rx.last_seg && !(link.rx.seg & BIT(0))) { - uint8_t expect_len; - - expect_len = (link.rx.buf->om_len - 20U - - ((link.rx.last_seg - 1) * 23U)); - if (expect_len != buf->om_len) { - BT_ERR("Incorrect last seg len: %u != %u", expect_len, - buf->om_len); - prov_failed(PROV_ERR_NVAL_FMT); - return; - } - } - - if (!link.rx.seg) { - prov_msg_recv(); - } -} - -static void gen_prov_ack(struct prov_rx *rx, struct os_mbuf *buf) -{ - BT_DBG("len %u", buf->om_len); - - if (!link.tx.buf[0]) { - return; - } - - if (rx->xact_id == link.tx.id) { - /* Don't clear resending of link_close messages */ - if (!atomic_test_bit(link.flags, ADV_LINK_CLOSING)) { - prov_clear_tx(); - } - - if (link.tx.cb) { - link.tx.cb(0, link.tx.cb_data); - } - } -} - -static void gen_prov_start(struct prov_rx *rx, struct os_mbuf *buf) -{ - uint8_t seg = SEG_NVAL; - - if (rx->xact_id == link.rx.id) { - if (!link.rx.seg) { - if (!ack_pending()) { - BT_DBG("Resending ack"); - gen_prov_ack_send(rx->xact_id); - } - - return; - } - - if (!(link.rx.seg & BIT(0))) { - BT_DBG("Ignoring duplicate segment"); - return; - } - } else if (rx->xact_id != next_transaction_id(link.rx.id)) { - BT_WARN("Unexpected xact 0x%x, expected 0x%x", rx->xact_id, - next_transaction_id(link.rx.id)); - return; - } - - net_buf_simple_reset(link.rx.buf); - link.rx.buf->om_len = net_buf_simple_pull_be16(buf); - link.rx.id = rx->xact_id; - link.rx.fcs = net_buf_simple_pull_u8(buf); - - BT_DBG("%p len %u last_seg %u total_len %u fcs 0x%02x", link.rx.buf, buf->om_len, - START_LAST_SEG(rx->gpc), link.rx.buf->om_len, link.rx.fcs); - - if (link.rx.buf->om_len < 1) { - BT_ERR("Ignoring zero-length provisioning PDU"); - prov_failed(PROV_ERR_NVAL_FMT); - return; - } - - if (START_LAST_SEG(rx->gpc) > 0 && link.rx.buf->om_len <= 20U) { - BT_ERR("Too small total length for multi-segment PDU"); - prov_failed(PROV_ERR_NVAL_FMT); - return; - } - - prov_clear_tx(); - - link.rx.last_seg = START_LAST_SEG(rx->gpc); - if ((link.rx.seg & BIT(0)) && - (find_msb_set((~link.rx.seg) & SEG_NVAL) - 1 > link.rx.last_seg)) { - BT_ERR("Invalid segment index %u", seg); - prov_failed(PROV_ERR_NVAL_FMT); - return; - } - - if (link.rx.seg) { - seg = link.rx.seg; - } - - link.rx.seg = seg & ((1 << (START_LAST_SEG(rx->gpc) + 1)) - 1); - memcpy(link.rx.buf->om_data, buf->om_data, buf->om_len); - XACT_SEG_RECV(0); - - if (!link.rx.seg) { - prov_msg_recv(); - } -} - -static void gen_prov_ctl(struct prov_rx *rx, struct os_mbuf *buf) -{ - BT_DBG("op 0x%02x len %u", BEARER_CTL(rx->gpc), buf->om_len); - - switch (BEARER_CTL(rx->gpc)) { - case LINK_OPEN: - link_open(rx, buf); - break; - case LINK_ACK: - if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { - return; - } - - link_ack(rx, buf); - break; - case LINK_CLOSE: - if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { - return; - } - - link_close(rx, buf); - break; - default: - BT_ERR("Unknown bearer opcode: 0x%02x", BEARER_CTL(rx->gpc)); - - if (IS_ENABLED(CONFIG_BT_TESTING)) { - bt_test_mesh_prov_invalid_bearer(BEARER_CTL(rx->gpc)); - } - - return; - } -} - -static const struct { - void (*func)(struct prov_rx *rx, struct os_mbuf *buf); - bool require_link; - uint8_t min_len; -} gen_prov[] = { - { gen_prov_start, true, 3 }, - { gen_prov_ack, true, 0 }, - { gen_prov_cont, true, 0 }, - { gen_prov_ctl, false, 0 }, -}; - -static void gen_prov_recv(struct prov_rx *rx, struct os_mbuf *buf) -{ - if (buf->om_len < gen_prov[GPCF(rx->gpc)].min_len) { - BT_ERR("Too short GPC message type %u", GPCF(rx->gpc)); - return; - } - - if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE) && - gen_prov[GPCF(rx->gpc)].require_link) { - BT_DBG("Ignoring message that requires active link"); - return; - } - - gen_prov[GPCF(rx->gpc)].func(rx, buf); -} - -/******************************************************************************* - * TX - ******************************************************************************/ - -static void send_reliable(void) -{ - int i; - - link.tx.start = k_uptime_get(); - - for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { - struct os_mbuf *buf = link.tx.buf[i]; - - if (!buf) { - break; - } - - if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) { - bt_mesh_adv_send(buf, NULL, NULL); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, NULL); - } - } -} - -static void prov_retransmit(struct ble_npl_event *work) -{ - int32_t timeout_ms; - int i; - - BT_DBG(""); - - if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { - BT_WARN("Link not active"); - return; - } - - /* - * According to mesh profile spec (5.3.1.4.3), the close message should - * be restransmitted at least three times. Retransmit the link_close - * message until CLOSING_TIMEOUT has elapsed. - */ - if (atomic_test_bit(link.flags, ADV_LINK_CLOSING)) { - timeout_ms = CLOSING_TIMEOUT; - } else { - timeout_ms = TRANSACTION_TIMEOUT; - } - - if (k_uptime_get() - link.tx.start > timeout_ms) { - if (atomic_test_bit(link.flags, ADV_LINK_CLOSING)) { - close_link(PROV_BEARER_LINK_STATUS_SUCCESS); - } else { - BT_WARN("Giving up transaction"); - close_link(PROV_BEARER_LINK_STATUS_TIMEOUT); - } - - return; - } - - for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { - struct os_mbuf *buf = link.tx.buf[i]; - - if (!buf) { - break; - } - - if (BT_MESH_ADV(buf)->busy) { - continue; - } - - BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - - if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) { - bt_mesh_adv_send(buf, NULL, NULL); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, NULL); - } - } -} - -static int bearer_ctl_send(uint8_t op, const void *data, uint8_t data_len, - bool reliable) -{ - struct os_mbuf *buf; - - BT_DBG("op 0x%02x data_len %u", op, data_len); - - prov_clear_tx(); - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); - - buf = adv_buf_create(reliable ? RETRANSMITS_RELIABLE : - RETRANSMITS_UNRELIABLE); - if (!buf) { - return -ENOBUFS; - } - - net_buf_add_be32(buf, link.id); - /* Transaction ID, always 0 for Bearer messages */ - net_buf_add_u8(buf, 0x00); - net_buf_add_u8(buf, GPC_CTL(op)); - net_buf_add_mem(buf, data, data_len); - - if (reliable) { - link.tx.buf[0] = buf; - send_reliable(); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, NULL); - net_buf_unref(buf); - } - - return 0; -} - -static int prov_send_adv(struct os_mbuf *msg, - prov_bearer_send_complete_t cb, void *cb_data) -{ - struct os_mbuf *start, *buf; - uint8_t seg_len, seg_id; - - prov_clear_tx(); - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); - - start = adv_buf_create(RETRANSMITS_RELIABLE); - if (!start) { - return -ENOBUFS; - } - - link.tx.id = next_transaction_id(link.tx.id); - net_buf_add_be32(start, link.id); - net_buf_add_u8(start, link.tx.id); - - net_buf_add_u8(start, GPC_START(last_seg(msg->om_len))); - net_buf_add_be16(start, msg->om_len); - net_buf_add_u8(start, bt_mesh_fcs_calc(msg->om_data, msg->om_len)); - - link.tx.buf[0] = start; - link.tx.cb = cb; - link.tx.cb_data = cb_data; - - BT_DBG("xact_id: 0x%x len: %u", link.tx.id, msg->om_len); - - seg_len = MIN(msg->om_len, START_PAYLOAD_MAX); - BT_DBG("seg 0 len %u: %s", seg_len, bt_hex(msg->om_data, seg_len)); - net_buf_add_mem(start, msg->om_data, seg_len); - net_buf_simple_pull_mem(msg, seg_len); - - buf = start; - for (seg_id = 1U; msg->om_len > 0; seg_id++) { - if (seg_id >= ARRAY_SIZE(link.tx.buf)) { - BT_ERR("Too big message"); - free_segments(); - return -E2BIG; - } - - buf = adv_buf_create(RETRANSMITS_RELIABLE); - if (!buf) { - free_segments(); - return -ENOBUFS; - } - - link.tx.buf[seg_id] = buf; - - seg_len = MIN(msg->om_len, CONT_PAYLOAD_MAX); - - BT_DBG("seg %u len %u: %s", seg_id, seg_len, - bt_hex(msg->om_data, seg_len)); - - net_buf_add_be32(buf, link.id); - net_buf_add_u8(buf, link.tx.id); - net_buf_add_u8(buf, GPC_CONT(seg_id)); - net_buf_add_mem(buf, msg->om_data, seg_len); - net_buf_simple_pull_mem(msg, seg_len); - } - - send_reliable(); - - return 0; -} - -/******************************************************************************* - * Link management rx - ******************************************************************************/ - -static void link_open(struct prov_rx *rx, struct os_mbuf *buf) -{ - BT_DBG("len %u", buf->om_len); - - if (buf->om_len < 16) { - BT_ERR("Too short bearer open message (len %u)", buf->om_len); - return; - } - - if (atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { - /* Send another link ack if the provisioner missed the last */ - if (link.id == rx->link_id) { - BT_DBG("Resending link ack"); - bearer_ctl_send(LINK_ACK, NULL, 0, false); - } else { - BT_DBG("Ignoring bearer open: link already active"); - } - - return; - } - - if (memcmp(buf->om_data, bt_mesh_prov_get()->uuid, 16)) { - BT_DBG("Bearer open message not for us"); - return; - } - - link.id = rx->link_id; - atomic_set_bit(link.flags, ADV_LINK_ACTIVE); - net_buf_simple_reset(link.rx.buf); - - bearer_ctl_send(LINK_ACK, NULL, 0, false); - - link.cb->link_opened(&pb_adv, link.cb_data); -} - -static void link_ack(struct prov_rx *rx, struct os_mbuf *buf) -{ - BT_DBG("len %u", buf->om_len); - - if (atomic_test_bit(link.flags, ADV_PROVISIONER)) { - if (atomic_test_and_set_bit(link.flags, ADV_LINK_ACK_RECVD)) { - return; - } - - prov_clear_tx(); - - link.cb->link_opened(&pb_adv, link.cb_data); - } -} - -static void link_close(struct prov_rx *rx, struct os_mbuf *buf) -{ - BT_DBG("len %u", buf->om_len); - - if (buf->om_len != 1) { - return; - } - - close_link(net_buf_simple_pull_u8(buf)); -} - -/******************************************************************************* - * Higher level functionality - ******************************************************************************/ - -void bt_mesh_pb_adv_recv(struct os_mbuf *buf) -{ - struct prov_rx rx; - - if (!link.cb) { - return; - } - - if (buf->om_len < 6) { - BT_WARN("Too short provisioning packet (len %u)", buf->om_len); - return; - } - - rx.link_id = net_buf_simple_pull_be32(buf); - rx.xact_id = net_buf_simple_pull_u8(buf); - rx.gpc = net_buf_simple_pull_u8(buf); - - if (atomic_test_bit(link.flags, ADV_LINK_ACTIVE) && link.id != rx.link_id) { - return; - } - - BT_DBG("link_id 0x%08x xact_id 0x%x", rx.link_id, rx.xact_id); - - gen_prov_recv(&rx, buf); -} - -static int prov_link_open(const uint8_t uuid[16], int32_t timeout, - const struct prov_bearer_cb *cb, void *cb_data) -{ - BT_DBG("uuid %s", bt_hex(uuid, 16)); - - if (atomic_test_and_set_bit(link.flags, ADV_LINK_ACTIVE)) { - return -EBUSY; - } - - atomic_set_bit(link.flags, ADV_PROVISIONER); - - bt_rand(&link.id, sizeof(link.id)); - link.tx.id = XACT_ID_MAX; - link.rx.id = XACT_ID_NVAL; - link.cb = cb; - link.cb_data = cb_data; - - net_buf_simple_reset(link.rx.buf); - - bearer_ctl_send(LINK_OPEN, uuid, 16, true); - - return 0; -} - -static int prov_link_accept(const struct prov_bearer_cb *cb, void *cb_data) -{ - if (atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { - return -EBUSY; - } - - link.rx.id = XACT_ID_MAX; - link.tx.id = XACT_ID_NVAL; - link.cb = cb; - link.cb_data = cb_data; - - /* Make sure we're scanning for provisioning inviations */ - bt_mesh_scan_enable(); - /* Enable unprovisioned beacon sending */ - bt_mesh_beacon_enable(); - - return 0; -} - -static void prov_link_close(enum prov_bearer_link_status status) -{ - if (atomic_test_and_set_bit(link.flags, ADV_LINK_CLOSING)) { - return; - } - - bearer_ctl_send(LINK_CLOSE, &status, 1, true); -} - -void pb_adv_init(void) -{ - k_delayed_work_init(&link.prot_timer, protocol_timeout); - k_delayed_work_init(&link.tx.retransmit, prov_retransmit); - - if (!rx_buf) { - rx_buf = NET_BUF_SIMPLE(65); - } - link.rx.buf = rx_buf; - net_buf_simple_reset(link.rx.buf); -} - -void pb_adv_reset(void) -{ - reset_adv_link(); -} - -const struct prov_bearer pb_adv = { - .type = BT_MESH_PROV_ADV, - .link_open = prov_link_open, - .link_accept = prov_link_accept, - .link_close = prov_link_close, - .send = prov_send_adv, - .clear_tx = prov_clear_tx, -}; - -#endif /* MYNEWT_VAL(BLE_MESH) */ \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/pb_gatt.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/pb_gatt.c deleted file mode 100644 index 2b28c91f4..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/pb_gatt.c +++ /dev/null @@ -1,163 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ -#define MESH_LOG_MODULE BLE_MESH_PROV_LOG - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#include "../include/mesh/mesh.h" -#include "prov.h" -#include "net.h" -#include "proxy.h" -#include "adv.h" -#include "prov.h" - -struct prov_link { - uint16_t conn_handle; - const struct prov_bearer_cb *cb; - void *cb_data; - struct { - uint8_t id; /* Transaction ID */ - uint8_t prev_id; /* Previous Transaction ID */ - uint8_t seg; /* Bit-field of unreceived segments */ - uint8_t last_seg; /* Last segment (to check length) */ - uint8_t fcs; /* Expected FCS value */ - struct os_mbuf *buf; - } rx; - struct k_delayed_work prot_timer; -}; - -static struct prov_link link; - -static void reset_state(void) -{ - link.conn_handle = BLE_HS_CONN_HANDLE_NONE; - - k_delayed_work_cancel(&link.prot_timer); - - link.rx.buf = bt_mesh_proxy_get_buf(); -} - -static void link_closed(enum prov_bearer_link_status status) -{ - const struct prov_bearer_cb *cb = link.cb; - - void *cb_data = link.cb_data; - - reset_state(); - - cb->link_closed(&pb_gatt, cb_data, status); -} - -static void protocol_timeout(struct ble_npl_event *work) -{ - BT_DBG("Protocol timeout"); - - link_closed(PROV_BEARER_LINK_STATUS_TIMEOUT); -} - -int bt_mesh_pb_gatt_recv(uint16_t conn_handle, struct os_mbuf *buf) -{ - BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - - if (link.conn_handle != conn_handle || !link.cb) { - BT_WARN("Data for unexpected connection"); - return -ENOTCONN; - } - - if (buf->om_len < 1) { - BT_WARN("Too short provisioning packet (len %u)", buf->om_len); - return -EINVAL; - } - - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); - - link.cb->recv(&pb_gatt, link.cb_data, buf); - - return 0; -} - -int bt_mesh_pb_gatt_open(uint16_t conn_handle) -{ - BT_DBG("conn %p", conn_handle); - - if (link.conn_handle) { - return -EBUSY; - } - - link.conn_handle = conn_handle; - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); - - link.cb->link_opened(&pb_gatt, link.cb_data); - - return 0; -} - -int bt_mesh_pb_gatt_close(uint16_t conn_handle) -{ - BT_DBG("conn %p", conn_handle); - - if (link.conn_handle != conn_handle) { - BT_DBG("Not connected"); - return -ENOTCONN; - } - - link.cb->link_closed(&pb_gatt, link.cb_data, - PROV_BEARER_LINK_STATUS_SUCCESS); - - reset_state(); - - return 0; -} - -static int link_accept(const struct prov_bearer_cb *cb, void *cb_data) -{ - bt_mesh_proxy_prov_enable(); - bt_mesh_adv_update(); - - link.cb = cb; - link.cb_data = cb_data; - - return 0; -} - -static int buf_send(struct os_mbuf *buf, prov_bearer_send_complete_t cb, - void *cb_data) -{ - if (!link.conn_handle) { - return -ENOTCONN; - } - - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); - - return bt_mesh_proxy_send(link.conn_handle, BT_MESH_PROXY_PROV, buf); -} - -static void clear_tx(void) -{ - /* No action */ -} - -void pb_gatt_init(void) -{ - k_delayed_work_init(&link.prot_timer, protocol_timeout); -} - -void pb_gatt_reset(void) -{ - reset_state(); -} -const struct prov_bearer pb_gatt = { - .type = BT_MESH_PROV_GATT, - .link_accept = link_accept, - .send = buf_send, - .clear_tx = clear_tx, -}; - -#endif /* MYNEWT_VAL(BLE_MESH) */ \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/prov.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/prov.c deleted file mode 100644 index 25e34ed75..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/prov.c +++ /dev/null @@ -1,379 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_PROV_LOG - -#include - -#include "../include/mesh/mesh.h" -#include "mesh_priv.h" - -#include "crypto.h" -#include "atomic.h" -#include "net.h" -#include "access.h" -#include "foundation.h" -#include "prov.h" - -struct bt_mesh_prov_link bt_mesh_prov_link; -const struct bt_mesh_prov *bt_mesh_prov; - -static void pub_key_ready(const uint8_t *pkey) -{ - if (!pkey) { - BT_WARN("Public key not available"); - return; - } - BT_DBG("Local public key ready"); -} - -int bt_mesh_prov_reset_state(void (*func)(const uint8_t key[64])) -{ - BT_DBG("bt_mesh_prov_reset_state"); - - int err; - static struct bt_pub_key_cb pub_key_cb; - const size_t offset = offsetof(struct bt_mesh_prov_link, dhkey); - - pub_key_cb.func = func ? func : pub_key_ready; - - /* Disable Attention Timer if it was set */ - if (bt_mesh_prov_link.conf_inputs[0]) { - bt_mesh_attention(NULL, 0); - } - - atomic_clear(bt_mesh_prov_link.flags); - (void)memset((uint8_t *)&bt_mesh_prov_link + offset, 0, - sizeof(bt_mesh_prov_link) - offset); - - err = bt_pub_key_gen(&pub_key_cb); - if (err) { - BT_ERR("Failed to generate public key (%d)", err); - return err; - } - return 0; -} - -static bt_mesh_output_action_t output_action(uint8_t action) -{ - switch (action) { - case OUTPUT_OOB_BLINK: - return BT_MESH_BLINK; - case OUTPUT_OOB_BEEP: - return BT_MESH_BEEP; - case OUTPUT_OOB_VIBRATE: - return BT_MESH_VIBRATE; - case OUTPUT_OOB_NUMBER: - return BT_MESH_DISPLAY_NUMBER; - case OUTPUT_OOB_STRING: - return BT_MESH_DISPLAY_STRING; - default: - return BT_MESH_NO_OUTPUT; - } -} - -static bt_mesh_input_action_t input_action(uint8_t action) -{ - switch (action) { - case INPUT_OOB_PUSH: - return BT_MESH_PUSH; - case INPUT_OOB_TWIST: - return BT_MESH_TWIST; - case INPUT_OOB_NUMBER: - return BT_MESH_ENTER_NUMBER; - case INPUT_OOB_STRING: - return BT_MESH_ENTER_STRING; - default: - return BT_MESH_NO_INPUT; - } -} - -int bt_mesh_prov_auth(uint8_t method, uint8_t action, uint8_t size) -{ - bt_mesh_output_action_t output; - bt_mesh_input_action_t input; - - switch (method) { - case AUTH_METHOD_NO_OOB: - if (action || size) { - return -EINVAL; - } - - (void)memset(bt_mesh_prov_link.auth, 0, sizeof(bt_mesh_prov_link.auth)); - return 0; - case AUTH_METHOD_STATIC: - if (action || size) { - return -EINVAL; - } - - atomic_set_bit(bt_mesh_prov_link.flags, OOB_STATIC_KEY); - - return 0; - - case AUTH_METHOD_OUTPUT: - output = output_action(action); - if (!output) { - return -EINVAL; - } - - if (!(bt_mesh_prov->output_actions & output)) { - return -EINVAL; - } - - if (size > bt_mesh_prov->output_size) { - return -EINVAL; - } - - atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); - - if (output == BT_MESH_DISPLAY_STRING) { - unsigned char str[9]; - uint8_t i; - - bt_rand(str, size); - - /* Normalize to '0' .. '9' & 'A' .. 'Z' */ - for (i = 0; i < size; i++) { - str[i] %= 36; - if (str[i] < 10) { - str[i] += '0'; - } else { - str[i] += 'A' - 10; - } - } - str[size] = '\0'; - - memcpy(bt_mesh_prov_link.auth, str, size); - memset(bt_mesh_prov_link.auth + size, 0, - sizeof(bt_mesh_prov_link.auth) - size); - - return bt_mesh_prov->output_string((char *)str); - } else { - uint32_t div[8] = { 10, 100, 1000, 10000, 100000, - 1000000, 10000000, 100000000 }; - uint32_t num; - - bt_rand(&num, sizeof(num)); - num %= div[size - 1]; - - sys_put_be32(num, &bt_mesh_prov_link.auth[12]); - memset(bt_mesh_prov_link.auth, 0, 12); - - return bt_mesh_prov->output_number(output, num); - } - - case AUTH_METHOD_INPUT: - input = input_action(action); - if (!input) { - return -EINVAL; - } - - if (!(bt_mesh_prov->input_actions & input)) { - return -EINVAL; - } - - if (size > bt_mesh_prov->input_size) { - return -EINVAL; - } - - if (input == BT_MESH_ENTER_STRING) { - atomic_set_bit(bt_mesh_prov_link.flags, WAIT_STRING); - } else { - atomic_set_bit(bt_mesh_prov_link.flags, WAIT_NUMBER); - } - - return bt_mesh_prov->input(input, size); - - default: - return -EINVAL; - } -} - -int bt_mesh_input_number(uint32_t num) -{ - BT_DBG("%u", (unsigned) num); - - if (!atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_NUMBER)) { - return -EINVAL; - } - - sys_put_be32(num, &bt_mesh_prov_link.auth[12]); - - bt_mesh_prov_link.role->input_complete(); - - return 0; -} - -int bt_mesh_input_string(const char *str) -{ - BT_DBG("%s", str); - - if (!atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_STRING)) { - return -EINVAL; - } - - strncpy((char *)bt_mesh_prov_link.auth, str, bt_mesh_prov->input_size); - - bt_mesh_prov_link.role->input_complete(); - - return 0; -} - -const struct bt_mesh_prov *bt_mesh_prov_get(void) -{ - return bt_mesh_prov; -} - -bool bt_mesh_prov_active(void) -{ - return atomic_test_bit(bt_mesh_prov_link.flags, LINK_ACTIVE); -} - -static void prov_recv(const struct prov_bearer *bearer, void *cb_data, - struct os_mbuf *buf) -{ - static const uint8_t op_len[10] = { - [PROV_INVITE] = 1, - [PROV_CAPABILITIES] = 11, - [PROV_START] = 5, - [PROV_PUB_KEY] = 64, - [PROV_INPUT_COMPLETE] = 0, - [PROV_CONFIRM] = 16, - [PROV_RANDOM] = 16, - [PROV_DATA] = 33, - [PROV_COMPLETE] = 0, - [PROV_FAILED] = 1, - }; - - uint8_t type = buf->om_data[0]; - BT_DBG("type 0x%02x len %u", type, buf->om_len); - - if (type >= ARRAY_SIZE(bt_mesh_prov_link.role->op)) { - BT_ERR("Unknown provisioning PDU type 0x%02x", type); - bt_mesh_prov_link.role->error(PROV_ERR_NVAL_FMT); - return; - } - - if ((type != PROV_FAILED && type != bt_mesh_prov_link.expect) || - !bt_mesh_prov_link.role->op[type]) { - BT_WARN("Unexpected msg 0x%02x != 0x%02x", type, bt_mesh_prov_link.expect); - bt_mesh_prov_link.role->error(PROV_ERR_UNEXP_PDU); - return; - } - - if (1 + op_len[type] != buf->om_len) { - BT_ERR("Invalid length %u for type 0x%02x", buf->om_len, type); - bt_mesh_prov_link.role->error(PROV_ERR_NVAL_FMT); - return; - } - - bt_mesh_prov_link.role->op[type](&buf->om_data[1]); -} - -static void prov_link_opened(const struct prov_bearer *bearer, void *cb_data) -{ - atomic_set_bit(bt_mesh_prov_link.flags, LINK_ACTIVE); - - BT_ERR("bt_mesh_prov->link_open"); - if (bt_mesh_prov->link_open) { - bt_mesh_prov->link_open(bearer->type); - } - - BT_ERR("bt_mesh_prov_link.bearer"); - bt_mesh_prov_link.bearer = bearer; - - BT_ERR("bt_mesh_prov_link.role->link_opened"); - BT_ERR("%p", bt_mesh_prov_link.role); - BT_ERR("%p", bt_mesh_prov_link.role->link_opened); - if (bt_mesh_prov_link.role->link_opened) { - bt_mesh_prov_link.role->link_opened(); - } - BT_ERR("done"); -} - -static void prov_link_closed(const struct prov_bearer *bearer, void *cb_data, - enum prov_bearer_link_status reason) -{ - if (bt_mesh_prov_link.role->link_closed) { - bt_mesh_prov_link.role->link_closed(); - } - - if (bt_mesh_prov->link_close) { - bt_mesh_prov->link_close(bearer->type); - } -} - -static void prov_bearer_error(const struct prov_bearer *bearer, void *cb_data, - uint8_t err) -{ - if (bt_mesh_prov_link.role->error) { - bt_mesh_prov_link.role->error(err); - } -} - -static const struct prov_bearer_cb prov_bearer_cb = { - .link_opened = prov_link_opened, - .link_closed = prov_link_closed, - .error = prov_bearer_error, - .recv = prov_recv, -}; - -const struct prov_bearer_cb *bt_mesh_prov_bearer_cb_get(void) -{ - return &prov_bearer_cb; -} - -void bt_mesh_prov_complete(uint16_t net_idx, uint16_t addr) -{ - if (bt_mesh_prov->complete) { - bt_mesh_prov->complete(net_idx, addr); - } -} - -void bt_mesh_prov_reset(void) -{ - BT_DBG("bt_mesh_prov_reset"); - - if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV)) { - pb_adv_reset(); - } - - if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { - pb_gatt_reset(); - } - - bt_mesh_prov_reset_state(NULL); - - if (bt_mesh_prov->reset) { - bt_mesh_prov->reset(); - } -} - -int bt_mesh_prov_init(const struct bt_mesh_prov *prov_info) -{ - if (!prov_info) { - BT_ERR("No provisioning context provided"); - return -EINVAL; - } - - bt_mesh_prov = prov_info; - - if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV)) { - pb_adv_init(); - } - if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { - pb_gatt_init(); - } - - return bt_mesh_prov_reset_state(NULL); -} - -#endif /* MYNEWT_VAL(BLE_MESH) */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/prov.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/prov.h deleted file mode 100644 index d68376000..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/prov.h +++ /dev/null @@ -1,154 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __PROV_H__ -#define __PROV_H__ - -#include "prov_bearer.h" -#include "nimble/porting/nimble/include/os/os_mbuf.h" -#include "../include/mesh/mesh.h" -#include "nimble/nimble/host/src/ble_hs_conn_priv.h" - -#define PROV_ERR_NONE 0x00 -#define PROV_ERR_NVAL_PDU 0x01 -#define PROV_ERR_NVAL_FMT 0x02 -#define PROV_ERR_UNEXP_PDU 0x03 -#define PROV_ERR_CFM_FAILED 0x04 -#define PROV_ERR_RESOURCES 0x05 -#define PROV_ERR_DECRYPT 0x06 -#define PROV_ERR_UNEXP_ERR 0x07 -#define PROV_ERR_ADDR 0x08 - -#define AUTH_METHOD_NO_OOB 0x00 -#define AUTH_METHOD_STATIC 0x01 -#define AUTH_METHOD_OUTPUT 0x02 -#define AUTH_METHOD_INPUT 0x03 - -#define OUTPUT_OOB_BLINK 0x00 -#define OUTPUT_OOB_BEEP 0x01 -#define OUTPUT_OOB_VIBRATE 0x02 -#define OUTPUT_OOB_NUMBER 0x03 -#define OUTPUT_OOB_STRING 0x04 - -#define INPUT_OOB_PUSH 0x00 -#define INPUT_OOB_TWIST 0x01 -#define INPUT_OOB_NUMBER 0x02 -#define INPUT_OOB_STRING 0x03 - -#define PUB_KEY_NO_OOB 0x00 -#define PUB_KEY_OOB 0x01 - -#define PROV_INVITE 0x00 -#define PROV_CAPABILITIES 0x01 -#define PROV_START 0x02 -#define PROV_PUB_KEY 0x03 -#define PROV_INPUT_COMPLETE 0x04 -#define PROV_CONFIRM 0x05 -#define PROV_RANDOM 0x06 -#define PROV_DATA 0x07 -#define PROV_COMPLETE 0x08 -#define PROV_FAILED 0x09 - -#define PROV_NO_PDU 0xff - -#define PROV_ALG_P256 0x00 - -#define PROV_BUF(len) \ - NET_BUF_SIMPLE(PROV_BEARER_BUF_HEADROOM + len) - -enum { - WAIT_PUB_KEY, /* Waiting for local PubKey to be generated */ - LINK_ACTIVE, /* Link has been opened */ - WAIT_NUMBER, /* Waiting for number input from user */ - WAIT_STRING, /* Waiting for string input from user */ - NOTIFY_INPUT_COMPLETE, /* Notify that input has been completed. */ - PROVISIONER, /* The link was opened as provisioner */ - OOB_PUB_KEY, /* OOB Public key used */ - PUB_KEY_SENT, /* Public key has been sent */ - REMOTE_PUB_KEY, /* Remote key has been received */ - INPUT_COMPLETE, /* Device input completed */ - WAIT_CONFIRM, /* Wait for send confirm */ - WAIT_AUTH, /* Wait for auth response */ - OOB_STATIC_KEY, /* OOB Static Authentication */ - - NUM_FLAGS, -}; - -/** Provisioning role */ -struct bt_mesh_prov_role { - void (*link_opened)(void); - - void (*link_closed)(void); - - void (*error)(uint8_t reason); - - void (*input_complete)(void); - - void (*op[10])(const uint8_t *data); -}; - -struct bt_mesh_prov_link { - ATOMIC_DEFINE(flags, NUM_FLAGS); - - const struct prov_bearer *bearer; - const struct bt_mesh_prov_role *role; - - uint8_t oob_method; /* Authen method */ - uint8_t oob_action; /* Authen action */ - uint8_t oob_size; /* Authen size */ - uint8_t auth[16]; /* Authen value */ - - uint8_t dhkey[32]; /* Calculated DHKey */ - uint8_t expect; /* Next expected PDU */ - uint8_t conf[16]; /* Remote Confirmation */ - uint8_t rand[16]; /* Local Random */ - - uint8_t conf_salt[16]; /* ConfirmationSalt */ - uint8_t conf_key[16]; /* ConfirmationKey */ - uint8_t conf_inputs[145]; /* ConfirmationInputs */ - uint8_t prov_salt[16]; /* Provisioning Salt */ -}; - -extern struct bt_mesh_prov_link bt_mesh_prov_link; -extern const struct bt_mesh_prov *bt_mesh_prov; - -static inline int bt_mesh_prov_send(struct os_mbuf *buf, - prov_bearer_send_complete_t cb) -{ - return bt_mesh_prov_link.bearer->send(buf, cb, NULL); -} - -static inline void bt_mesh_prov_buf_init(struct os_mbuf *buf, uint8_t type) -{ - net_buf_reserve(buf, PROV_BEARER_BUF_HEADROOM); - net_buf_simple_add_u8(buf, type); -} - -int bt_mesh_prov_reset_state(void (*func)(const uint8_t key[64])); - -bool bt_mesh_prov_active(void); - -int bt_mesh_prov_auth(uint8_t method, uint8_t action, uint8_t size); - -int bt_mesh_pb_gatt_open(uint16_t conn_handle); -int bt_mesh_pb_gatt_close(uint16_t conn_handle); -int bt_mesh_pb_gatt_recv(uint16_t conn_handle, struct os_mbuf *buf); - -const struct bt_mesh_prov *bt_mesh_prov_get(void); - -void bt_mesh_prov_reset_link(void); - -void bt_mesh_prov_complete(uint16_t net_idx, uint16_t addr); -void bt_mesh_prov_reset(void); - -const struct prov_bearer_cb *bt_mesh_prov_bearer_cb_get(void); - -void bt_mesh_pb_adv_recv(struct os_mbuf *buf); - -int bt_mesh_prov_init(const struct bt_mesh_prov *prov); -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/prov_bearer.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/prov_bearer.h deleted file mode 100644 index 3e5268314..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/prov_bearer.h +++ /dev/null @@ -1,116 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define PROTOCOL_TIMEOUT K_SECONDS(60) - -/** @def PROV_BEARER_BUF_HEADROOM - * - * @brief Required headroom for the bearer packet buffers. - */ -#if MYNEWT_VAL(BLE_MESH_PB_GATT) -#define PROV_BEARER_BUF_HEADROOM 5 -#else -#define PROV_BEARER_BUF_HEADROOM 0 -#endif - -enum prov_bearer_link_status { - PROV_BEARER_LINK_STATUS_SUCCESS, - PROV_BEARER_LINK_STATUS_TIMEOUT, - PROV_BEARER_LINK_STATUS_FAIL, -}; - -struct prov_bearer; - -/** Callbacks from bearer to host */ -struct prov_bearer_cb { - - void (*link_opened)(const struct prov_bearer *bearer, void *cb_data); - - void (*link_closed)(const struct prov_bearer *bearer, void *cb_data, - enum prov_bearer_link_status reason); - - void (*error)(const struct prov_bearer *bearer, void *cb_data, - uint8_t err); - - void (*recv)(const struct prov_bearer *bearer, void *cb_data, - struct os_mbuf *buf); -}; - -typedef void (*prov_bearer_send_complete_t)(int err, void *cb_data); - -/** Provisioning bearer API */ -struct prov_bearer { - /** Provisioning bearer type. */ - bt_mesh_prov_bearer_t type; - - /** @brief Enable link establishment as a provisionee. - * - * Prompts the bearer to make itself visible to provisioners, and - * start accepting link open messages. - * - * @param cb Bearer event callbacks used for the duration of the link. - * @param cb_data Context parameter to pass to the bearer callbacks. - * - * @return Zero on success, or (negative) error code otherwise. - */ - int (*link_accept)(const struct prov_bearer_cb *cb, void *cb_data); - - /** @brief Send a packet on an established link. - * - * @param buf Payload buffer. Requires @ref - * PROV_BEARER_BUF_HEADROOM bytes of headroom. - * @param cb Callback to call when sending is complete. - * @param cb_data Callback data. - * - * @return Zero on success, or (negative) error code otherwise. - */ - int (*send)(struct os_mbuf *buf, prov_bearer_send_complete_t cb, - void *cb_data); - - /** @brief Clear any ongoing transmissions, if possible. - * - * Bearers that don't support tx clearing must implement this callback - * and leave it empty. - */ - void (*clear_tx)(void); - - /* Only available in provisioners: */ - - /** @brief Open a new link as a provisioner. - * - * Only available in provisioners. Bearers that don't support the - * provisioner role should leave this as NULL. - * - * @param uuid UUID of the node to establish a link to. - * @param timeout Protocol timeout. - * @param cb Bearer event callbacks used for the duration of the link. - * @param cb_data Context parameter to pass to the bearer callbacks. - * - * @return Zero on success, or (negative) error code otherwise. - */ - int (*link_open)(const uint8_t uuid[16], int32_t timeout, - const struct prov_bearer_cb *cb, void *cb_data); - - /** @brief Close the current link. - * - * Only available in provisioners. Bearers that don't support the - * provisioner role should leave this as NULL. - * - * @param status Link status for the link close message. - */ - void (*link_close)(enum prov_bearer_link_status status); -}; - -extern const struct prov_bearer pb_adv; -extern const struct prov_bearer pb_gatt; - -void pb_adv_init(void); -void pb_gatt_init(void); - -void pb_adv_reset(void); -void pb_gatt_reset(void); diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/prov_device.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/prov_device.c deleted file mode 100644 index 95d01c415..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/prov_device.c +++ /dev/null @@ -1,573 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * Copyright (c) 2020 Lingao Meng - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define MESH_LOG_MODULE BLE_MESH_PROV_LOG - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#include "crypto.h" -#include "adv.h" -#include "../include/mesh/mesh.h" -#include "net.h" -#include "rpl.h" -#include "beacon.h" -#include "access.h" -#include "foundation.h" -#include "proxy.h" -#include "prov.h" -#include "settings.h" - -static void send_pub_key(void); -static void pub_key_ready(const uint8_t *pkey); - -static int reset_state(void) -{ - return bt_mesh_prov_reset_state(pub_key_ready); -} - -static void prov_send_fail_msg(uint8_t err) -{ - struct os_mbuf *buf = PROV_BUF(2); - - BT_DBG("%u", err); - - bt_mesh_prov_link.expect = PROV_NO_PDU; - - bt_mesh_prov_buf_init(buf, PROV_FAILED); - net_buf_simple_add_u8(buf, err); - - if (bt_mesh_prov_send(buf, NULL)) { - BT_ERR("Failed to send Provisioning Failed message"); - } -} - -static void prov_fail(uint8_t reason) -{ - /* According to Bluetooth Mesh Specification v1.0.1, Section 5.4.4, the - * provisioner just closes the link when something fails, while the - * provisionee sends the fail message, and waits for the provisioner to - * close the link. - */ - prov_send_fail_msg(reason); -} - -static void prov_invite(const uint8_t *data) -{ - struct os_mbuf *buf = PROV_BUF(12); - - BT_DBG("Attention Duration: %u seconds", data[0]); - - if (data[0]) { - bt_mesh_attention(NULL, data[0]); - } - - bt_mesh_prov_link.conf_inputs[0] = data[0]; - - bt_mesh_prov_buf_init(buf, PROV_CAPABILITIES); - - /* Number of Elements supported */ - net_buf_simple_add_u8(buf, bt_mesh_elem_count()); - - /* Supported algorithms - FIPS P-256 Eliptic Curve */ - net_buf_simple_add_be16(buf, BIT(PROV_ALG_P256)); - - /* Public Key Type, Only "No OOB" Public Key is supported */ - net_buf_simple_add_u8(buf, PUB_KEY_NO_OOB); - - /* Static OOB Type */ - net_buf_simple_add_u8(buf, bt_mesh_prov->static_val ? BIT(0) : 0x00); - - /* Output OOB Size */ - net_buf_simple_add_u8(buf, bt_mesh_prov->output_size); - - /* Output OOB Action */ - net_buf_simple_add_be16(buf, bt_mesh_prov->output_actions); - - /* Input OOB Size */ - net_buf_simple_add_u8(buf, bt_mesh_prov->input_size); - - /* Input OOB Action */ - net_buf_simple_add_be16(buf, bt_mesh_prov->input_actions); - - memcpy(&bt_mesh_prov_link.conf_inputs[1], &buf->om_data[1], 11); - - if (bt_mesh_prov_send(buf, NULL)) { - BT_ERR("Failed to send capabilities"); - return; - } - - bt_mesh_prov_link.expect = PROV_START; -} - -static void prov_start(const uint8_t *data) -{ - BT_DBG("Algorithm: 0x%02x", data[0]); - BT_DBG("Public Key: 0x%02x", data[1]); - BT_DBG("Auth Method: 0x%02x", data[2]); - BT_DBG("Auth Action: 0x%02x", data[3]); - BT_DBG("Auth Size: 0x%02x", data[4]); - - if (data[0] != PROV_ALG_P256) { - BT_ERR("Unknown algorithm 0x%02x", data[0]); - prov_fail(PROV_ERR_NVAL_FMT); - return; - } - - if (data[1] != PUB_KEY_NO_OOB) { - BT_ERR("Invalid public key type: 0x%02x", data[1]); - prov_fail(PROV_ERR_NVAL_FMT); - return; - } - - memcpy(&bt_mesh_prov_link.conf_inputs[12], data, 5); - - bt_mesh_prov_link.expect = PROV_PUB_KEY; - - if (bt_mesh_prov_auth(data[2], data[3], data[4]) < 0) { - BT_ERR("Invalid authentication method: 0x%02x; " - "action: 0x%02x; size: 0x%02x", data[2], data[3], - data[4]); - prov_fail(PROV_ERR_NVAL_FMT); - } - - if (atomic_test_bit(bt_mesh_prov_link.flags, OOB_STATIC_KEY)) { - memcpy(bt_mesh_prov_link.auth + 16 - bt_mesh_prov->static_val_len, - bt_mesh_prov->static_val, bt_mesh_prov->static_val_len); - (void)memset(bt_mesh_prov_link.auth, 0, - sizeof(bt_mesh_prov_link.auth) - bt_mesh_prov->static_val_len); - } -} - -static void send_confirm(void) -{ - struct os_mbuf *cfm = PROV_BUF(17); - - BT_DBG("ConfInputs[0] %s", bt_hex(bt_mesh_prov_link.conf_inputs, 64)); - BT_DBG("ConfInputs[64] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[64], 64)); - BT_DBG("ConfInputs[128] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[128], 17)); - - if (bt_mesh_prov_conf_salt(bt_mesh_prov_link.conf_inputs, - bt_mesh_prov_link.conf_salt)) { - BT_ERR("Unable to generate confirmation salt"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("ConfirmationSalt: %s", bt_hex(bt_mesh_prov_link.conf_salt, 16)); - - if (bt_mesh_prov_conf_key(bt_mesh_prov_link.dhkey, bt_mesh_prov_link.conf_salt, - bt_mesh_prov_link.conf_key)) { - BT_ERR("Unable to generate confirmation key"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("ConfirmationKey: %s", bt_hex(bt_mesh_prov_link.conf_key, 16)); - - if (bt_rand(bt_mesh_prov_link.rand, 16)) { - BT_ERR("Unable to generate random number"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("LocalRandom: %s", bt_hex(bt_mesh_prov_link.rand, 16)); - - bt_mesh_prov_buf_init(cfm, PROV_CONFIRM); - - if (bt_mesh_prov_conf(bt_mesh_prov_link.conf_key, bt_mesh_prov_link.rand, - bt_mesh_prov_link.auth, net_buf_simple_add(cfm, 16))) { - BT_ERR("Unable to generate confirmation value"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - if (bt_mesh_prov_send(cfm, NULL)) { - BT_ERR("Failed to send Provisioning Confirm"); - return; - } - - bt_mesh_prov_link.expect = PROV_RANDOM; - -} - -static void send_input_complete(void) -{ - struct os_mbuf *buf = PROV_BUF(1); - - bt_mesh_prov_buf_init(buf, PROV_INPUT_COMPLETE); - if (bt_mesh_prov_send(buf, NULL)) { - BT_ERR("Failed to send Provisioning Input Complete"); - } - bt_mesh_prov_link.expect = PROV_CONFIRM; -} - -static void public_key_sent(int err, void *cb_data) -{ - atomic_set_bit(bt_mesh_prov_link.flags, PUB_KEY_SENT); - - if (atomic_test_bit(bt_mesh_prov_link.flags, INPUT_COMPLETE)) { - send_input_complete(); - return; - } -} - -static void send_pub_key(void) -{ - struct os_mbuf *buf = PROV_BUF(65); - const uint8_t *key; - - key = bt_pub_key_get(); - if (!key) { - BT_ERR("No public key available"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("Local Public Key: %s", bt_hex(key, 64)); - - bt_mesh_prov_buf_init(buf, PROV_PUB_KEY); - - /* Swap X and Y halves independently to big-endian */ - sys_memcpy_swap(net_buf_simple_add(buf, 32), key, 32); - sys_memcpy_swap(net_buf_simple_add(buf, 32), &key[32], 32); - - /* PublicKeyRemote */ - memcpy(&bt_mesh_prov_link.conf_inputs[81], &buf->om_data[1], 64); - - if (bt_mesh_prov_send(buf, public_key_sent)) { - BT_ERR("Failed to send Public Key"); - return; - } - - if (atomic_test_bit(bt_mesh_prov_link.flags, WAIT_NUMBER) || - atomic_test_bit(bt_mesh_prov_link.flags, WAIT_STRING)) { - bt_mesh_prov_link.expect = PROV_NO_PDU; /* Wait for input */ - } else { - bt_mesh_prov_link.expect = PROV_CONFIRM; - } -} - -static void prov_dh_key_cb(const uint8_t dhkey[32]) -{ - BT_DBG("%p", dhkey); - - if (!dhkey) { - BT_ERR("DHKey generation failed"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - sys_memcpy_swap(bt_mesh_prov_link.dhkey, dhkey, 32); - - BT_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, 32)); - - send_pub_key(); -} - -static void prov_dh_key_gen(void) -{ - uint8_t remote_pk_le[64], *remote_pk; - - remote_pk = &bt_mesh_prov_link.conf_inputs[17]; - - /* Copy remote key in little-endian for bt_dh_key_gen(). - * X and Y halves are swapped independently. The bt_dh_key_gen() - * will also take care of validating the remote public key. - */ - sys_memcpy_swap(remote_pk_le, remote_pk, 32); - sys_memcpy_swap(&remote_pk_le[32], &remote_pk[32], 32); - - if (bt_dh_key_gen(remote_pk_le, prov_dh_key_cb)) { - BT_ERR("Failed to generate DHKey"); - prov_fail(PROV_ERR_UNEXP_ERR); - } -} - -static void prov_pub_key(const uint8_t *data) -{ - BT_DBG("Remote Public Key: %s", bt_hex(data, 64)); - - /* PublicKeyProvisioner */ - memcpy(&bt_mesh_prov_link.conf_inputs[17], data, 64); - - if (!bt_pub_key_get()) { - /* Clear retransmit timer */ - bt_mesh_prov_link.bearer->clear_tx(); - atomic_set_bit(bt_mesh_prov_link.flags, WAIT_PUB_KEY); - BT_WARN("Waiting for local public key"); - return; - } - - prov_dh_key_gen(); -} - -static void pub_key_ready(const uint8_t *pkey) -{ - if (!pkey) { - BT_WARN("Public key not available"); - return; - } - - BT_DBG("Local public key ready"); - - if (atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_PUB_KEY)) { - prov_dh_key_gen(); - } -} - -static void notify_input_complete(void) -{ - if (atomic_test_and_clear_bit(bt_mesh_prov_link.flags, - NOTIFY_INPUT_COMPLETE) && - bt_mesh_prov->input_complete) { - bt_mesh_prov->input_complete(); - } -} - -static void send_random(void) -{ - struct os_mbuf *rnd = PROV_BUF(17); - - bt_mesh_prov_buf_init(rnd, PROV_RANDOM); - net_buf_simple_add_mem(rnd, bt_mesh_prov_link.rand, 16); - - if (bt_mesh_prov_send(rnd, NULL)) { - BT_ERR("Failed to send Provisioning Random"); - return; - } - - bt_mesh_prov_link.expect = PROV_DATA; -} - -static void prov_random(const uint8_t *data) -{ - uint8_t conf_verify[16]; - - BT_DBG("Remote Random: %s", bt_hex(data, 16)); - if (!memcmp(data, bt_mesh_prov_link.rand, 16)) { - BT_ERR("Random value is identical to ours, rejecting."); - prov_fail(PROV_ERR_CFM_FAILED); - return; - } - - if (bt_mesh_prov_conf(bt_mesh_prov_link.conf_key, data, - bt_mesh_prov_link.auth, conf_verify)) { - BT_ERR("Unable to calculate confirmation verification"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - if (memcmp(conf_verify, bt_mesh_prov_link.conf, 16)) { - BT_ERR("Invalid confirmation value"); - BT_DBG("Received: %s", bt_hex(bt_mesh_prov_link.conf, 16)); - BT_DBG("Calculated: %s", bt_hex(conf_verify, 16)); - prov_fail(PROV_ERR_CFM_FAILED); - return; - } - - if (bt_mesh_prov_salt(bt_mesh_prov_link.conf_salt, data, - bt_mesh_prov_link.rand, bt_mesh_prov_link.prov_salt)) { - BT_ERR("Failed to generate provisioning salt"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("ProvisioningSalt: %s", bt_hex(bt_mesh_prov_link.prov_salt, 16)); - - send_random(); -} - -static void prov_confirm(const uint8_t *data) -{ - BT_DBG("Remote Confirm: %s", bt_hex(data, 16)); - - memcpy(bt_mesh_prov_link.conf, data, 16); - - notify_input_complete(); - - send_confirm(); -} - -static inline bool is_pb_gatt(void) -{ - return bt_mesh_prov_link.bearer && - bt_mesh_prov_link.bearer->type == BT_MESH_PROV_GATT; -} - -static void prov_data(const uint8_t *data) -{ - struct os_mbuf *msg = PROV_BUF(1); - uint8_t session_key[16]; - uint8_t nonce[13]; - uint8_t dev_key[16]; - uint8_t pdu[25]; - uint8_t flags; - uint32_t iv_index; - uint16_t addr; - uint16_t net_idx; - int err; - bool identity_enable; - - BT_DBG(""); - - err = bt_mesh_session_key(bt_mesh_prov_link.dhkey, - bt_mesh_prov_link.prov_salt, session_key); - if (err) { - BT_ERR("Unable to generate session key"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("SessionKey: %s", bt_hex(session_key, 16)); - - err = bt_mesh_prov_nonce(bt_mesh_prov_link.dhkey, - bt_mesh_prov_link.prov_salt, nonce); - if (err) { - BT_ERR("Unable to generate session nonce"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("Nonce: %s", bt_hex(nonce, 13)); - - err = bt_mesh_prov_decrypt(session_key, nonce, data, pdu); - if (err) { - BT_ERR("Unable to decrypt provisioning data"); - prov_fail(PROV_ERR_DECRYPT); - return; - } - - err = bt_mesh_dev_key(bt_mesh_prov_link.dhkey, - bt_mesh_prov_link.prov_salt, dev_key); - if (err) { - BT_ERR("Unable to generate device key"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("DevKey: %s", bt_hex(dev_key, 16)); - - net_idx = sys_get_be16(&pdu[16]); - flags = pdu[18]; - iv_index = sys_get_be32(&pdu[19]); - addr = sys_get_be16(&pdu[23]); - - BT_DBG("net_idx %u iv_index 0x%08x, addr 0x%04x", - net_idx, iv_index, addr); - - bt_mesh_prov_buf_init(msg, PROV_COMPLETE); - if (bt_mesh_prov_send(msg, NULL)) { - BT_ERR("Failed to send Provisioning Complete"); - return; - } - - /* Ignore any further PDUs on this link */ - bt_mesh_prov_link.expect = PROV_NO_PDU; - - /* Store info, since bt_mesh_provision() will end up clearing it */ - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - identity_enable = is_pb_gatt(); - } else { - identity_enable = false; - } - - err = bt_mesh_provision(pdu, net_idx, flags, iv_index, addr, dev_key); - if (err) { - BT_ERR("Failed to provision (err %d)", err); - return; - } - - /* After PB-GATT provisioning we should start advertising - * using Node Identity. - */ - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && identity_enable) { - bt_mesh_proxy_identity_enable(); - } -} - -static void local_input_complete(void) -{ - if (atomic_test_bit(bt_mesh_prov_link.flags, PUB_KEY_SENT)) { - send_input_complete(); - } else { - atomic_set_bit(bt_mesh_prov_link.flags, INPUT_COMPLETE); - } -} - -static void prov_link_closed(void) -{ - reset_state(); -} - -static void prov_link_opened(void) -{ - bt_mesh_prov_link.expect = PROV_INVITE; -} - -static const struct bt_mesh_prov_role role_device = { - .input_complete = local_input_complete, - .link_opened = prov_link_opened, - .link_closed = prov_link_closed, - .error = prov_fail, - .op = { - [PROV_INVITE] = prov_invite, - [PROV_START] = prov_start, - [PROV_PUB_KEY] = prov_pub_key, - [PROV_CONFIRM] = prov_confirm, - [PROV_RANDOM] = prov_random, - [PROV_DATA] = prov_data, - }, -}; - -int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) -{ - BT_DBG("bt_mesh_prov_enable"); - - if (bt_mesh_is_provisioned()) { - return -EALREADY; - } - - if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) && - (bearers & BT_MESH_PROV_ADV)) { - pb_adv.link_accept(bt_mesh_prov_bearer_cb_get(), NULL); - } - - if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) && - (bearers & BT_MESH_PROV_GATT)) { - pb_gatt.link_accept(bt_mesh_prov_bearer_cb_get(), NULL); - } - - BT_DBG("bt_mesh_prov_link.role = &role_device"); - bt_mesh_prov_link.role = &role_device; - - return 0; -} - -int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers) -{ - if (bt_mesh_is_provisioned()) { - return -EALREADY; - } - - if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) && - (bearers & BT_MESH_PROV_ADV)) { - bt_mesh_beacon_disable(); - bt_mesh_scan_disable(); - } - - if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) && - (bearers & BT_MESH_PROV_GATT)) { - bt_mesh_proxy_prov_disable(true); - } - - return 0; -} - -#endif /* MYNEWT_VAL(BLE_MESH) */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/provisioner.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/provisioner.c deleted file mode 100644 index 8a00087af..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/provisioner.c +++ /dev/null @@ -1,750 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * Copyright (c) 2020 Lingao Meng - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_PROV_LOG - -#if MYNEWT_VAL(BLE_MESH) - -#include "crypto.h" -#include "adv.h" -#include "../include/mesh/mesh.h" -#include "net.h" -#include "rpl.h" -#include "beacon.h" -#include "access.h" -#include "foundation.h" -#include "proxy.h" -#include "prov.h" -#include "settings.h" - -static struct { - struct bt_mesh_cdb_node *node; - uint16_t addr; - uint16_t net_idx; - uint8_t attention_duration; - uint8_t uuid[16]; -} prov_device; - -static void send_pub_key(void); -static void prov_dh_key_gen(void); -static void pub_key_ready(const uint8_t *pkey); - -static int reset_state(void) -{ -#if MYNEWT_VAL(BLE_MESH_CDB) - if (prov_device.node != NULL) { - bt_mesh_cdb_node_del(prov_device.node, false); - } -#endif - return bt_mesh_prov_reset_state(pub_key_ready); -} - -static void prov_link_close(enum prov_bearer_link_status status) -{ - BT_DBG("%u", status); - bt_mesh_prov_link.expect = PROV_NO_PDU; - - bt_mesh_prov_link.bearer->link_close(status); -} - -static void prov_fail(uint8_t reason) -{ - /* According to Bluetooth Mesh Specification v1.0.1, Section 5.4.4, the - * provisioner just closes the link when something fails, while the - * provisionee sends the fail message, and waits for the provisioner to - * close the link. - */ - prov_link_close(PROV_BEARER_LINK_STATUS_FAIL); -} - -static void send_invite(void) -{ - struct os_mbuf *inv = PROV_BUF(2); - - BT_DBG(""); - - bt_mesh_prov_buf_init(inv, PROV_INVITE); - net_buf_simple_add_u8(inv, prov_device.attention_duration); - - bt_mesh_prov_link.conf_inputs[0] = prov_device.attention_duration; - - if (bt_mesh_prov_send(inv, NULL)) { - BT_ERR("Failed to send invite"); - return; - } - - bt_mesh_prov_link.expect = PROV_CAPABILITIES; -} - -static void start_sent(int err, void *cb_data) -{ - if (!bt_pub_key_get()) { - atomic_set_bit(bt_mesh_prov_link.flags, WAIT_PUB_KEY); - BT_WARN("Waiting for local public key"); - } else { - send_pub_key(); - } -} - -static void send_start(void) -{ - BT_DBG(""); - uint8_t method, action; - struct os_mbuf *start = PROV_BUF(6); - - const uint8_t *data = &bt_mesh_prov_link.conf_inputs[1 + 3]; - - bt_mesh_prov_buf_init(start, PROV_START); - net_buf_simple_add_u8(start, PROV_ALG_P256); - - if (atomic_test_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY) && - *data == PUB_KEY_OOB) { - net_buf_simple_add_u8(start, PUB_KEY_OOB); - atomic_set_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY); - } else { - net_buf_simple_add_u8(start, PUB_KEY_NO_OOB); - } - - if (bt_mesh_prov_link.oob_method == AUTH_METHOD_INPUT) { - method = AUTH_METHOD_OUTPUT; - if (bt_mesh_prov_link.oob_action == INPUT_OOB_STRING) { - action = OUTPUT_OOB_STRING; - } else { - action = OUTPUT_OOB_NUMBER; - } - - } else if (bt_mesh_prov_link.oob_method == AUTH_METHOD_OUTPUT) { - method = AUTH_METHOD_INPUT; - if (bt_mesh_prov_link.oob_action == OUTPUT_OOB_STRING) { - action = INPUT_OOB_STRING; - } else { - action = INPUT_OOB_NUMBER; - } - } else { - method = bt_mesh_prov_link.oob_method; - action = 0x00; - } - - net_buf_simple_add_u8(start, bt_mesh_prov_link.oob_method); - - net_buf_simple_add_u8(start, bt_mesh_prov_link.oob_action); - - net_buf_simple_add_u8(start, bt_mesh_prov_link.oob_size); - - memcpy(&bt_mesh_prov_link.conf_inputs[12], &start->om_data[1], 5); - - if (bt_mesh_prov_auth(method, action, bt_mesh_prov_link.oob_size) < 0) { - BT_ERR("Invalid authentication method: 0x%02x; " - "action: 0x%02x; size: 0x%02x", method, - action, bt_mesh_prov_link.oob_size); - return; - } - - if (bt_mesh_prov_send(start, start_sent)) { - BT_ERR("Failed to send Provisioning Start"); - return; - } -} - -static bool prov_check_method(struct bt_mesh_dev_capabilities *caps) -{ - if (bt_mesh_prov_link.oob_method == AUTH_METHOD_STATIC) { - if (!caps->static_oob) { - BT_WARN("Device not support OOB static authentication provisioning"); - return false; - } - } else if (bt_mesh_prov_link.oob_method == AUTH_METHOD_INPUT) { - if (bt_mesh_prov_link.oob_size > caps->input_size) { - BT_WARN("The required input length (0x%02x) " - "exceeds the device capacity (0x%02x)", - bt_mesh_prov_link.oob_size, caps->input_size); - return false; - } - - if (!(BIT(bt_mesh_prov_link.oob_action) & caps->input_actions)) { - BT_WARN("The required input action (0x%02x) " - "not supported by the device (0x%02x)", - bt_mesh_prov_link.oob_action, caps->input_actions); - return false; - } - - if (bt_mesh_prov_link.oob_action == INPUT_OOB_STRING) { - if (!bt_mesh_prov->output_string) { - BT_WARN("Not support output string"); - return false; - } - } else { - if (!bt_mesh_prov->output_number) { - BT_WARN("Not support output number"); - return false; - } - } - } else if (bt_mesh_prov_link.oob_method == AUTH_METHOD_OUTPUT) { - if (bt_mesh_prov_link.oob_size > caps->output_size) { - BT_WARN("The required output length (0x%02x) " - "exceeds the device capacity (0x%02x)", - bt_mesh_prov_link.oob_size, caps->output_size); - return false; - } - - if (!(BIT(bt_mesh_prov_link.oob_action) & caps->output_actions)) { - BT_WARN("The required output action (0x%02x) " - "not supported by the device (0x%02x)", - bt_mesh_prov_link.oob_action, caps->output_actions); - return false; - } - - if (!bt_mesh_prov->input) { - BT_WARN("Not support input"); - return false; - } - } - - return true; -} - -static void prov_capabilities(const uint8_t *data) -{ - struct bt_mesh_dev_capabilities caps; - - caps.elem_count = data[0]; - BT_DBG("Elements: %u", caps.elem_count); - - caps.algorithms = sys_get_be16(&data[1]); - BT_DBG("Algorithms: %u", caps.algorithms); - - caps.pub_key_type = data[3]; - caps.static_oob = data[4]; - caps.output_size = data[5]; - BT_DBG("Public Key Type: 0x%02x", caps.pub_key_type); - BT_DBG("Static OOB Type: 0x%02x", caps.static_oob); - BT_DBG("Output OOB Size: %u", caps.output_size); - - caps.output_actions = (bt_mesh_output_action_t)data[6]; - caps.input_size = data[8]; - caps.input_actions = (bt_mesh_input_action_t)data[9]; - BT_DBG("Output OOB Action: 0x%04x", caps.output_actions); - BT_DBG("Input OOB Size: %u", caps.input_size); - BT_DBG("Input OOB Action: 0x%04x", caps.input_actions); - - if (data[0] == 0) { - BT_ERR("Invalid number of elements"); - prov_fail(PROV_ERR_NVAL_FMT); - return; - } -#if MYNEWT_VAL(BLE_MESH_CDB) - prov_device.node = - bt_mesh_cdb_node_alloc(prov_device.uuid, - prov_device.addr, data[0], - prov_device.net_idx); - if (prov_device.node == NULL) { - BT_ERR("Failed allocating node 0x%04x", prov_device.addr); - prov_fail(PROV_ERR_RESOURCES); - return; - } -#endif - memcpy(&bt_mesh_prov_link.conf_inputs[1], data, 11); - - if (bt_mesh_prov->capabilities) { - bt_mesh_prov->capabilities(&caps); - } - - if (!prov_check_method(&caps)) { - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - send_start(); -} - -static void send_confirm(void) -{ - struct os_mbuf *cfm = PROV_BUF(17); - - BT_DBG("ConfInputs[0] %s", bt_hex(bt_mesh_prov_link.conf_inputs, 64)); - BT_DBG("ConfInputs[64] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[64], 64)); - BT_DBG("ConfInputs[128] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[128], 17)); - - if (bt_mesh_prov_conf_salt(bt_mesh_prov_link.conf_inputs, - bt_mesh_prov_link.conf_salt)) { - BT_ERR("Unable to generate confirmation salt"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("ConfirmationSalt: %s", bt_hex(bt_mesh_prov_link.conf_salt, 16)); - - if (bt_mesh_prov_conf_key(bt_mesh_prov_link.dhkey, - bt_mesh_prov_link.conf_salt, bt_mesh_prov_link.conf_key)) { - BT_ERR("Unable to generate confirmation key"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("ConfirmationKey: %s", bt_hex(bt_mesh_prov_link.conf_key, 16)); - - if (bt_rand(bt_mesh_prov_link.rand, 16)) { - BT_ERR("Unable to generate random number"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("LocalRandom: %s", bt_hex(bt_mesh_prov_link.rand, 16)); - - bt_mesh_prov_buf_init(cfm, PROV_CONFIRM); - - if (bt_mesh_prov_conf(bt_mesh_prov_link.conf_key, - bt_mesh_prov_link.rand, bt_mesh_prov_link.auth, - net_buf_simple_add(cfm, 16))) { - BT_ERR("Unable to generate confirmation value"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - if (bt_mesh_prov_send(cfm, NULL)) { - BT_ERR("Failed to send Provisioning Confirm"); - return; - } - - bt_mesh_prov_link.expect = PROV_CONFIRM; -} - -static void public_key_sent(int err, void *cb_data) -{ - atomic_set_bit(bt_mesh_prov_link.flags, PUB_KEY_SENT); - - if (atomic_test_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY) && - atomic_test_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY)) { - prov_dh_key_gen(); - return; - } - - bt_mesh_prov_link.expect = PROV_PUB_KEY; -} - -static void send_pub_key(void) -{ - struct os_mbuf *buf = PROV_BUF(65); - const uint8_t *key; - - key = bt_pub_key_get(); - if (!key) { - BT_ERR("No public key available"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("Local Public Key: %s", bt_hex(key, 64)); - - bt_mesh_prov_buf_init(buf, PROV_PUB_KEY); - - /* Swap X and Y halves independently to big-endian */ - sys_memcpy_swap(net_buf_simple_add(buf, 32), key, 32); - sys_memcpy_swap(net_buf_simple_add(buf, 32), &key[32], 32); - - /* PublicKeyProvisioner */ - memcpy(&bt_mesh_prov_link.conf_inputs[17], &buf->om_databuf[1], 64); - - if (bt_mesh_prov_send(buf, public_key_sent)) { - BT_ERR("Failed to send Public Key"); - return; - } -} - -static void prov_dh_key_cb(const uint8_t dhkey[32]) -{ - BT_DBG("%p", dhkey); - - if (!dhkey) { - BT_ERR("DHKey generation failed"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - sys_memcpy_swap(bt_mesh_prov_link.dhkey, dhkey, 32); - - BT_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, 32)); - - if (atomic_test_bit(bt_mesh_prov_link.flags, WAIT_STRING) || - atomic_test_bit(bt_mesh_prov_link.flags, WAIT_NUMBER) || - atomic_test_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE)) { - atomic_set_bit(bt_mesh_prov_link.flags, WAIT_CONFIRM); - return; - } - - send_confirm(); -} - -static void prov_dh_key_gen(void) -{ - uint8_t remote_pk_le[64], *remote_pk; - - remote_pk = &bt_mesh_prov_link.conf_inputs[81]; - - /* Copy remote key in little-endian for bt_dh_key_gen(). - * X and Y halves are swapped independently. The bt_dh_key_gen() - * will also take care of validating the remote public key. - */ - sys_memcpy_swap(remote_pk_le, remote_pk, 32); - sys_memcpy_swap(&remote_pk_le[32], &remote_pk[32], 32); - - if (bt_dh_key_gen(remote_pk_le, prov_dh_key_cb)) { - BT_ERR("Failed to generate DHKey"); - prov_fail(PROV_ERR_UNEXP_ERR); - } - - if (atomic_test_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE)) { - bt_mesh_prov_link.expect = PROV_INPUT_COMPLETE; - } -} - -static void prov_pub_key(const uint8_t *data) -{ - BT_DBG("Remote Public Key: %s", bt_hex(data, 64)); - - atomic_set_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY); - - /* PublicKeyDevice */ - memcpy(&bt_mesh_prov_link.conf_inputs[81], data, 64); - bt_mesh_prov_link.bearer->clear_tx(); - - prov_dh_key_gen(); -} - -static void pub_key_ready(const uint8_t *pkey) -{ - if (!pkey) { - BT_WARN("Public key not available"); - return; - } - - BT_DBG("Local public key ready"); - - if (atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_PUB_KEY)) { - send_pub_key(); - } -} - -static void notify_input_complete(void) -{ - if (atomic_test_and_clear_bit(bt_mesh_prov_link.flags, - NOTIFY_INPUT_COMPLETE) && - bt_mesh_prov->input_complete) { - bt_mesh_prov->input_complete(); - } -} - -static void prov_input_complete(const uint8_t *data) -{ - BT_DBG(""); - - notify_input_complete(); - - if (atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_CONFIRM)) { - send_confirm(); - } -} - -static void send_prov_data(void) -{ - struct os_mbuf *pdu = PROV_BUF(34); -#if MYNEWT_VAL(BLE_MESH_CDB) - struct bt_mesh_cdb_subnet *sub; -#endif - uint8_t session_key[16]; - uint8_t nonce[13]; - int err; - - err = bt_mesh_session_key(bt_mesh_prov_link.dhkey, - bt_mesh_prov_link.prov_salt, session_key); - if (err) { - BT_ERR("Unable to generate session key"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("SessionKey: %s", bt_hex(session_key, 16)); - - err = bt_mesh_prov_nonce(bt_mesh_prov_link.dhkey, - bt_mesh_prov_link.prov_salt, nonce); - if (err) { - BT_ERR("Unable to generate session nonce"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("Nonce: %s", bt_hex(nonce, 13)); - - err = bt_mesh_dev_key(bt_mesh_prov_link.dhkey, - bt_mesh_prov_link.prov_salt, prov_device.node->dev_key); - if (err) { - BT_ERR("Unable to generate device key"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("DevKey: %s", bt_hex(prov_device.node->dev_key, 16)); -#if MYNEWT_VAL(BLE_MESH_CDB) - sub = bt_mesh_cdb_subnet_get(prov_device.node->net_idx); - if (sub == NULL) { - BT_ERR("No subnet with net_idx %u", - prov_device.node->net_idx); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } -#endif - bt_mesh_prov_buf_init(pdu, PROV_DATA); -#if MYNEWT_VAL(BLE_MESH_CDB) - net_buf_simple_add_mem(pdu, sub->keys[sub->kr_flag].net_key, 16); - net_buf_simple_add_be16(pdu, prov_device.node->net_idx); - net_buf_simple_add_u8(pdu, bt_mesh_cdb_subnet_flags(sub)); - net_buf_simple_add_be32(pdu, bt_mesh_cdb.iv_index); -#endif - net_buf_simple_add_be16(pdu, prov_device.node->addr); - net_buf_simple_add(pdu, 8); /* For MIC */ - - BT_DBG("net_idx %u, iv_index 0x%08x, addr 0x%04x", - prov_device.node->net_idx, bt_mesh.iv_index, - prov_device.node->addr); - - err = bt_mesh_prov_encrypt(session_key, nonce, &pdu->om_data[1], - &pdu->om_data[1]); - if (err) { - BT_ERR("Unable to encrypt provisioning data"); - prov_fail(PROV_ERR_DECRYPT); - return; - } - - if (bt_mesh_prov_send(pdu, NULL)) { - BT_ERR("Failed to send Provisioning Data"); - return; - } - - bt_mesh_prov_link.expect = PROV_COMPLETE; -} - -static void prov_complete(const uint8_t *data) -{ - struct bt_mesh_cdb_node *node = prov_device.node; - - BT_DBG("key %s, net_idx %u, num_elem %u, addr 0x%04x", - bt_hex(node->dev_key, 16), node->net_idx, node->num_elem, - node->addr); - -#if MYNEWT_VAL(BLE_MESH_CDB) - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb_node(node); - } -#endif - - prov_device.node = NULL; - prov_link_close(PROV_BEARER_LINK_STATUS_SUCCESS); - - if (bt_mesh_prov->node_added) { - bt_mesh_prov->node_added(node->net_idx, node->uuid, node->addr, - node->num_elem); - } -} - -static void send_random(void) -{ - struct os_mbuf *rnd = PROV_BUF(17); - - bt_mesh_prov_buf_init(rnd, PROV_RANDOM); - net_buf_simple_add_mem(rnd, bt_mesh_prov_link.rand, 16); - - if (bt_mesh_prov_send(rnd, NULL)) { - BT_ERR("Failed to send Provisioning Random"); - return; - } - - bt_mesh_prov_link.expect = PROV_RANDOM; -} - -static void prov_random(const uint8_t *data) -{ - uint8_t conf_verify[16]; - - BT_DBG("Remote Random: %s", bt_hex(data, 16)); - if (!memcmp(data, bt_mesh_prov_link.rand, 16)) { - BT_ERR("Random value is identical to ours, rejecting."); - prov_fail(PROV_ERR_CFM_FAILED); - return; - } - - if (bt_mesh_prov_conf(bt_mesh_prov_link.conf_key, - data, bt_mesh_prov_link.auth, conf_verify)) { - BT_ERR("Unable to calculate confirmation verification"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - if (memcmp(conf_verify, bt_mesh_prov_link.conf, 16)) { - BT_ERR("Invalid confirmation value"); - BT_DBG("Received: %s", bt_hex(bt_mesh_prov_link.conf, 16)); - BT_DBG("Calculated: %s", bt_hex(conf_verify, 16)); - prov_fail(PROV_ERR_CFM_FAILED); - return; - } - - if (bt_mesh_prov_salt(bt_mesh_prov_link.conf_salt, - bt_mesh_prov_link.rand, data, bt_mesh_prov_link.prov_salt)) { - BT_ERR("Failed to generate provisioning salt"); - prov_fail(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("ProvisioningSalt: %s", bt_hex(bt_mesh_prov_link.prov_salt, 16)); - - send_prov_data(); -} - -static void prov_confirm(const uint8_t *data) -{ - BT_DBG("Remote Confirm: %s", bt_hex(data, 16)); - - memcpy(bt_mesh_prov_link.conf, data, 16); - - send_random(); -} - -static void prov_failed(const uint8_t *data) -{ - BT_WARN("Error: 0x%02x", data[0]); - reset_state(); -} - -static void local_input_complete(void) -{ - if (atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_CONFIRM)) { - send_confirm(); - } -} - -static void prov_link_closed(void) -{ - reset_state(); -} - -static void prov_link_opened(void) -{ - send_invite(); -} - -static const struct bt_mesh_prov_role role_provisioner = { - .input_complete = local_input_complete, - .link_opened = prov_link_opened, - .link_closed = prov_link_closed, - .error = prov_fail, - .op = { - [PROV_CAPABILITIES] = prov_capabilities, - [PROV_PUB_KEY] = prov_pub_key, - [PROV_INPUT_COMPLETE] = prov_input_complete, - [PROV_CONFIRM] = prov_confirm, - [PROV_RANDOM] = prov_random, - [PROV_COMPLETE] = prov_complete, - [PROV_FAILED] = prov_failed, - }, -}; - -static void prov_set_method(uint8_t method, uint8_t action, uint8_t size) -{ - bt_mesh_prov_link.oob_method = method; - bt_mesh_prov_link.oob_action = action; - bt_mesh_prov_link.oob_size = size; -} - -int bt_mesh_auth_method_set_input(bt_mesh_input_action_t action, uint8_t size) -{ - if (!action || !size || size > 8) { - return -EINVAL; - } - - prov_set_method(AUTH_METHOD_INPUT, find_msb_set(action) - 1, size); - return 0; -} - -int bt_mesh_auth_method_set_output(bt_mesh_output_action_t action, uint8_t size) -{ - if (!action || !size || size > 8) { - return -EINVAL; - } - - prov_set_method(AUTH_METHOD_OUTPUT, find_msb_set(action) - 1, size); - return 0; -} - -int bt_mesh_auth_method_set_static(const uint8_t *static_val, uint8_t size) -{ - if (!size || !static_val || size > 16) { - return -EINVAL; - } - - prov_set_method(AUTH_METHOD_STATIC, 0, 0); - - memcpy(bt_mesh_prov_link.auth + 16 - size, static_val, size); - if (size < 16) { - (void)memset(bt_mesh_prov_link.auth, 0, - sizeof(bt_mesh_prov_link.auth) - size); - } - return 0; -} - -int bt_mesh_auth_method_set_none(void) -{ - prov_set_method(AUTH_METHOD_NO_OOB, 0, 0); - return 0; -} - -int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[64]) -{ - if (public_key == NULL) { - return -EINVAL; - } - - if (atomic_test_and_set_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY)) { - return -EALREADY; - } - - /* Swap X and Y halves independently to big-endian */ - memcpy(&bt_mesh_prov_link.conf_inputs[81], public_key, 32); - memcpy(&bt_mesh_prov_link.conf_inputs[81 + 32], &public_key[32], 32); - - return 0; -} - -#if defined(CONFIG_BT_MESH_PB_ADV) -int bt_mesh_pb_adv_open(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr, - uint8_t attention_duration) -{ - int err; - - if (atomic_test_and_set_bit(bt_mesh_prov_link.flags, LINK_ACTIVE)) { - return -EBUSY; - } - - atomic_set_bit(bt_mesh_prov_link.flags, PROVISIONER); - memcpy(prov_device.uuid, uuid, 16); - prov_device.addr = addr; - prov_device.net_idx = net_idx; - prov_device.attention_duration = attention_duration; - bt_mesh_prov_link.bearer = &pb_adv; - bt_mesh_prov_link.role = &role_provisioner; - - err = bt_mesh_prov_link.bearer->link_open(prov_device.uuid, PROTOCOL_TIMEOUT, - bt_mesh_prov_bearer_cb_get(), NULL); - if (err) { - atomic_clear_bit(bt_mesh_prov_link.flags, LINK_ACTIVE); - } - - return err; -} -#endif -#endif /* MYNEWT_VAL(BLE_MESH) */ diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/provisioner.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/provisioner.h deleted file mode 100644 index ccda47efe..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/provisioner.h +++ /dev/null @@ -1,10 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -int bt_mesh_pb_adv_open(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr, - uint8_t attention_duration); \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/proxy.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/proxy.c deleted file mode 100644 index d8b679302..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/proxy.c +++ /dev/null @@ -1,1571 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_PROXY_LOG - -#if MYNEWT_VAL(BLE_MESH_PROXY) - -#include "../include/mesh/mesh.h" -#include "nimble/nimble/host/include/host/ble_att.h" -#include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h" -#include "nimble/nimble/host/src/ble_hs_priv.h" - -#include "mesh_priv.h" -#include "adv.h" -#include "net.h" -#include "rpl.h" -#include "prov.h" -#include "beacon.h" -#include "foundation.h" -#include "access.h" -#include "proxy.h" - -#define PDU_TYPE(data) (data[0] & BIT_MASK(6)) -#define PDU_SAR(data) (data[0] >> 6) - -#define BT_UUID_16_ENCODE(w16) \ - (((w16) >> 0) & 0xFF), \ - (((w16) >> 8) & 0xFF) -/* Mesh Profile 1.0 Section 6.6: - * "The timeout for the SAR transfer is 20 seconds. When the timeout - * expires, the Proxy Server shall disconnect." - */ -#define PROXY_SAR_TIMEOUT K_SECONDS(20) - -#define SAR_COMPLETE 0x00 -#define SAR_FIRST 0x01 -#define SAR_CONT 0x02 -#define SAR_LAST 0x03 - -#define CFG_FILTER_SET 0x00 -#define CFG_FILTER_ADD 0x01 -#define CFG_FILTER_REMOVE 0x02 -#define CFG_FILTER_STATUS 0x03 - -/** @def BT_UUID_MESH_PROV - * @brief Mesh Provisioning Service - */ -ble_uuid16_t BT_UUID_MESH_PROV = BLE_UUID16_INIT(0x1827); -#define BT_UUID_MESH_PROV_VAL 0x1827 -/** @def BT_UUID_MESH_PROXY - * @brief Mesh Proxy Service - */ -ble_uuid16_t BT_UUID_MESH_PROXY = BLE_UUID16_INIT(0x1828); -#define BT_UUID_MESH_PROXY_VAL 0x1828 -/** @def BT_UUID_GATT_CCC - * @brief GATT Client Characteristic Configuration - */ -ble_uuid16_t BT_UUID_GATT_CCC = BLE_UUID16_INIT(0x2902); -#define BT_UUID_GATT_CCC_VAL 0x2902 -/** @def BT_UUID_MESH_PROV_DATA_IN - * @brief Mesh Provisioning Data In - */ -ble_uuid16_t BT_UUID_MESH_PROV_DATA_IN = BLE_UUID16_INIT(0x2adb); -#define BT_UUID_MESH_PROV_DATA_IN_VAL 0x2adb -/** @def BT_UUID_MESH_PROV_DATA_OUT - * @brief Mesh Provisioning Data Out - */ -ble_uuid16_t BT_UUID_MESH_PROV_DATA_OUT = BLE_UUID16_INIT(0x2adc); -#define BT_UUID_MESH_PROV_DATA_OUT_VAL 0x2adc -/** @def BT_UUID_MESH_PROXY_DATA_IN - * @brief Mesh Proxy Data In - */ -ble_uuid16_t BT_UUID_MESH_PROXY_DATA_IN = BLE_UUID16_INIT(0x2add); -#define BT_UUID_MESH_PROXY_DATA_IN_VAL 0x2add -/** @def BT_UUID_MESH_PROXY_DATA_OUT - * @brief Mesh Proxy Data Out - */ -ble_uuid16_t BT_UUID_MESH_PROXY_DATA_OUT = BLE_UUID16_INIT(0x2ade); -#define BT_UUID_MESH_PROXY_DATA_OUT_VAL 0x2ade - -#define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6))) - -#define CLIENT_BUF_SIZE 68 - -static const struct ble_gap_adv_params slow_adv_param = { - .conn_mode = (BLE_GAP_CONN_MODE_UND), - .disc_mode = (BLE_GAP_DISC_MODE_GEN), - .itvl_min = BT_GAP_ADV_SLOW_INT_MIN, - .itvl_max = BT_GAP_ADV_SLOW_INT_MAX, -}; - -static const struct ble_gap_adv_params fast_adv_param = { - .conn_mode = (BLE_GAP_CONN_MODE_UND), - .disc_mode = (BLE_GAP_DISC_MODE_GEN), - .itvl_min = BT_GAP_ADV_FAST_INT_MIN_2, - .itvl_max = BT_GAP_ADV_FAST_INT_MAX_2, -}; - -static bool proxy_adv_enabled; - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) -static void proxy_send_beacons(struct ble_npl_event *work); -#endif - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) -static bool prov_fast_adv; -#endif - -static struct bt_mesh_proxy_client { - uint16_t conn_handle; - uint16_t filter[MYNEWT_VAL(BLE_MESH_PROXY_FILTER_SIZE)]; - enum __packed { - NONE, - WHITELIST, - BLACKLIST, - PROV, - } filter_type; - uint8_t msg_type; -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - struct ble_npl_callout send_beacons; -#endif - struct k_delayed_work sar_timer; - struct os_mbuf *buf; -} clients[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = { - [0 ... (MYNEWT_VAL(BLE_MAX_CONNECTIONS) - 1)] = { 0 }, -}; - -static sys_slist_t idle_waiters; -static atomic_t pending_notifications; - -/* Track which service is enabled */ -static enum { - MESH_GATT_NONE, - MESH_GATT_PROV, - MESH_GATT_PROXY, -} gatt_svc = MESH_GATT_NONE; - -static struct { - uint16_t proxy_h; - uint16_t proxy_data_out_h; - uint16_t prov_h; - uint16_t prov_data_in_h; - uint16_t prov_data_out_h; -} svc_handles; - -static void resolve_svc_handles(void) -{ - int rc; - - /* Either all handles are already resolved, or none of them */ - if (svc_handles.prov_data_out_h) { - return; - } - - /* - * We assert if attribute is not found since at this stage all attributes - * shall be already registered and thus shall be found. - */ - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), - &svc_handles.proxy_h); - assert(rc == 0); - - rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), - BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_OUT_VAL), - NULL, &svc_handles.proxy_data_out_h); - assert(rc == 0); - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), - &svc_handles.prov_h); - assert(rc == 0); - - rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), - BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_IN_VAL), - NULL, &svc_handles.prov_data_in_h); - assert(rc == 0); - - rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), - BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_OUT_VAL), - NULL, &svc_handles.prov_data_out_h); - assert(rc == 0); -} - -static struct bt_mesh_proxy_client *find_client(uint16_t conn_handle) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].conn_handle == conn_handle) { - return &clients[i]; - } - } - - return NULL; -} - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) -/* Next subnet in queue to be advertised */ -static struct bt_mesh_subnet *beacon_sub; - -static int proxy_segment_and_send(uint16_t conn_handle, uint8_t type, - struct os_mbuf *msg); - -static int filter_set(struct bt_mesh_proxy_client *client, - struct os_mbuf *buf) -{ - uint8_t type; - - if (buf->om_len < 1) { - BT_WARN("Too short Filter Set message"); - return -EINVAL; - } - - type = net_buf_simple_pull_u8(buf); - BT_DBG("type 0x%02x", type); - - switch (type) { - case 0x00: - memset(client->filter, 0, sizeof(client->filter)); - client->filter_type = WHITELIST; - break; - case 0x01: - memset(client->filter, 0, sizeof(client->filter)); - client->filter_type = BLACKLIST; - break; - default: - BT_WARN("Prohibited Filter Type 0x%02x", type); - return -EINVAL; - } - - return 0; -} - -static void filter_add(struct bt_mesh_proxy_client *client, uint16_t addr) -{ - int i; - - BT_DBG("addr 0x%04x", addr); - - if (addr == BT_MESH_ADDR_UNASSIGNED) { - return; - } - - for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == addr) { - return; - } - } - - for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == BT_MESH_ADDR_UNASSIGNED) { - client->filter[i] = addr; - return; - } - } -} - -static void filter_remove(struct bt_mesh_proxy_client *client, uint16_t addr) -{ - int i; - - BT_DBG("addr 0x%04x", addr); - - if (addr == BT_MESH_ADDR_UNASSIGNED) { - return; - } - - for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == addr) { - client->filter[i] = BT_MESH_ADDR_UNASSIGNED; - return; - } - } -} - -static void send_filter_status(struct bt_mesh_proxy_client *client, - struct bt_mesh_net_rx *rx, - struct os_mbuf *buf) -{ - struct bt_mesh_net_tx tx = { - .sub = rx->sub, - .ctx = &rx->ctx, - .src = bt_mesh_primary_addr(), - }; - uint16_t filter_size; - int i, err; - - /* Configuration messages always have dst unassigned */ - tx.ctx->addr = BT_MESH_ADDR_UNASSIGNED; - - net_buf_simple_init(buf, 10); - - net_buf_simple_add_u8(buf, CFG_FILTER_STATUS); - - if (client->filter_type == WHITELIST) { - net_buf_simple_add_u8(buf, 0x00); - } else { - net_buf_simple_add_u8(buf, 0x01); - } - - for (filter_size = 0, i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] != BT_MESH_ADDR_UNASSIGNED) { - filter_size++; - } - } - - net_buf_simple_add_be16(buf, filter_size); - - BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - - err = bt_mesh_net_encode(&tx, buf, true); - if (err) { - BT_ERR("Encoding Proxy cfg message failed (err %d)", err); - return; - } - - err = proxy_segment_and_send(client->conn_handle, BT_MESH_PROXY_CONFIG, buf); - if (err) { - BT_ERR("Failed to send proxy cfg message (err %d)", err); - } -} - -static void proxy_cfg(struct bt_mesh_proxy_client *client) -{ - struct os_mbuf *buf = NET_BUF_SIMPLE(29); - struct bt_mesh_net_rx rx; - uint8_t opcode; - int err; - - err = bt_mesh_net_decode(client->buf, BT_MESH_NET_IF_PROXY_CFG, - &rx, buf); - if (err) { - BT_ERR("Failed to decode Proxy Configuration (err %d)", err); - goto done; - } - - rx.local_match = 1U; - - if (bt_mesh_rpl_check(&rx, NULL)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", - rx.ctx.addr, rx.ctx.recv_dst, rx.seq); - goto done; - } - - /* Remove network headers */ - net_buf_simple_pull_mem(buf, BT_MESH_NET_HDR_LEN); - - BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - - if (buf->om_len < 1) { - BT_WARN("Too short proxy configuration PDU"); - goto done; - } - - opcode = net_buf_simple_pull_u8(buf); - switch (opcode) { - case CFG_FILTER_SET: - filter_set(client, buf); - send_filter_status(client, &rx, buf); - break; - case CFG_FILTER_ADD: - while (buf->om_len >= 2) { - uint16_t addr; - - addr = net_buf_simple_pull_be16(buf); - filter_add(client, addr); - } - send_filter_status(client, &rx, buf); - break; - case CFG_FILTER_REMOVE: - while (buf->om_len >= 2) { - uint16_t addr; - - addr = net_buf_simple_pull_be16(buf); - filter_remove(client, addr); - } - send_filter_status(client, &rx, buf); - break; - default: - BT_WARN("Unhandled configuration OpCode 0x%02x", opcode); - break; - } - -done: - os_mbuf_free_chain(buf); -} - -static int beacon_send(uint16_t conn_handle, struct bt_mesh_subnet *sub) -{ - struct os_mbuf *buf = NET_BUF_SIMPLE(23); - int rc; - - net_buf_simple_init(buf, 1); - bt_mesh_beacon_create(sub, buf); - - rc = proxy_segment_and_send(conn_handle, BT_MESH_PROXY_BEACON, buf); - os_mbuf_free_chain(buf); - return rc; -} - -static int send_beacon_cb(struct bt_mesh_subnet *sub, void *cb_data) -{ - struct bt_mesh_proxy_client *client = cb_data; - - return beacon_send(client->conn_handle, sub); -} - -static void proxy_send_beacons(struct ble_npl_event *work) -{ - struct bt_mesh_proxy_client *client; - - client = ble_npl_event_get_arg(work); - - (void)bt_mesh_subnet_find(send_beacon_cb, client); -} - -static void proxy_sar_timeout(struct ble_npl_event *work) -{ - struct bt_mesh_proxy_client *client; - int rc; - - BT_WARN("Proxy SAR timeout"); - - client = ble_npl_event_get_arg(work); - assert(client != NULL); - - if ((client->conn_handle != BLE_HS_CONN_HANDLE_NONE)) { - rc = ble_gap_terminate(client->conn_handle, - BLE_ERR_REM_USER_CONN_TERM); - assert(rc == 0); - } -} - -void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub) -{ - int i; - - if (!sub) { - /* NULL means we send on all subnets */ - bt_mesh_subnet_foreach(bt_mesh_proxy_beacon_send); - return; - } - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].conn_handle != BLE_HS_CONN_HANDLE_NONE) { - beacon_send(clients[i].conn_handle, sub); - } - } -} - -static void node_id_start(struct bt_mesh_subnet *sub) -{ - sub->node_id = BT_MESH_NODE_IDENTITY_RUNNING; - sub->node_id_start = k_uptime_get_32(); -} - -void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub) -{ - node_id_start(sub); - /* Prioritize the recently enabled subnet */ - beacon_sub = sub; -} - -void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub) -{ - sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED; - sub->node_id_start = 0; -} - -int bt_mesh_proxy_identity_enable(void) -{ - BT_DBG(""); - - if (!bt_mesh_is_provisioned()) { - return -EAGAIN; - } - - if (bt_mesh_subnet_foreach(node_id_start)) { - bt_mesh_adv_update(); - } - - return 0; -} - -#endif /* GATT_PROXY */ - -static void proxy_complete_pdu(struct bt_mesh_proxy_client *client) -{ - switch (client->msg_type) { -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - case BT_MESH_PROXY_NET_PDU: - BT_INFO("Mesh Network PDU"); - bt_mesh_net_recv(client->buf, 0, BT_MESH_NET_IF_PROXY); - break; - case BT_MESH_PROXY_BEACON: - BT_INFO("Mesh Beacon PDU"); - bt_mesh_beacon_recv(client->buf); - break; - case BT_MESH_PROXY_CONFIG: - BT_INFO("Mesh Configuration PDU"); - proxy_cfg(client); - break; -#endif -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) - case BT_MESH_PROXY_PROV: - BT_INFO("Mesh Provisioning PDU"); - bt_mesh_pb_gatt_recv(client->conn_handle, client->buf); - break; -#endif - default: - BT_WARN("Unhandled Message Type 0x%02x", client->msg_type); - break; - } - - net_buf_simple_init(client->buf, 0); -} - -static int proxy_recv(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - struct bt_mesh_proxy_client *client = find_client(conn_handle); - const uint8_t *data = ctxt->om->om_data; - uint16_t len = ctxt->om->om_len; - - client = find_client(conn_handle); - - if (!client) { - return -ENOTCONN; - } - - if (len < 1) { - BT_WARN("Too small Proxy PDU"); - return -EINVAL; - } - - if ((attr_handle == svc_handles.prov_data_in_h) != - (PDU_TYPE(data) == BT_MESH_PROXY_PROV)) { - BT_WARN("Proxy PDU type doesn't match GATT service"); - return -EINVAL; - } - - if (len - 1 > net_buf_simple_tailroom(client->buf)) { - BT_WARN("Too big proxy PDU"); - return -EINVAL; - } - - switch (PDU_SAR(data)) { - case SAR_COMPLETE: - if (client->buf->om_len) { - BT_WARN("Complete PDU while a pending incomplete one"); - return -EINVAL; - } - - client->msg_type = PDU_TYPE(data); - net_buf_simple_add_mem(client->buf, data + 1, len - 1); - proxy_complete_pdu(client); - break; - - case SAR_FIRST: - if (client->buf->om_len) { - BT_WARN("First PDU while a pending incomplete one"); - return -EINVAL; - } - - k_delayed_work_submit(&client->sar_timer, PROXY_SAR_TIMEOUT); - client->msg_type = PDU_TYPE(data); - net_buf_simple_add_mem(client->buf, data + 1, len - 1); - break; - - case SAR_CONT: - if (!client->buf->om_len) { - BT_WARN("Continuation with no prior data"); - return -EINVAL; - } - - if (client->msg_type != PDU_TYPE(data)) { - BT_WARN("Unexpected message type in continuation"); - return -EINVAL; - } - - k_delayed_work_submit(&client->sar_timer, PROXY_SAR_TIMEOUT); - net_buf_simple_add_mem(client->buf, data + 1, len - 1); - break; - - case SAR_LAST: - if (!client->buf->om_len) { - BT_WARN("Last SAR PDU with no prior data"); - return -EINVAL; - } - - if (client->msg_type != PDU_TYPE(data)) { - BT_WARN("Unexpected message type in last SAR PDU"); - return -EINVAL; - } - - k_delayed_work_cancel(&client->sar_timer); - net_buf_simple_add_mem(client->buf, data + 1, len - 1); - proxy_complete_pdu(client); - break; - } - - return len; -} - -static int conn_count; - -static void proxy_connected(uint16_t conn_handle) -{ - struct bt_mesh_proxy_client *client; - int i; - - BT_INFO("conn_handle %d", conn_handle); - - conn_count++; - - /* Since we use ADV_OPT_ONE_TIME */ - proxy_adv_enabled = false; - - /* Try to re-enable advertising in case it's possible */ - if (conn_count < CONFIG_BT_MAX_CONN) { - bt_mesh_adv_update(); - } - - for (client = NULL, i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].conn_handle == BLE_HS_CONN_HANDLE_NONE) { - client = &clients[i]; - break; - } - } - - if (!client) { - BT_ERR("No free Proxy Client objects"); - return; - } - - client->conn_handle = conn_handle; - client->filter_type = NONE; - memset(client->filter, 0, sizeof(client->filter)); - net_buf_simple_init(client->buf, 0); -} - -static void proxy_disconnected(uint16_t conn_handle, int reason) -{ - int i; - - BT_DBG("conn handle %u reason 0x%02x", conn_handle, reason); - conn_count--; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - struct bt_mesh_proxy_client *client = &clients[i]; - - if (client->conn_handle == conn_handle) { - if ((MYNEWT_VAL(BLE_MESH_PB_GATT)) && - client->filter_type == PROV) { - bt_mesh_pb_gatt_close(conn_handle); - } - - k_delayed_work_cancel(&client->sar_timer); - client->conn_handle = BLE_HS_CONN_HANDLE_NONE; - break; - } - } - - bt_mesh_adv_update(); -} - -struct os_mbuf *bt_mesh_proxy_get_buf(void) -{ - struct os_mbuf *buf = clients[0].buf; - - if (buf != NULL) { - net_buf_simple_init(buf, 0); - } - - return buf; -} - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) -static void prov_ccc_write(uint16_t conn_handle) -{ - struct bt_mesh_proxy_client *client; - - BT_DBG("conn_handle %d", conn_handle); - - /* If a connection exists there must be a client */ - client = find_client(conn_handle); - __ASSERT(client, "No client for connection"); - - if (client->filter_type == NONE) { - client->filter_type = PROV; - bt_mesh_pb_gatt_open(conn_handle); - } -} - -int bt_mesh_proxy_prov_enable(void) -{ - uint16_t handle; - int rc; - int i; - - BT_DBG(""); - - if (gatt_svc == MESH_GATT_PROV) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_NONE) { - return -EBUSY; - } - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), &handle); - assert(rc == 0); - ble_gatts_svc_set_visibility(handle, 1); - /* FIXME: figure out end handle */ - ble_svc_gatt_changed(svc_handles.prov_h, 0xffff); - - gatt_svc = MESH_GATT_PROV; - prov_fast_adv = true; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].conn_handle != BLE_HS_CONN_HANDLE_NONE) { - clients[i].filter_type = PROV; - } - } - - - return 0; -} - -int bt_mesh_proxy_prov_disable(bool disconnect) -{ - uint16_t handle; - int rc; - int i; - - BT_DBG(""); - - if (gatt_svc == MESH_GATT_NONE) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_PROV) { - return -EBUSY; - } - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), &handle); - assert(rc == 0); - ble_gatts_svc_set_visibility(handle, 0); - /* FIXME: figure out end handle */ - ble_svc_gatt_changed(svc_handles.prov_h, 0xffff); - - gatt_svc = MESH_GATT_NONE; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - struct bt_mesh_proxy_client *client = &clients[i]; - - if ((client->conn_handle == BLE_HS_CONN_HANDLE_NONE) - || (client->filter_type != PROV)) { - continue; - } - - if (disconnect) { - rc = ble_gap_terminate(client->conn_handle, - BLE_ERR_REM_USER_CONN_TERM); - assert(rc == 0); - } else { - bt_mesh_pb_gatt_close(client->conn_handle); - client->filter_type = NONE; - } - } - - bt_mesh_adv_update(); - - return 0; -} -#endif /* MYNEWT_VAL(BLE_MESH_PB_GATT) */ - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) -static void proxy_ccc_write(uint16_t conn_handle) -{ - struct bt_mesh_proxy_client *client; - - BT_DBG("conn_handle %d", conn_handle); - - client = find_client(conn_handle); - __ASSERT(client, "No client for connection"); - - if (client->filter_type == NONE) { - client->filter_type = WHITELIST; - k_work_add_arg(&client->send_beacons, client); - k_work_submit(&client->send_beacons); - } -} - -int bt_mesh_proxy_gatt_enable(void) -{ - uint16_t handle; - int rc; - int i; - - BT_DBG(""); - - if (gatt_svc == MESH_GATT_PROXY) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_NONE) { - return -EBUSY; - } - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle); - assert(rc == 0); - ble_gatts_svc_set_visibility(handle, 1); - /* FIXME: figure out end handle */ - ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff); - - gatt_svc = MESH_GATT_PROXY; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].conn_handle != BLE_HS_CONN_HANDLE_NONE) { - clients[i].filter_type = WHITELIST; - } - } - - return 0; -} - -void bt_mesh_proxy_gatt_disconnect(void) -{ - int rc; - int i; - - BT_DBG(""); - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - struct bt_mesh_proxy_client *client = &clients[i]; - - if ((client->conn_handle != BLE_HS_CONN_HANDLE_NONE) && - (client->filter_type == WHITELIST || - client->filter_type == BLACKLIST)) { - client->filter_type = NONE; - rc = ble_gap_terminate(client->conn_handle, - BLE_ERR_REM_USER_CONN_TERM); - assert(rc == 0); - } - } -} - -int bt_mesh_proxy_gatt_disable(void) -{ - uint16_t handle; - int rc; - - BT_DBG(""); - - if (gatt_svc == MESH_GATT_NONE) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_PROXY) { - return -EBUSY; - } - - bt_mesh_proxy_gatt_disconnect(); - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle); - assert(rc == 0); - ble_gatts_svc_set_visibility(handle, 0); - /* FIXME: figure out end handle */ - ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff); - - gatt_svc = MESH_GATT_NONE; - - return 0; -} - -void bt_mesh_proxy_addr_add(struct os_mbuf *buf, uint16_t addr) -{ - struct bt_mesh_proxy_client *client = NULL; - int i; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - client = &clients[i]; - if (client->buf == buf) { - break; - } - } - - assert(client); - - BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); - - if (client->filter_type == WHITELIST) { - filter_add(client, addr); - } else if (client->filter_type == BLACKLIST) { - filter_remove(client, addr); - } -} - -static bool client_filter_match(struct bt_mesh_proxy_client *client, - uint16_t addr) -{ - int i; - - BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); - - if (client->filter_type == BLACKLIST) { - for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == addr) { - return false; - } - } - - return true; - } - - if (addr == BT_MESH_ADDR_ALL_NODES) { - return true; - } - - if (client->filter_type == WHITELIST) { - for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == addr) { - return true; - } - } - } - - return false; -} - -bool bt_mesh_proxy_relay(struct os_mbuf *buf, uint16_t dst) -{ - bool relayed = false; - int i; - - BT_DBG("%u bytes to dst 0x%04x", buf->om_len, dst); - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - struct bt_mesh_proxy_client *client = &clients[i]; - struct os_mbuf *msg; - - if (client->conn_handle == BLE_HS_CONN_HANDLE_NONE) { - continue; - } - - if (!client_filter_match(client, dst)) { - continue; - } - - /* Proxy PDU sending modifies the original buffer, - * so we need to make a copy. - */ - msg = NET_BUF_SIMPLE(32); - net_buf_simple_init(msg, 1); - net_buf_simple_add_mem(msg, buf->om_data, buf->om_len); - - bt_mesh_proxy_send(client->conn_handle, BT_MESH_PROXY_NET_PDU, msg); - os_mbuf_free_chain(msg); - relayed = true; - } - - return relayed; -} - -#endif /* MYNEWT_VAL(BLE_MESH_GATT_PROXY) */ - -static void notify_complete(void) -{ - sys_snode_t *n; - - if (atomic_dec(&pending_notifications) > 1) { - return; - } - - BT_DBG(""); - - while ((n = sys_slist_get(&idle_waiters))) { - CONTAINER_OF(n, struct bt_mesh_proxy_idle_cb, n)->cb(); - } -} - -static int proxy_send(uint16_t conn_handle, const void *data, uint16_t len) -{ - struct os_mbuf *om; - int err = 0; - - BT_DBG("%u bytes: %s", len, bt_hex(data, len)); - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - if (gatt_svc == MESH_GATT_PROXY) { - om = ble_hs_mbuf_from_flat(data, len); - assert(om); - err = ble_gattc_notify_custom(conn_handle, svc_handles.proxy_data_out_h, om); - notify_complete(); - } -#endif - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) - if (gatt_svc == MESH_GATT_PROV) { - om = ble_hs_mbuf_from_flat(data, len); - assert(om); - err = ble_gattc_notify_custom(conn_handle, svc_handles.prov_data_out_h, om); - notify_complete(); - } -#endif - - if (!err) { - atomic_inc(&pending_notifications); - } - - return err; -} - -static int proxy_segment_and_send(uint16_t conn_handle, uint8_t type, - struct os_mbuf *msg) -{ - uint16_t mtu; - - BT_DBG("conn_handle %d type 0x%02x len %u: %s", conn_handle, type, msg->om_len, - bt_hex(msg->om_data, msg->om_len)); - - /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */ - mtu = ble_att_mtu(conn_handle) - 3; - if (mtu > msg->om_len) { - net_buf_simple_push_u8(msg, PDU_HDR(SAR_COMPLETE, type)); - return proxy_send(conn_handle, msg->om_data, msg->om_len); - } - - net_buf_simple_push_u8(msg, PDU_HDR(SAR_FIRST, type)); - proxy_send(conn_handle, msg->om_data, mtu); - net_buf_simple_pull_mem(msg, mtu); - - while (msg->om_len) { - if (msg->om_len + 1 < mtu) { - net_buf_simple_push_u8(msg, PDU_HDR(SAR_LAST, type)); - proxy_send(conn_handle, msg->om_data, msg->om_len); - break; - } - - net_buf_simple_push_u8(msg, PDU_HDR(SAR_CONT, type)); - proxy_send(conn_handle, msg->om_data, mtu); - net_buf_simple_pull_mem(msg, mtu); - } - - return 0; -} - -int bt_mesh_proxy_send(uint16_t conn_handle, uint8_t type, - struct os_mbuf *msg) -{ - struct bt_mesh_proxy_client *client = find_client(conn_handle); - - if (!client) { - BT_ERR("No Proxy Client found"); - return -ENOTCONN; - } - - if ((client->filter_type == PROV) != (type == BT_MESH_PROXY_PROV)) { - BT_ERR("Invalid PDU type for Proxy Client"); - return -EINVAL; - } - - return proxy_segment_and_send(conn_handle, type, msg); -} - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) -static uint8_t prov_svc_data[20] = { - BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL), -}; - -static const struct bt_data prov_ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), - BT_DATA_BYTES(BT_DATA_UUID16_ALL, - BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL)), - BT_DATA(BT_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)), -}; -#endif /* PB_GATT */ - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - -#define ID_TYPE_NET 0x00 -#define ID_TYPE_NODE 0x01 - -#define NODE_ID_LEN 19 -#define NET_ID_LEN 11 - -#define NODE_ID_TIMEOUT K_SECONDS(CONFIG_BT_MESH_NODE_ID_TIMEOUT) - -static uint8_t proxy_svc_data[NODE_ID_LEN] = { - BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL), -}; - -static const struct bt_data node_id_ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), - BT_DATA_BYTES(BT_DATA_UUID16_ALL, - BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)), - BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NODE_ID_LEN), -}; - -static const struct bt_data net_id_ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), - BT_DATA_BYTES(BT_DATA_UUID16_ALL, - BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)), - BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN), -}; - -static int node_id_adv(struct bt_mesh_subnet *sub) -{ - uint8_t tmp[16]; - int err; - - BT_DBG(""); - - proxy_svc_data[2] = ID_TYPE_NODE; - - err = bt_rand(proxy_svc_data + 11, 8); - if (err) { - return err; - } - - memset(tmp, 0, 6); - memcpy(tmp + 6, proxy_svc_data + 11, 8); - sys_put_be16(bt_mesh_primary_addr(), tmp + 14); - - err = bt_encrypt_be(sub->keys[SUBNET_KEY_TX_IDX(sub)].identity, tmp, - tmp); - if (err) { - return err; - } - - memcpy(proxy_svc_data + 3, tmp + 8, 8); - - err = bt_le_adv_start(&fast_adv_param, node_id_ad, - ARRAY_SIZE(node_id_ad), NULL, 0); - if (err) { - BT_WARN("Failed to advertise using Node ID (err %d)", err); - return err; - } - - proxy_adv_enabled = true; - - return 0; -} - -static int net_id_adv(struct bt_mesh_subnet *sub) -{ - int err; - - BT_DBG(""); - - proxy_svc_data[2] = ID_TYPE_NET; - - BT_DBG("Advertising with NetId %s", - bt_hex(sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8)); - - memcpy(proxy_svc_data + 3, sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8); - - err = bt_le_adv_start(&slow_adv_param, net_id_ad, - ARRAY_SIZE(net_id_ad), NULL, 0); - if (err) { - BT_WARN("Failed to advertise using Network ID (err %d)", err); - return err; - } - - proxy_adv_enabled = true; - - return 0; -} - -static bool advertise_subnet(struct bt_mesh_subnet *sub) -{ - if (sub->net_idx == BT_MESH_KEY_UNUSED) { - return false; - } - - return (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING || - bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED); -} - -static struct bt_mesh_subnet *next_sub(void) -{ - struct bt_mesh_subnet *sub = NULL; - - if (!beacon_sub) { - beacon_sub = bt_mesh_subnet_next(NULL); - if (!beacon_sub) { - /* No valid subnets */ - return NULL; - } - } - - sub = beacon_sub; - do { - if (advertise_subnet(sub)) { - beacon_sub = sub; - return sub; - } - - sub = bt_mesh_subnet_next(sub); - } while (sub != beacon_sub); - - /* No subnets to advertise on */ - - return NULL; -} - -static int sub_count_cb(struct bt_mesh_subnet *sub, void *cb_data) -{ - int *count = cb_data; - - if (advertise_subnet(sub)) { - (*count)++; - } - - return 0; -} - -static int sub_count(void) -{ - int count = 0; - - (void)bt_mesh_subnet_find(sub_count_cb, &count); - return count; -} - -static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) -{ - int32_t remaining = K_FOREVER; - int subnet_count; - - BT_DBG(""); - - if (conn_count == CONFIG_BT_MAX_CONN) { - BT_DBG("Connectable advertising deferred (max connections %d)", conn_count); - return -ENOMEM; - } - - sub = beacon_sub ? beacon_sub : bt_mesh_subnet_next(beacon_sub); - if (!sub) { - BT_WARN("No subnets to advertise on"); - return -ENOENT; - } - - if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) { - uint32_t active = k_uptime_get_32() - sub->node_id_start; - - if (active < NODE_ID_TIMEOUT) { - remaining = NODE_ID_TIMEOUT - active; - BT_DBG("Node ID active for %u ms, %d ms remaining", - (unsigned) active, (int) remaining); - node_id_adv(sub); - } else { - bt_mesh_proxy_identity_stop(sub); - BT_DBG("Node ID stopped"); - } - } - - if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) { - net_id_adv(sub); - } - - subnet_count = sub_count(); - BT_DBG("sub_count %u", subnet_count); - if (subnet_count > 1) { - int32_t max_timeout; - - /* We use NODE_ID_TIMEOUT as a starting point since it may - * be less than 60 seconds. Divide this period into at least - * 6 slices, but make sure that a slice is at least one - * second long (to avoid excessive rotation). - */ - max_timeout = NODE_ID_TIMEOUT / max(subnet_count, 6); - max_timeout = max(max_timeout, K_SECONDS(1)); - - if (remaining > max_timeout || remaining < 0) { - remaining = max_timeout; - } - } - - BT_DBG("Advertising %d ms for net_idx 0x%04x", - (int) remaining, sub->net_idx); - - beacon_sub = bt_mesh_subnet_next(beacon_sub); - - return remaining; -} -#endif /* GATT_PROXY */ - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) -static size_t gatt_prov_adv_create(struct bt_data prov_sd[2]) -{ - const struct bt_mesh_prov *prov = bt_mesh_prov_get(); - const char *name = CONFIG_BT_DEVICE_NAME; - size_t name_len = strlen(name); - size_t prov_sd_len = 0; - size_t sd_space = 31; - - memcpy(prov_svc_data + 2, prov->uuid, 16); - sys_put_be16(prov->oob_info, prov_svc_data + 18); - - if (prov->uri) { - size_t uri_len = strlen(prov->uri); - - if (uri_len > 29) { - /* There's no way to shorten an URI */ - BT_WARN("Too long URI to fit advertising packet"); - } else { - prov_sd[0].type = BT_DATA_URI; - prov_sd[0].data_len = uri_len; - prov_sd[0].data = (void *)prov->uri; - sd_space -= 2 + uri_len; - prov_sd_len++; - } - } - - if (sd_space > 2 && name_len > 0) { - sd_space -= 2; - - if (sd_space < name_len) { - prov_sd[prov_sd_len].type = BT_DATA_NAME_SHORTENED; - prov_sd[prov_sd_len].data_len = sd_space; - } else { - prov_sd[prov_sd_len].type = BT_DATA_NAME_COMPLETE; - prov_sd[prov_sd_len].data_len = name_len; - } - - prov_sd[prov_sd_len].data = (void *)name; - prov_sd_len++; - } - - return prov_sd_len; -} -#endif /* PB_GATT */ - -int32_t bt_mesh_proxy_adv_start(void) -{ - BT_DBG(""); - - if (gatt_svc == MESH_GATT_NONE) { - return K_FOREVER; - } - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) - if (!bt_mesh_is_provisioned()) { - const struct ble_gap_adv_params *param; - struct bt_data prov_sd[2]; - size_t prov_sd_len; - - if (prov_fast_adv) { - param = &fast_adv_param; - } else { - param = &slow_adv_param; - } - - prov_sd_len = gatt_prov_adv_create(prov_sd); - - if (bt_le_adv_start(param, prov_ad, ARRAY_SIZE(prov_ad), - prov_sd, prov_sd_len) == 0) { - proxy_adv_enabled = true; - - /* Advertise 60 seconds using fast interval */ - if (prov_fast_adv) { - prov_fast_adv = false; - return K_SECONDS(60); - } - } - } -#endif /* PB_GATT */ - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - if (bt_mesh_is_provisioned()) { - return gatt_proxy_advertise(next_sub()); - } -#endif /* GATT_PROXY */ - - return K_FOREVER; -} - -void bt_mesh_proxy_adv_stop(void) -{ - int err; - - BT_DBG("adv_enabled %u", proxy_adv_enabled); - - if (!proxy_adv_enabled) { - return; - } - - err = bt_le_adv_stop(true); - if (err) { - BT_ERR("Failed to stop advertising (err %d)", err); - } else { - proxy_adv_enabled = false; - } -} - -#if defined(CONFIG_BT_MESH_GATT_PROXY) -static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) -{ - if (evt == BT_MESH_KEY_DELETED) { - if (sub == beacon_sub) { - beacon_sub = NULL; - } - } else { - bt_mesh_proxy_beacon_send(sub); - } -} -#endif - -static void ble_mesh_handle_connect(struct ble_gap_event *event, void *arg) -{ -#if MYNEWT_VAL(BLE_EXT_ADV) - /* When EXT ADV is enabled then mesh proxy is connected - * when proxy advertising instance is completed. - * Therefore no need to handle BLE_GAP_EVENT_CONNECT - */ - if (event->type == BLE_GAP_EVENT_ADV_COMPLETE) { - /* Reason 0 means advertising has been completed because - * connection has been established - */ - if (event->adv_complete.reason != 0) { - return; - } - - if (event->adv_complete.instance != BT_MESH_ADV_GATT_INST) { - return; - } - - proxy_connected(event->adv_complete.conn_handle); - } -#else - if (event->type == BLE_GAP_EVENT_CONNECT) { - proxy_connected(event->connect.conn_handle); - } -#endif -} - -int ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg) -{ - if ((event->type == BLE_GAP_EVENT_CONNECT) || - (event->type == BLE_GAP_EVENT_ADV_COMPLETE)) { - ble_mesh_handle_connect(event, arg); - } else if (event->type == BLE_GAP_EVENT_DISCONNECT) { - proxy_disconnected(event->disconnect.conn.conn_handle, - event->disconnect.reason); - } else if (event->type == BLE_GAP_EVENT_SUBSCRIBE) { - if (event->subscribe.attr_handle == svc_handles.proxy_data_out_h) { -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - proxy_ccc_write(event->subscribe.conn_handle); -#endif - } else if (event->subscribe.attr_handle == - svc_handles.prov_data_out_h) { -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) - prov_ccc_write(event->subscribe.conn_handle); -#endif - } - } - - return 0; -} - -static int -dummy_access_cb(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - /* - * We should never never enter this callback - it's attached to notify-only - * characteristic which are notified directly from mbuf. And we can't pass - * NULL as access_cb because gatts will assert on init... - */ - BLE_HS_DBG_ASSERT(0); - return 0; -} - -static const struct ble_gatt_svc_def svc_defs [] = { - { - .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), - .characteristics = (struct ble_gatt_chr_def[]) { { - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_IN_VAL), - .access_cb = proxy_recv, - .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, - }, { - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_OUT_VAL), - .access_cb = dummy_access_cb, - .flags = BLE_GATT_CHR_F_NOTIFY, - }, { - 0, /* No more characteristics in this service. */ - } }, - }, { - .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), - .characteristics = (struct ble_gatt_chr_def[]) { { - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_IN_VAL), - .access_cb = proxy_recv, - .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, - }, { - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_OUT_VAL), - .access_cb = dummy_access_cb, - .flags = BLE_GATT_CHR_F_NOTIFY, - }, { - 0, /* No more characteristics in this service. */ - } }, - }, { - 0, /* No more services. */ - }, -}; - -int bt_mesh_proxy_svcs_register(void) -{ - int rc; - - rc = ble_gatts_count_cfg(svc_defs); - assert(rc == 0); - - rc = ble_gatts_add_svcs(svc_defs); - assert(rc == 0); - - return 0; -} - -int bt_mesh_proxy_init(void) -{ - int i; - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - if (!bt_mesh_subnet_cb_list[4]) { - bt_mesh_subnet_cb_list[4] = subnet_evt; - } -#endif - - for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) { -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - k_work_init(&clients[i].send_beacons, proxy_send_beacons); -#endif - clients[i].buf = NET_BUF_SIMPLE(CLIENT_BUF_SIZE); - clients[i].conn_handle = BLE_HS_CONN_HANDLE_NONE; - - k_delayed_work_init(&clients[i].sar_timer, proxy_sar_timeout); - k_delayed_work_add_arg(&clients[i].sar_timer, &clients[i]); - } - - resolve_svc_handles(); - - ble_gatts_svc_set_visibility(svc_handles.proxy_h, 0); - ble_gatts_svc_set_visibility(svc_handles.prov_h, 0); - - return 0; -} - -void bt_mesh_proxy_on_idle(struct bt_mesh_proxy_idle_cb *cb) -{ - if (!atomic_get(&pending_notifications)) { - cb->cb(); - return; - } - - sys_slist_append(&idle_waiters, &cb->n); -} - -#endif /* MYNEWT_VAL(BLE_MESH_PROXY) */ -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/proxy.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/proxy.h deleted file mode 100644 index 3764cc3ad..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/proxy.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __PROXY_H__ -#define __PROXY_H__ - -#define BT_MESH_PROXY_NET_PDU 0x00 -#define BT_MESH_PROXY_BEACON 0x01 -#define BT_MESH_PROXY_CONFIG 0x02 -#define BT_MESH_PROXY_PROV 0x03 - -#include "../include/mesh/mesh.h" -#include "../include/mesh/slist.h" - -struct bt_mesh_proxy_idle_cb { - sys_snode_t n; - void (*cb)(void); -}; - -int bt_mesh_proxy_send(uint16_t conn_handle, uint8_t type, struct os_mbuf *msg); - -int bt_mesh_proxy_prov_enable(void); -int bt_mesh_proxy_prov_disable(bool disconnect); - -int bt_mesh_proxy_gatt_enable(void); -int bt_mesh_proxy_gatt_disable(void); -void bt_mesh_proxy_gatt_disconnect(void); - -void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub); - -struct os_mbuf *bt_mesh_proxy_get_buf(void); - -int32_t bt_mesh_proxy_adv_start(void); -void bt_mesh_proxy_adv_stop(void); - -void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub); -void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub); - -bool bt_mesh_proxy_relay(struct os_mbuf *buf, uint16_t dst); -void bt_mesh_proxy_addr_add(struct os_mbuf *buf, uint16_t addr); - -int bt_mesh_proxy_init(void); -void bt_mesh_proxy_on_idle(struct bt_mesh_proxy_idle_cb *cb); - -int ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg); - -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/rpl.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/rpl.c deleted file mode 100644 index 5565ff685..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/rpl.c +++ /dev/null @@ -1,167 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * Copyright (c) 2020 Lingao Meng - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define MESH_LOG_MODULE BLE_MESH_RPL_LOG - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#include "nimble/porting/nimble/include/log/log.h" - -#include "mesh_priv.h" -#include "adv.h" -#include "net.h" -#include "rpl.h" -#include "settings.h" - -static struct bt_mesh_rpl replay_list[MYNEWT_VAL(BLE_MESH_CRPL)]; - -void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl, - struct bt_mesh_net_rx *rx) -{ - rpl->src = rx->ctx.addr; - rpl->seq = rx->seq; - rpl->old_iv = rx->old_iv; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_rpl(rpl); - } -} - -/* Check the Replay Protection List for a replay attempt. If non-NULL match - * parameter is given the RPL slot is returned but it is not immediately - * updated (needed for segmented messages), whereas if a NULL match is given - * the RPL is immediately updated (used for unsegmented messages). - */ -bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, - struct bt_mesh_rpl **match) -{ - int i; - - /* Don't bother checking messages from ourselves */ - if (rx->net_if == BT_MESH_NET_IF_LOCAL) { - return false; - } - - /* The RPL is used only for the local node */ - if (!rx->local_match) { - return false; - } - - for (i = 0; i < ARRAY_SIZE(replay_list); i++) { - struct bt_mesh_rpl *rpl = &replay_list[i]; - - /* Empty slot */ - if (!rpl->src) { - if (match) { - *match = rpl; - } else { - bt_mesh_rpl_update(rpl, rx); - } - - return false; - } - - /* Existing slot for given address */ - if (rpl->src == rx->ctx.addr) { - if (rx->old_iv && !rpl->old_iv) { - return true; - } - - if ((!rx->old_iv && rpl->old_iv) || - rpl->seq < rx->seq) { - if (match) { - *match = rpl; - } else { - bt_mesh_rpl_update(rpl, rx); - } - - return false; - } else { - return true; - } - } - } - - BT_ERR("RPL is full!"); - return true; -} - -void bt_mesh_rpl_clear(void) -{ - BT_DBG(""); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_clear_rpl(); - } else { - (void)memset(replay_list, 0, sizeof(replay_list)); - } -} - -struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(replay_list); i++) { - if (replay_list[i].src == src) { - return &replay_list[i]; - } - } - - return NULL; -} - -struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(replay_list); i++) { - if (!replay_list[i].src) { - replay_list[i].src = src; - return &replay_list[i]; - } - } - - return NULL; -} - -void bt_mesh_rpl_foreach(bt_mesh_rpl_func_t func, void *user_data) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(replay_list); i++) { - func(&replay_list[i], user_data); - } -} - -void bt_mesh_rpl_reset(void) -{ - int i; - - /* Discard "old old" IV Index entries from RPL and flag - * any other ones (which are valid) as old. - */ - for (i = 0; i < ARRAY_SIZE(replay_list); i++) { - struct bt_mesh_rpl *rpl = &replay_list[i]; - - if (rpl->src) { - if (rpl->old_iv) { - (void)memset(rpl, 0, sizeof(*rpl)); - } else { - rpl->old_iv = true; - } - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_rpl(rpl); - } - } - } -} - -#endif /* MYNEWT_VAL(BLE_MESH) */ \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/rpl.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/rpl.h deleted file mode 100644 index 0592712f8..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/rpl.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * Copyright (c) 2020 Lingao Meng - * - * SPDX-License-Identifier: Apache-2.0 - */ - -struct bt_mesh_rpl { - uint16_t src; - bool old_iv; -#if defined(CONFIG_BT_SETTINGS) - bool store; -#endif - uint32_t seq; -}; - -typedef void (*bt_mesh_rpl_func_t)(struct bt_mesh_rpl *rpl, - void *user_data); - -void bt_mesh_rpl_reset(void); -bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, - struct bt_mesh_rpl **match); -void bt_mesh_rpl_clear(void); -struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src); -struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src); -void bt_mesh_rpl_foreach(bt_mesh_rpl_func_t func, void *user_data); -void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl, - struct bt_mesh_net_rx *rx); \ No newline at end of file diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/settings.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/settings.c deleted file mode 100644 index 345a7d2df..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/settings.c +++ /dev/null @@ -1,2467 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#define MESH_LOG_MODULE BLE_MESH_SETTINGS_LOG - -#if MYNEWT_VAL(BLE_MESH_SETTINGS) - -#include "mesh_priv.h" -#include "../include/mesh/mesh.h" -#include "../include/mesh/glue.h" -#include "subnet.h" -#include "app_keys.h" -#include "net.h" -#include "rpl.h" -#include "crypto.h" -#include "transport.h" -#include "heartbeat.h" -#include "access.h" -#include "foundation.h" -#include "proxy.h" -#include "settings.h" -#include "lpn.h" -#include "cfg.h" - - -#include "config/config.h" - -/* Tracking of what storage changes are pending for App and Net Keys. We - * track this in a separate array here instead of within the respective - * bt_mesh_app_key and bt_mesh_subnet structs themselves, since once a key - * gets deleted its struct becomes invalid and may be reused for other keys. - */ -struct key_update { - uint16_t key_idx:12, /* AppKey or NetKey Index */ - valid:1, /* 1 if this entry is valid, 0 if not */ - app_key:1, /* 1 if this is an AppKey, 0 if a NetKey */ - clear:1; /* 1 if key needs clearing, 0 if storing */ -}; - -static struct key_update key_updates[CONFIG_BT_MESH_APP_KEY_COUNT + - CONFIG_BT_MESH_SUBNET_COUNT]; - -static struct k_delayed_work pending_store; - -/* Mesh network storage information */ -struct net_val { - uint16_t primary_addr; - uint8_t dev_key[16]; -} __packed; - -/* Sequence number storage */ -struct seq_val { - uint8_t val[3]; -} __packed; - -/* Heartbeat Publication storage */ -struct hb_pub_val { - uint16_t dst; - uint8_t period; - uint8_t ttl; - uint16_t feat; - uint16_t net_idx:12, - indefinite:1; -}; - -/* Miscelaneous configuration server model states */ -struct cfg_val { - uint8_t net_transmit; - uint8_t relay; - uint8_t relay_retransmit; - uint8_t beacon; - uint8_t gatt_proxy; - uint8_t frnd; - uint8_t default_ttl; -}; - -/* IV Index & IV Update storage */ -struct iv_val { - uint32_t iv_index; - uint8_t iv_update:1, - iv_duration:7; -} __packed; - -/* Replay Protection List storage */ -struct rpl_val { - uint32_t seq:24, - old_iv:1; -}; - -/* NetKey storage information */ -struct net_key_val { - uint8_t kr_flag:1, - kr_phase:7; - uint8_t val[2][16]; -} __packed; - -/* AppKey storage information */ -struct app_key_val { - uint16_t net_idx; - bool updated; - uint8_t val[2][16]; -} __packed; - -struct mod_pub_val { - uint16_t addr; - uint16_t key; - uint8_t ttl; - uint8_t retransmit; - uint8_t period; - uint8_t period_div:4, - cred:1; -}; - -/* Virtual Address information */ -struct va_val { - uint16_t ref; - uint16_t addr; - uint8_t uuid[16]; -} __packed; - -struct cdb_net_val { - uint32_t iv_index; - bool iv_update; -} __packed; - -/* Node storage information */ -struct node_val { - uint16_t net_idx; - uint8_t num_elem; - uint8_t flags; -#define F_NODE_CONFIGURED 0x01 - uint8_t uuid[16]; - uint8_t dev_key[16]; -} __packed; - -struct node_update { - uint16_t addr; - bool clear; -}; - -#if MYNEWT_VAL(BLE_MESH_CDB) -static struct node_update cdb_node_updates[MYNEWT_VAL(BLE_MESH_CDB_NODE_COUNT)]; -static struct key_update cdb_key_updates[ - MYNEWT_VAL(BLE_MESH_CDB_SUBNET_COUNT) + - MYNEWT_VAL(BLE_MESH_CDB_APP_KEY_COUNT)]; -#endif - -int settings_name_next(char *name, char **next) -{ - int rc = 0; - - if (next) { - *next = NULL; - } - - if (!name) { - return 0; - } - - /* name might come from flash directly, in flash the name would end - * with '=' or '\0' depending how storage is done. Flash reading is - * limited to what can be read - */ - while ((*name != '\0') && (*name != '=') && - (*name != '/')) { - rc++; - name++; - } - - if (*name == '/') { - if (next) { - *next = name + 1; - } - return rc; - } - - return rc; -} - -static int net_set(int argc, char **argv, char *val) -{ - struct net_val net; - int len, err; - - BT_DBG("val %s", val ? val : "(null)"); - - if (!val) { - bt_mesh_comp_unprovision(); - memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key)); - return 0; - } - - len = sizeof(net); - err = settings_bytes_from_str(val, &net, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(net)) { - BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(net)); - return -EINVAL; - } - - memcpy(bt_mesh.dev_key, net.dev_key, sizeof(bt_mesh.dev_key)); - bt_mesh_comp_provision(net.primary_addr); - - BT_DBG("Provisioned with primary address 0x%04x", net.primary_addr); - BT_DBG("Recovered DevKey %s", bt_hex(bt_mesh.dev_key, 16)); - - return 0; -} - -static int iv_set(int argc, char **argv, char *val) -{ - struct iv_val iv; - int len, err; - - BT_DBG("val %s", val ? val : "(null)"); - - if (!val) { - bt_mesh.iv_index = 0U; - atomic_clear_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS); - return 0; - } - - len = sizeof(iv); - err = settings_bytes_from_str(val, &iv, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(iv)) { - BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(iv)); - return -EINVAL; - } - - bt_mesh.iv_index = iv.iv_index; - atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, iv.iv_update); - bt_mesh.ivu_duration = iv.iv_duration; - - BT_DBG("IV Index 0x%04x (IV Update Flag %u) duration %u hours", - (unsigned) iv.iv_index, iv.iv_update, iv.iv_duration); - - return 0; -} - -static int seq_set(int argc, char **argv, char *val) -{ - struct seq_val seq; - int len, err; - - BT_DBG("val %s", val ? val : "(null)"); - - if (!val) { - bt_mesh.seq = 0; - return 0; - } - - len = sizeof(seq); - err = settings_bytes_from_str(val, &seq, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(seq)) { - BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(seq)); - return -EINVAL; - } - - bt_mesh.seq = sys_get_le24(seq.val); - - if (CONFIG_BT_MESH_SEQ_STORE_RATE > 0) { - /* Make sure we have a large enough sequence number. We - * subtract 1 so that the first transmission causes a write - * to the settings storage. - */ - bt_mesh.seq += (CONFIG_BT_MESH_SEQ_STORE_RATE - - (bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE)); - bt_mesh.seq--; - } - - BT_DBG("Sequence Number 0x%06x", bt_mesh.seq); - - return 0; -} - -static int rpl_set(int argc, char **argv, char *val) -{ - struct bt_mesh_rpl *entry; - struct rpl_val rpl; - int len, err; - uint16_t src; - - if (argc < 1) { - BT_ERR("Invalid argc (%d)", argc); - return -ENOENT; - } - - BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); - - src = strtol(argv[0], NULL, 16); - entry = bt_mesh_rpl_find(src); - - if (!val) { - if (entry) { - memset(entry, 0, sizeof(*entry)); - } else { - BT_WARN("Unable to find RPL entry for 0x%04x", src); - } - - return 0; - } - - if (!entry) { - entry = bt_mesh_rpl_alloc(src); - if (!entry) { - BT_ERR("Unable to allocate RPL entry for 0x%04x", src); - return -ENOMEM; - } - } - - len = sizeof(rpl); - err = settings_bytes_from_str(val, &rpl, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(rpl)) { - BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(rpl)); - return -EINVAL; - } - - entry->seq = rpl.seq; - entry->old_iv = rpl.old_iv; - - BT_DBG("RPL entry for 0x%04x: Seq 0x%06x old_iv %u", entry->src, - (unsigned) entry->seq, entry->old_iv); - - return 0; -} - -static int net_key_set(int argc, char **argv, char *val) -{ - struct net_key_val key; - int len, err; - uint16_t net_idx; - - BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); - - net_idx = strtol(argv[0], NULL, 16); - - len = sizeof(key); - err = settings_bytes_from_str(val, &key, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(key)) { - BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(key)); - return -EINVAL; - } - - BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); - - return bt_mesh_subnet_set( - net_idx, key.kr_phase, key.val[0], - (key.kr_phase != BT_MESH_KR_NORMAL) ? key.val[1] : NULL); -} - -static int app_key_set(int argc, char **argv, char *val) -{ - struct app_key_val key; - uint16_t app_idx; - int len_rd, err; - - BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); - - app_idx = strtol(argv[0], NULL, 16); - len_rd = strtol(argv[1], NULL, 16); - - if (!len_rd) { - return 0; - } - - err = settings_bytes_from_str(val, &key, &len_rd); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - err = bt_mesh_app_key_set(app_idx, key.net_idx, key.val[0], - key.updated ? key.val[1] : NULL); - if (err) { - BT_ERR("Failed to set \'app-key\'"); - return err; - } - - BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); - - return 0; -} - -static int hb_pub_set(int argc, char **argv, char *val) -{ - struct bt_mesh_hb_pub pub; - struct hb_pub_val hb_val; - int len, err; - - BT_DBG("val %s", val ? val : "(null)"); - - len = sizeof(hb_val); - err = settings_bytes_from_str(val, &hb_val, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(hb_val)) { - BT_ERR("Unexpected value length (%d != %zu)", len, - sizeof(hb_val)); - return -EINVAL; - } - - pub.dst = hb_val.dst; - pub.period = bt_mesh_hb_pwr2(hb_val.period); - pub.ttl = hb_val.ttl; - pub.feat = hb_val.feat; - pub.net_idx = hb_val.net_idx; - - if (hb_val.indefinite) { - pub.count = 0xffff; - } else { - pub.count = 0; - } - - (void)bt_mesh_hb_pub_set(&pub); - - BT_DBG("Restored heartbeat publication"); - - return 0; -} - -static int cfg_set(int argc, char **argv, char *val) -{ - struct cfg_val cfg; - int len, err; - - BT_DBG("val %s", val ? val : "(null)"); - - if (!val) { - BT_DBG("Cleared configuration state"); - return 0; - } - - len = sizeof(cfg); - err = settings_bytes_from_str(val, &cfg, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(cfg)) { - BT_ERR("Unexpected value length (%d != %zu)", len, - sizeof(cfg)); - return -EINVAL; - } - - bt_mesh_net_transmit_set(cfg.net_transmit); - bt_mesh_relay_set(cfg.relay, cfg.relay_retransmit); - bt_mesh_beacon_set(cfg.beacon); - bt_mesh_gatt_proxy_set(cfg.gatt_proxy); - bt_mesh_friend_set(cfg.frnd); - bt_mesh_default_ttl_set(cfg.default_ttl); - - BT_DBG("Restored configuration state"); - - return 0; -} - -static int mod_set_bind(struct bt_mesh_model *mod, char *val) -{ - int len, err, i; - - /* Start with empty array regardless of cleared or set value */ - for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { - mod->keys[i] = BT_MESH_KEY_UNUSED; - } - - if (!val) { - BT_DBG("Cleared bindings for model"); - return 0; - } - - len = sizeof(mod->keys); - err = settings_bytes_from_str(val, mod->keys, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; - } - - BT_DBG("Decoded %u bound keys for model", len / sizeof(mod->keys[0])); - return 0; -} - -static int mod_set_sub(struct bt_mesh_model *mod, char *val) -{ - int len, err; - - /* Start with empty array regardless of cleared or set value */ - memset(mod->groups, 0, sizeof(mod->groups)); - - if (!val) { - BT_DBG("Cleared subscriptions for model"); - return 0; - } - - len = sizeof(mod->groups); - err = settings_bytes_from_str(val, mod->groups, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; - } - - BT_DBG("Decoded %u subscribed group addresses for model", - len / sizeof(mod->groups[0])); - return 0; -} - -static int mod_set_pub(struct bt_mesh_model *mod, char *val) -{ - struct mod_pub_val pub; - int len, err; - - if (!mod->pub) { - BT_WARN("Model has no publication context!"); - return -EINVAL; - } - - if (!val) { - mod->pub->addr = BT_MESH_ADDR_UNASSIGNED; - mod->pub->key = 0; - mod->pub->cred = 0; - mod->pub->ttl = 0; - mod->pub->period = 0; - mod->pub->retransmit = 0; - mod->pub->count = 0; - - BT_DBG("Cleared publication for model"); - return 0; - } - - len = sizeof(pub); - err = settings_bytes_from_str(val, &pub, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; - } - - if (len != sizeof(pub)) { - BT_ERR("Invalid length for model publication"); - return -EINVAL; - } - - mod->pub->addr = pub.addr; - mod->pub->key = pub.key; - mod->pub->cred = pub.cred; - mod->pub->ttl = pub.ttl; - mod->pub->period = pub.period; - mod->pub->retransmit = pub.retransmit; - mod->pub->count = 0; - - BT_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x", - pub.addr, pub.key); - - return 0; -} - -static int mod_data_set(struct bt_mesh_model *mod, - char *name, char *len_rd) -{ - char *next; - - settings_name_next(name, &next); - - if (mod->cb && mod->cb->settings_set) { - return mod->cb->settings_set(mod, next, len_rd); - } - - return 0; -} - -static int mod_set(bool vnd, int argc, char **argv, char *val) -{ - struct bt_mesh_model *mod; - uint8_t elem_idx, mod_idx; - uint16_t mod_key; - - if (argc < 2) { - BT_ERR("Too small argc (%d)", argc); - return -ENOENT; - } - - mod_key = strtol(argv[0], NULL, 16); - elem_idx = mod_key >> 8; - mod_idx = mod_key; - - BT_DBG("Decoded mod_key 0x%04x as elem_idx %u mod_idx %u", - mod_key, elem_idx, mod_idx); - - mod = bt_mesh_model_get(vnd, elem_idx, mod_idx); - if (!mod) { - BT_ERR("Failed to get model for elem_idx %u mod_idx %u", - elem_idx, mod_idx); - return -ENOENT; - } - - if (!strcmp(argv[1], "bind")) { - return mod_set_bind(mod, val); - } - - if (!strcmp(argv[1], "sub")) { - return mod_set_sub(mod, val); - } - - if (!strcmp(argv[1], "pub")) { - return mod_set_pub(mod, val); - } - - if (!strcmp(argv[1], "data")) { - return mod_data_set(mod, argv[1], val); - } - - BT_WARN("Unknown module key %s", argv[1]); - return -ENOENT; -} - -static int sig_mod_set(int argc, char **argv, char *val) -{ - return mod_set(false, argc, argv, val); -} - -static int vnd_mod_set(int argc, char **argv, char *val) -{ - return mod_set(true, argc, argv, val); -} - -#if CONFIG_BT_MESH_LABEL_COUNT > 0 -static int va_set(int argc, char **argv, char *val) -{ - struct va_val va; - struct bt_mesh_va *lab; - uint16_t index; - int len, err; - - if (argc < 1) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - index = strtol(argv[0], NULL, 16); - - if (val == NULL) { - BT_WARN("Mesh Virtual Address length = 0"); - return 0; - } - - err = settings_bytes_from_str(val, &va, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; - } - - if (len != sizeof(struct va_val)) { - BT_ERR("Invalid length for virtual address"); - return -EINVAL; - } - - if (va.ref == 0) { - BT_WARN("Ignore Mesh Virtual Address ref = 0"); - return 0; - } - - lab = bt_mesh_va_get(index); - if (lab == NULL) { - BT_WARN("Out of labels buffers"); - return -ENOBUFS; - } - - memcpy(lab->uuid, va.uuid, 16); - lab->addr = va.addr; - lab->ref = va.ref; - - BT_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", - lab->addr, lab->ref); - - return 0; -} -#endif - -#if MYNEWT_VAL(BLE_MESH_CDB) -static int cdb_net_set(int argc, char *val) -{ - struct cdb_net_val net; - int len, err; - - len = sizeof(net); - err = settings_bytes_from_str(val, &net, &len); - if (err) { - BT_ERR("Failed to set \'cdb_net\'"); - return err; - } - - bt_mesh_cdb.iv_index = net.iv_index; - - if (net.iv_update) { - atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS); - } - - atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID); - - return 0; -} - -static int cdb_node_set(int argc, char *str) -{ - struct bt_mesh_cdb_node *node; - struct node_val val; - uint16_t addr; - int len, err; - - if (argc < 1) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - addr = strtol(str, NULL, 16); - len = sizeof(str); - - if (argc < 1) { - BT_DBG("val (null)"); - BT_DBG("Deleting node 0x%04x", addr); - - node = bt_mesh_cdb_node_get(addr); - if (node) { - bt_mesh_cdb_node_del(node, false); - } - - return 0; - } - - err = settings_bytes_from_str(str, &val, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; - } - - if (len != sizeof(struct node_val)) { - BT_ERR("Invalid length for node_val"); - return -EINVAL; - } - - node = bt_mesh_cdb_node_get(addr); - if (!node) { - node = bt_mesh_cdb_node_alloc(val.uuid, addr, val.num_elem, - val.net_idx); - } - - if (!node) { - BT_ERR("No space for a new node"); - return -ENOMEM; - } - - if (val.flags & F_NODE_CONFIGURED) { - atomic_set_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED); - } - - memcpy(node->uuid, val.uuid, 16); - memcpy(node->dev_key, val.dev_key, 16); - - BT_DBG("Node 0x%04x recovered from storage", addr); - - return 0; -} - -static int cdb_subnet_set(int argc, char *name) -{ - struct bt_mesh_cdb_subnet *sub; - struct net_key_val key; - uint16_t net_idx; - int len, len_rd, err; - - if (!name) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - len_rd = sizeof(sub); - net_idx = strtol(name, NULL, 16); - sub = bt_mesh_cdb_subnet_get(net_idx); - - if (len_rd == 0) { - BT_DBG("val (null)"); - if (!sub) { - BT_ERR("No subnet with NetKeyIndex 0x%03x", net_idx); - return -ENOENT; - } - - BT_DBG("Deleting NetKeyIndex 0x%03x", net_idx); - bt_mesh_cdb_subnet_del(sub, false); - return 0; - } - - len = sizeof(key); - err = settings_bytes_from_str(name, &key, &len); - if (err) { - BT_ERR("Failed to set \'net-key\'"); - return err; - } - - if (sub) { - BT_DBG("Updating existing NetKeyIndex 0x%03x", net_idx); - - sub->kr_flag = key.kr_flag; - sub->kr_phase = key.kr_phase; - memcpy(sub->keys[0].net_key, &key.val[0], 16); - memcpy(sub->keys[1].net_key, &key.val[1], 16); - - return 0; - } - - sub = bt_mesh_cdb_subnet_alloc(net_idx); - if (!sub) { - BT_ERR("No space to allocate a new subnet"); - return -ENOMEM; - } - - sub->kr_flag = key.kr_flag; - sub->kr_phase = key.kr_phase; - memcpy(sub->keys[0].net_key, &key.val[0], 16); - memcpy(sub->keys[1].net_key, &key.val[1], 16); - - BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); - - return 0; -} - -static int cdb_app_key_set(int argc, char *name) -{ - struct bt_mesh_cdb_app_key *app; - struct app_key_val key; - uint16_t app_idx; - int len_rd, err; - - app_idx = strtol(name, NULL, 16); - len_rd = sizeof(key); - - if (len_rd == 0) { - BT_DBG("val (null)"); - BT_DBG("Deleting AppKeyIndex 0x%03x", app_idx); - - app = bt_mesh_cdb_app_key_get(app_idx); - if (app) { - bt_mesh_cdb_app_key_del(app, false); - } - - return 0; - } - - err = settings_bytes_from_str(name, &key, &len_rd); - if (err) { - BT_ERR("Failed to set \'app-key\'"); - return err; - } - - app = bt_mesh_cdb_app_key_get(app_idx); - if (!app) { - app = bt_mesh_cdb_app_key_alloc(key.net_idx, app_idx); - } - - if (!app) { - BT_ERR("No space for a new app key"); - return -ENOMEM; - } - - memcpy(app->keys[0].app_key, key.val[0], 16); - memcpy(app->keys[1].app_key, key.val[1], 16); - - BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); - - return 0; -} - -static int cdb_set(int argc, char **argv, char *name) -{ - int len; - char *next; - - if (argc < 1) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - if (!strcmp(name, "Net")) { - return cdb_net_set(1, name); - } - - - len = settings_name_next(name, &next); - - if (!next) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - if (!strncmp(name, "Node", len)) { - return cdb_node_set(1, next); - } - - if (!strncmp(name, "Subnet", len)) { - return cdb_subnet_set(1, next); - } - - if (!strncmp(name, "AppKey", len)) { - return cdb_app_key_set(1, next); - } - - BT_WARN("Unknown module key %s", name); - return -ENOENT; -} -#endif - -const struct mesh_setting { - const char *name; - int (*func)(int argc, char **argv, char *val); -} settings[] = { - { "Net", net_set }, - { "IV", iv_set }, - { "Seq", seq_set }, - { "RPL", rpl_set }, - { "NetKey", net_key_set }, - { "AppKey", app_key_set }, - { "HBPub", hb_pub_set }, - { "Cfg", cfg_set }, - { "s", sig_mod_set }, - { "v", vnd_mod_set }, -#if CONFIG_BT_MESH_LABEL_COUNT > 0 - { "Va", va_set }, -#endif -#if MYNEWT_VAL(BLE_MESH_CDB) - { "cdb", cdb_set }, -#endif -}; - -static int mesh_set(int argc, char **argv, char *val) -{ - int i; - - if (argc < 1) { - BT_ERR("Insufficient number of arguments"); - return -EINVAL; - } - - BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); - - for (i = 0; i < ARRAY_SIZE(settings); i++) { - if (!strcmp(settings[i].name, argv[0])) { - argc--; - argv++; - - return settings[i].func(argc, argv, val); - } - } - - BT_WARN("No matching handler for key %s", argv[0]); - - return -ENOENT; -} - -static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, - bool vnd, bool primary, void *user_data) -{ - if (mod->pub && mod->pub->update && - mod->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int32_t ms = bt_mesh_model_pub_period_get(mod); - if (ms) { - BT_DBG("Starting publish timer (period %u ms)", - (unsigned) ms); - k_delayed_work_submit(&mod->pub->timer, ms); - } - } - - if (!IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - return; - } - - for (int i = 0; i < ARRAY_SIZE(mod->groups); i++) { - if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { - bt_mesh_lpn_group_add(mod->groups[i]); - } - } -} - -static int mesh_commit(void) -{ - if (!bt_mesh_subnet_next(NULL)) { - /* Nothing to do since we're not yet provisioned */ - return 0; - } - - if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { - bt_mesh_proxy_prov_disable(true); - } - - if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) { - k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); - } - - bt_mesh_model_foreach(commit_mod, NULL); - - atomic_set_bit(bt_mesh.flags, BT_MESH_VALID); - - bt_mesh_start(); - - return 0; -} - -/* Pending flags that use K_NO_WAIT as the storage timeout */ -#define NO_WAIT_PENDING_BITS (BIT(BT_MESH_NET_PENDING) | \ - BIT(BT_MESH_IV_PENDING) | \ - BIT(BT_MESH_SEQ_PENDING)) - -/* Pending flags that use CONFIG_BT_MESH_STORE_TIMEOUT */ -#define GENERIC_PENDING_BITS (BIT(BT_MESH_KEYS_PENDING) | \ - BIT(BT_MESH_HB_PUB_PENDING) | \ - BIT(BT_MESH_CFG_PENDING) | \ - BIT(BT_MESH_MOD_PENDING)) - -static void schedule_store(int flag) -{ - int32_t timeout, remaining; - - atomic_set_bit(bt_mesh.flags, flag); - - if (atomic_get(bt_mesh.flags) & NO_WAIT_PENDING_BITS) { - timeout = K_NO_WAIT; - } else if (atomic_test_bit(bt_mesh.flags, BT_MESH_RPL_PENDING) && - (!(atomic_get(bt_mesh.flags) & GENERIC_PENDING_BITS) || - (CONFIG_BT_MESH_RPL_STORE_TIMEOUT < - CONFIG_BT_MESH_STORE_TIMEOUT))) { - timeout = K_SECONDS(CONFIG_BT_MESH_RPL_STORE_TIMEOUT); - } else { - timeout = K_SECONDS(CONFIG_BT_MESH_STORE_TIMEOUT); - } - - remaining = k_delayed_work_remaining_get(&pending_store); - if (remaining && remaining < timeout) { - BT_DBG("Not rescheduling due to existing earlier deadline"); - return; - } - - BT_DBG("Waiting %d seconds", (int) (timeout / MSEC_PER_SEC)); - - k_delayed_work_submit(&pending_store, timeout); -} - -static void clear_iv(void) -{ - int err; - - err = settings_save_one("bt_mesh/IV", NULL); - if (err) { - BT_ERR("Failed to clear IV"); - } else { - BT_DBG("Cleared IV"); - } -} - -static void clear_net(void) -{ - int err; - - err = settings_save_one("bt_mesh/Net", NULL); - if (err) { - BT_ERR("Failed to clear Network"); - } else { - BT_DBG("Cleared Network"); - } -} - -static void store_pending_net(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct net_val))]; - struct net_val net; - char *str; - int err; - - BT_DBG("addr 0x%04x DevKey %s", bt_mesh_primary_addr(), - bt_hex(bt_mesh.dev_key, 16)); - - net.primary_addr = bt_mesh_primary_addr(); - memcpy(net.dev_key, bt_mesh.dev_key, 16); - - str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode Network as value"); - return; - } - - BT_DBG("Saving Network as value %s", str); - err = settings_save_one("bt_mesh/Net", str); - if (err) { - BT_ERR("Failed to store Network"); - } else { - BT_DBG("Stored Network"); - } -} - -void bt_mesh_store_net(void) -{ - schedule_store(BT_MESH_NET_PENDING); -} - -static void store_pending_iv(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct iv_val))]; - struct iv_val iv; - char *str; - int err; - - iv.iv_index = bt_mesh.iv_index; - iv.iv_update = atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS); - iv.iv_duration = bt_mesh.ivu_duration; - - str = settings_str_from_bytes(&iv, sizeof(iv), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode IV as value"); - return; - } - - BT_DBG("Saving IV as value %s", str); - err = settings_save_one("bt_mesh/IV", str); - if (err) { - BT_ERR("Failed to store IV"); - } else { - BT_DBG("Stored IV"); - } -} - -void bt_mesh_store_iv(bool only_duration) -{ - schedule_store(BT_MESH_IV_PENDING); - - if (!only_duration) { - /* Always update Seq whenever IV changes */ - schedule_store(BT_MESH_SEQ_PENDING); - } -} - -static void store_pending_seq(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct seq_val))]; - struct seq_val seq; - char *str; - int err; - - sys_put_le24(bt_mesh.seq, seq.val); - - str = settings_str_from_bytes(&seq, sizeof(seq), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode Seq as value"); - return; - } - - BT_DBG("Saving Seq as value %s", str); - err = settings_save_one("bt_mesh/Seq", str); - if (err) { - BT_ERR("Failed to store Seq"); - } else { - BT_DBG("Stored Seq"); - } -} - -void bt_mesh_store_seq(void) -{ - if (CONFIG_BT_MESH_SEQ_STORE_RATE && - (bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE)) { - return; - } - - schedule_store(BT_MESH_SEQ_PENDING); -} - -static void store_rpl(struct bt_mesh_rpl *entry) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct rpl_val))]; - struct rpl_val rpl; - char path[18]; - char *str; - int err; - - BT_DBG("src 0x%04x seq 0x%06x old_iv %u", entry->src, - (unsigned) entry->seq, entry->old_iv); - - rpl.seq = entry->seq; - rpl.old_iv = entry->old_iv; - - str = settings_str_from_bytes(&rpl, sizeof(rpl), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode RPL as value"); - return; - } - - snprintk(path, sizeof(path), "bt_mesh/RPL/%x", entry->src); - - BT_DBG("Saving RPL %s as value %s", path, str); - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store RPL"); - } else { - BT_DBG("Stored RPL"); - } -} - -static void clear_rpl(struct bt_mesh_rpl *rpl, void *user_data) -{ - int err; - char path[18]; - - if (!rpl->src) { - return; - } - - snprintk(path, sizeof(path), "bt/mesh/RPL/%x", rpl->src); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear RPL"); - } else { - BT_DBG("Cleared RPL"); - } - - (void)memset(rpl, 0, sizeof(*rpl)); -} - -static void store_pending_rpl(struct bt_mesh_rpl *rpl, void *user_data) -{ - BT_DBG(""); - - if (rpl->store) { - rpl->store = false; - store_rpl(rpl); - } -} - -static void store_pending_hb_pub(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct hb_pub_val))]; - struct bt_mesh_hb_pub pub; - struct hb_pub_val val; - char *str; - int err; - - bt_mesh_hb_pub_get(&pub); - if (pub.dst == BT_MESH_ADDR_UNASSIGNED) { - str = NULL; - } else { - val.indefinite = (pub.count == 0xffff); - val.dst = pub.dst; - val.period = bt_mesh_hb_log(pub.period); - val.ttl = pub.ttl; - val.feat = pub.feat; - val.net_idx = pub.net_idx; - - str = settings_str_from_bytes(&val, sizeof(val), - buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode hb pub as value"); - return; - } - } - - BT_DBG("Saving Heartbeat Publication as value %s", - str ? str : "(null)"); - err = settings_save_one("bt_mesh/HBPub", str); - if (err) { - BT_ERR("Failed to store Heartbeat Publication"); - } else { - BT_DBG("Stored Heartbeat Publication"); - } -} - -static void store_pending_cfg(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct cfg_val))]; - struct cfg_val val; - char *str; - int err; - - val.net_transmit = bt_mesh_net_transmit_get(); - val.relay = bt_mesh_relay_get(); - val.relay_retransmit = bt_mesh_relay_retransmit_get(); - val.beacon = bt_mesh_beacon_enabled(); - val.gatt_proxy = bt_mesh_gatt_proxy_get(); - val.frnd = bt_mesh_friend_get(); - val.default_ttl = bt_mesh_default_ttl_get(); - - str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode configuration as value"); - return; - } - - BT_DBG("Saving configuration as value %s", str); - err = settings_save_one("bt_mesh/Cfg", str); - if (err) { - BT_ERR("Failed to store configuration"); - } else { - BT_DBG("Stored configuration"); - } -} - -static void clear_cfg(void) -{ - int err; - - err = settings_save_one("bt_mesh/Cfg", NULL); - if (err) { - BT_ERR("Failed to clear configuration"); - } else { - BT_DBG("Cleared configuration"); - } -} - -static void clear_app_key(uint16_t app_idx) -{ - char path[20]; - int err; - - BT_DBG("AppKeyIndex 0x%03x", app_idx); - - snprintk(path, sizeof(path), "bt_mesh/AppKey/%x", app_idx); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear AppKeyIndex 0x%03x", app_idx); - } else { - BT_DBG("Cleared AppKeyIndex 0x%03x", app_idx); - } -} - -static void clear_net_key(uint16_t net_idx) -{ - char path[20]; - int err; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - snprintk(path, sizeof(path), "bt_mesh/NetKey/%x", net_idx); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear NetKeyIndex 0x%03x", net_idx); - } else { - BT_DBG("Cleared NetKeyIndex 0x%03x", net_idx); - } -} - -static void store_subnet(uint16_t net_idx) -{ - const struct bt_mesh_subnet *sub; - struct net_key_val key; - char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; - char path[20]; - char *str; - int err; - - sub = bt_mesh_subnet_get(net_idx); - if (!sub) { - BT_WARN("NetKeyIndex 0x%03x not found", net_idx); - return; - } - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - snprintk(path, sizeof(path), "bt/mesh/NetKey/%x", net_idx); - - memcpy(&key.val[0], sub->keys[0].net, 16); - memcpy(&key.val[1], sub->keys[1].net, 16); - key.kr_flag = 0U; /* Deprecated */ - key.kr_phase = sub->kr_phase; - - str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode AppKey as value"); - return; - } - - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store NetKey"); - } else { - BT_DBG("Stored NetKey"); - } -} - -static void store_app(uint16_t app_idx) -{ - const struct bt_mesh_app_key *app; - char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; - struct app_key_val key; - char path[20]; - char *str; - int err; - - snprintk(path, sizeof(path), "bt/mesh/AppKey/%x", app_idx); - - app = bt_mesh_app_key_get(app_idx); - if (!app) { - BT_WARN("ApKeyIndex 0x%03x not found", app_idx); - return; - } - - key.net_idx = app->net_idx, - key.updated = app->updated, - - memcpy(key.val[0], app->keys[0].val, 16); - memcpy(key.val[1], app->keys[1].val, 16); - - str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode AppKey as value"); - return; - } - - snprintk(path, sizeof(path), "bt_mesh/AppKey/%x", app->app_idx); - - BT_DBG("Saving AppKey %s as value %s", path, str); - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store AppKey"); - } else { - BT_DBG("Stored AppKey"); - } -} - -static void store_pending_keys(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(key_updates); i++) { - struct key_update *update = &key_updates[i]; - - if (!update->valid) { - continue; - } - - if (update->clear) { - if (update->app_key) { - clear_app_key(update->key_idx); - } else { - clear_net_key(update->key_idx); - } - } else { - store_subnet(update->key_idx); - } - - update->valid = 0; - } -} - -#if MYNEWT_VAL(BLE_MESH_CDB) -static void clear_cdb(void) -{ - int err; - - err = settings_save_one("bt/mesh/cdb/Net", NULL); - if (err) { - BT_ERR("Failed to clear Network"); - } else { - BT_DBG("Cleared Network"); - } -} - -static void store_pending_cdb(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct cdb_net_val))]; - struct cdb_net_val net; - int err; - char *str; - - BT_DBG(""); - - net.iv_index = bt_mesh_cdb.iv_index; - net.iv_update = atomic_test_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_IVU_IN_PROGRESS); - - str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode Network as value"); - return; - } - err = settings_save_one("bt/mesh/cdb/Net", str); - if (err) { - BT_ERR("Failed to store Network value"); - } else { - BT_DBG("Stored Network value"); - } -} - -static void store_cdb_node(const struct bt_mesh_cdb_node *node) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct node_val))]; - struct node_val val; - char path[30]; - char *str; - int err; - - val.net_idx = node->net_idx; - val.num_elem = node->num_elem; - val.flags = 0; - - if (atomic_test_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED)) { - val.flags |= F_NODE_CONFIGURED; - } - - memcpy(val.uuid, node->uuid, 16); - memcpy(val.dev_key, node->dev_key, 16); - - snprintk(path, sizeof(path), "bt/mesh/cdb/Node/%x", node->addr); - - str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode Node as value"); - return; - } - - - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store Node %s value", path); - } else { - BT_DBG("Stored Node %s value", path); - } -} - -static void clear_cdb_node(uint16_t addr) -{ - char path[30]; - int err; - - BT_DBG("Node 0x%04x", addr); - - snprintk(path, sizeof(path), "bt/mesh/cdb/Node/%x", addr); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear Node 0x%04x", addr); - } else { - BT_DBG("Cleared Node 0x%04x", addr); - } -} - -static void store_pending_cdb_nodes(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cdb_node_updates); ++i) { - struct node_update *update = &cdb_node_updates[i]; - - if (update->addr == BT_MESH_ADDR_UNASSIGNED) { - continue; - } - - BT_DBG("addr: 0x%04x, clear: %d", update->addr, update->clear); - - if (update->clear) { - clear_cdb_node(update->addr); - } else { - struct bt_mesh_cdb_node *node; - - node = bt_mesh_cdb_node_get(update->addr); - if (node) { - store_cdb_node(node); - } else { - BT_WARN("Node 0x%04x not found", update->addr); - } - } - - update->addr = BT_MESH_ADDR_UNASSIGNED; - } -} - -static void store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct net_key_val))]; - struct net_key_val key; - char path[30]; - int err; - char *str; - - BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, - bt_hex(sub->keys[0].net_key, 16)); - - memcpy(&key.val[0], sub->keys[0].net_key, 16); - memcpy(&key.val[1], sub->keys[1].net_key, 16); - key.kr_flag = sub->kr_flag; - key.kr_phase = sub->kr_phase; - - snprintk(path, sizeof(path), "bt/mesh/cdb/Subnet/%x", sub->net_idx); - - - str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode Subnet as value"); - return; - } - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store Subnet value"); - } else { - BT_DBG("Stored Subnet value"); - } -} - -static void clear_cdb_subnet(uint16_t net_idx) -{ - char path[30]; - int err; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - snprintk(path, sizeof(path), "bt/mesh/cdb/Subnet/%x", net_idx); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear NetKeyIndex 0x%03x", net_idx); - } else { - BT_DBG("Cleared NetKeyIndex 0x%03x", net_idx); - } -} - -static void store_cdb_app_key(const struct bt_mesh_cdb_app_key *app) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; - struct app_key_val key; - char path[30]; - int err; - char *str; - - key.net_idx = app->net_idx; - key.updated = false; - memcpy(key.val[0], app->keys[0].app_key, 16); - memcpy(key.val[1], app->keys[1].app_key, 16); - - snprintk(path, sizeof(path), "bt/mesh/cdb/AppKey/%x", app->app_idx); - - str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store AppKey"); - } else { - BT_DBG("Stored AppKey"); - } -} - -static void clear_cdb_app_key(uint16_t app_idx) -{ - char path[30]; - int err; - - snprintk(path, sizeof(path), "bt/mesh/cdb/AppKey/%x", app_idx); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear AppKeyIndex 0x%03x", app_idx); - } else { - BT_DBG("Cleared AppKeyIndex 0x%03x", app_idx); - } -} - -static void store_pending_cdb_keys(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) { - struct key_update *update = &cdb_key_updates[i]; - - if (!update->valid) { - continue; - } - - if (update->clear) { - if (update->app_key) { - clear_cdb_app_key(update->key_idx); - } else { - clear_cdb_subnet(update->key_idx); - } - } else { - if (update->app_key) { - struct bt_mesh_cdb_app_key *key; - - key = bt_mesh_cdb_app_key_get(update->key_idx); - if (key) { - store_cdb_app_key(key); - } else { - BT_WARN("AppKeyIndex 0x%03x not found", - update->key_idx); - } - } else { - struct bt_mesh_cdb_subnet *sub; - - sub = bt_mesh_cdb_subnet_get(update->key_idx); - if (sub) { - store_cdb_subnet(sub); - } else { - BT_WARN("NetKeyIndex 0x%03x not found", - update->key_idx); - } - } - } - - update->valid = 0U; - } -} - -static struct node_update *cdb_node_update_find(uint16_t addr, - struct node_update **free_slot) -{ - struct node_update *match; - int i; - - match = NULL; - *free_slot = NULL; - - for (i = 0; i < ARRAY_SIZE(cdb_node_updates); i++) { - struct node_update *update = &cdb_node_updates[i]; - - if (update->addr == BT_MESH_ADDR_UNASSIGNED) { - *free_slot = update; - continue; - } - - if (update->addr == addr) { - match = update; - } - } - - return match; -} -#endif - -static void encode_mod_path(struct bt_mesh_model *mod, bool vnd, - const char *key, char *path, size_t path_len) -{ - uint16_t mod_key = (((uint16_t)mod->elem_idx << 8) | mod->mod_idx); - - if (vnd) { - snprintk(path, path_len, "bt_mesh/v/%x/%s", mod_key, key); - } else { - snprintk(path, path_len, "bt_mesh/s/%x/%s", mod_key, key); - } -} - -static void store_pending_mod_bind(struct bt_mesh_model *mod, bool vnd) -{ - uint16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT]; - char buf[BT_SETTINGS_SIZE(sizeof(keys))]; - char path[20]; - int i, count, err; - char *val; - - for (i = 0, count = 0; i < ARRAY_SIZE(mod->keys); i++) { - if (mod->keys[i] != BT_MESH_KEY_UNUSED) { - keys[count++] = mod->keys[i]; - } - } - - if (count) { - val = settings_str_from_bytes(keys, count * sizeof(keys[0]), - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model bindings as value"); - return; - } - } else { - val = NULL; - } - - encode_mod_path(mod, vnd, "bind", path, sizeof(path)); - - BT_DBG("Saving %s as %s", path, val ? val : "(null)"); - err = settings_save_one(path, val); - if (err) { - BT_ERR("Failed to store bind"); - } else { - BT_DBG("Stored bind"); - } -} - -static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd) -{ - uint16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT]; - char buf[BT_SETTINGS_SIZE(sizeof(groups))]; - char path[20]; - int i, count, err; - char *val; - - for (i = 0, count = 0; i < CONFIG_BT_MESH_MODEL_GROUP_COUNT; i++) { - if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { - groups[count++] = mod->groups[i]; - } - } - - if (count) { - val = settings_str_from_bytes(groups, count * sizeof(groups[0]), - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model subscription as value"); - return; - } - } else { - val = NULL; - } - - encode_mod_path(mod, vnd, "sub", path, sizeof(path)); - - BT_DBG("Saving %s as %s", path, val ? val : "(null)"); - err = settings_save_one(path, val); - if (err) { - BT_ERR("Failed to store sub"); - } else { - BT_DBG("Stored sub"); - } -} - -static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct mod_pub_val))]; - struct mod_pub_val pub; - char path[20]; - char *val; - int err; - - if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - val = NULL; - } else { - pub.addr = mod->pub->addr; - pub.key = mod->pub->key; - pub.ttl = mod->pub->ttl; - pub.retransmit = mod->pub->retransmit; - pub.period = mod->pub->period; - pub.period_div = mod->pub->period_div; - pub.cred = mod->pub->cred; - - val = settings_str_from_bytes(&pub, sizeof(pub), - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model publication as value"); - return; - } - } - - encode_mod_path(mod, vnd, "pub", path, sizeof(path)); - - BT_DBG("Saving %s as %s", path, val ? val : "(null)"); - err = settings_save_one(path, val); - if (err) { - BT_ERR("Failed to store pub"); - } else { - BT_DBG("Stored pub"); - } -} - -static void store_pending_mod(struct bt_mesh_model *mod, - struct bt_mesh_elem *elem, bool vnd, - bool primary, void *user_data) -{ - if (!mod->flags) { - return; - } - - if (mod->flags & BT_MESH_MOD_BIND_PENDING) { - mod->flags &= ~BT_MESH_MOD_BIND_PENDING; - store_pending_mod_bind(mod, vnd); - } - - if (mod->flags & BT_MESH_MOD_SUB_PENDING) { - mod->flags &= ~BT_MESH_MOD_SUB_PENDING; - store_pending_mod_sub(mod, vnd); - } - - if (mod->flags & BT_MESH_MOD_PUB_PENDING) { - mod->flags &= ~BT_MESH_MOD_PUB_PENDING; - store_pending_mod_pub(mod, vnd); - } -} - -#define IS_VA_DEL(_label) ((_label)->ref == 0) -static void store_pending_va(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct va_val))]; - struct bt_mesh_va *lab; - struct va_val va; - char path[18]; - char *val; - uint16_t i; - int err = 0; - - for (i = 0; (lab = bt_mesh_va_get(i)) != NULL; i++) { - if (!lab->changed) { - continue; - } - - lab->changed = 0U; - - snprintk(path, sizeof(path), "bt_mesh/Va/%x", i); - - if (IS_VA_DEL(lab)) { - val = NULL; - } else { - va.ref = lab->ref; - va.addr = lab->addr; - memcpy(va.uuid, lab->uuid, 16); - - val = settings_str_from_bytes(&va, sizeof(va), - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model publication as value"); - return; - } - - err = settings_save_one(path, val); - } - - if (err) { - BT_ERR("Failed to %s %s value (err %d)", - IS_VA_DEL(lab) ? "delete" : "store", path, err); - } else { - BT_DBG("%s %s value", - IS_VA_DEL(lab) ? "Deleted" : "Stored", path); - } - } -} - -static void store_pending(struct ble_npl_event *work) -{ - BT_DBG(""); - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_RPL_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_rpl_foreach(store_pending_rpl, NULL); - } else { - bt_mesh_rpl_foreach(clear_rpl, NULL); - } - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_KEYS_PENDING)) { - store_pending_keys(); - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_NET_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - store_pending_net(); - } else { - clear_net(); - } - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_IV_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - store_pending_iv(); - } else { - clear_iv(); - } - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_SEQ_PENDING)) { - store_pending_seq(); - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_HB_PUB_PENDING)) { - store_pending_hb_pub(); - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_CFG_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - store_pending_cfg(); - } else { - clear_cfg(); - } - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_MOD_PENDING)) { - bt_mesh_model_foreach(store_pending_mod, NULL); - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_VA_PENDING)) { - store_pending_va(); - } - -#if MYNEWT_VAL(BLE_MESH_CDB) - if (IS_ENABLED(CONFIG_BT_MESH_CDB)) { - if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_SUBNET_PENDING)) { - if (atomic_test_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_VALID)) { - store_pending_cdb(); - } else { - clear_cdb(); - } - } - - if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_NODES_PENDING)) { - store_pending_cdb_nodes(); - } - - if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_KEYS_PENDING)) { - store_pending_cdb_keys(); - } - } -#endif -} - -void bt_mesh_store_rpl(struct bt_mesh_rpl *entry) -{ - entry->store = true; - schedule_store(BT_MESH_RPL_PENDING); -} - -static struct key_update *key_update_find(bool app_key, uint16_t key_idx, - struct key_update **free_slot) -{ - struct key_update *match; - int i; - - match = NULL; - *free_slot = NULL; - - for (i = 0; i < ARRAY_SIZE(key_updates); i++) { - struct key_update *update = &key_updates[i]; - - if (!update->valid) { - *free_slot = update; - continue; - } - - if (update->app_key != app_key) { - continue; - } - - if (update->key_idx == key_idx) { - match = update; - } - } - - return match; -} - -void bt_mesh_store_subnet(uint16_t net_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - update = key_update_find(false, net_idx, &free_slot); - if (update) { - update->clear = 0; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_subnet(net_idx); - return; - } - - free_slot->valid = 1; - free_slot->key_idx = net_idx; - free_slot->app_key = 0; - free_slot->clear = 0; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_store_app_key(uint16_t app_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", app_idx); - - update = key_update_find(true, app_idx, &free_slot); - if (update) { - update->clear = 0; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_app(app_idx); - return; - } - - free_slot->valid = 1; - free_slot->key_idx = app_idx; - free_slot->app_key = 1; - free_slot->clear = 0; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_store_hb_pub(void) -{ - schedule_store(BT_MESH_HB_PUB_PENDING); -} - -void bt_mesh_store_cfg(void) -{ - schedule_store(BT_MESH_CFG_PENDING); -} - -void bt_mesh_clear_net(void) -{ - schedule_store(BT_MESH_NET_PENDING); - schedule_store(BT_MESH_IV_PENDING); - schedule_store(BT_MESH_CFG_PENDING); -} - -void bt_mesh_clear_subnet(uint16_t net_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - update = key_update_find(false, net_idx, &free_slot); - if (update) { - update->clear = 1; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_net_key(net_idx); - return; - } - - free_slot->valid = 1; - free_slot->key_idx = net_idx; - free_slot->app_key = 0; - free_slot->clear = 1; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_clear_app_key(uint16_t app_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", app_idx); - - update = key_update_find(true, app_idx, &free_slot); - if (update) { - update->clear = 1; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_app_key(app_idx); - return; - } - - free_slot->valid = 1; - free_slot->key_idx = app_idx; - free_slot->app_key = 1; - free_slot->clear = 1; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_clear_rpl(void) -{ - schedule_store(BT_MESH_RPL_PENDING); -} - -void bt_mesh_store_mod_bind(struct bt_mesh_model *mod) -{ - mod->flags |= BT_MESH_MOD_BIND_PENDING; - schedule_store(BT_MESH_MOD_PENDING); -} - -void bt_mesh_store_mod_sub(struct bt_mesh_model *mod) -{ - mod->flags |= BT_MESH_MOD_SUB_PENDING; - schedule_store(BT_MESH_MOD_PENDING); -} - -void bt_mesh_store_mod_pub(struct bt_mesh_model *mod) -{ - mod->flags |= BT_MESH_MOD_PUB_PENDING; - schedule_store(BT_MESH_MOD_PENDING); -} - - -void bt_mesh_store_label(void) -{ - schedule_store(BT_MESH_VA_PENDING); -} - -#if MYNEWT_VAL(BLE_MESH_CDB) -static void schedule_cdb_store(int flag) -{ - atomic_set_bit(bt_mesh_cdb.flags, flag); - k_delayed_work_submit(&pending_store, K_NO_WAIT); -} - -void bt_mesh_store_cdb(void) -{ - schedule_cdb_store(BT_MESH_CDB_SUBNET_PENDING); -} - -void bt_mesh_store_cdb_node(const struct bt_mesh_cdb_node *node) -{ - struct node_update *update, *free_slot; - - BT_DBG("Node 0x%04x", node->addr); - - update = cdb_node_update_find(node->addr, &free_slot); - if (update) { - update->clear = false; - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); - return; - } - - if (!free_slot) { - store_cdb_node(node); - return; - } - - free_slot->addr = node->addr; - free_slot->clear = false; - - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); -} - -void bt_mesh_clear_cdb_node(struct bt_mesh_cdb_node *node) -{ - struct node_update *update, *free_slot; - - BT_DBG("Node 0x%04x", node->addr); - - update = cdb_node_update_find(node->addr, &free_slot); - if (update) { - update->clear = true; - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); - return; - } - - if (!free_slot) { - clear_cdb_node(node->addr); - return; - } - - free_slot->addr = node->addr; - free_slot->clear = true; - - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); -} - -/* TODO: Could be shared with key_update_find? */ -static struct key_update *cdb_key_update_find(bool app_key, uint16_t key_idx, - struct key_update **free_slot) -{ - struct key_update *match; - int i; - - match = NULL; - *free_slot = NULL; - - for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) { - struct key_update *update = &cdb_key_updates[i]; - - if (!update->valid) { - *free_slot = update; - continue; - } - - if (update->app_key != app_key) { - continue; - } - - if (update->key_idx == key_idx) { - match = update; - } - } - - return match; -} - -void bt_mesh_store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); - - update = cdb_key_update_find(false, sub->net_idx, &free_slot); - if (update) { - update->clear = 0U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_cdb_subnet(sub); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = sub->net_idx; - free_slot->app_key = 0U; - free_slot->clear = 0U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} - -void bt_mesh_clear_cdb_subnet(struct bt_mesh_cdb_subnet *sub) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); - - update = cdb_key_update_find(false, sub->net_idx, &free_slot); - if (update) { - update->clear = 1U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_cdb_subnet(sub->net_idx); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = sub->net_idx; - free_slot->app_key = 0U; - free_slot->clear = 1U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} - -void bt_mesh_store_cdb_app_key(const struct bt_mesh_cdb_app_key *key) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); - - update = cdb_key_update_find(true, key->app_idx, &free_slot); - if (update) { - update->clear = 0U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_cdb_app_key(key); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = key->app_idx; - free_slot->app_key = 1U; - free_slot->clear = 0U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} - -void bt_mesh_clear_cdb_app_key(struct bt_mesh_cdb_app_key *key) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); - - update = cdb_key_update_find(true, key->app_idx, &free_slot); - if (update) { - update->clear = 1U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_cdb_app_key(key->app_idx); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = key->app_idx; - free_slot->app_key = 1U; - free_slot->clear = 1U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} -#endif - -int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, - const char *name, const void *data, - size_t data_len) -{ - char path[30]; - char buf[BT_SETTINGS_SIZE(sizeof(struct mod_pub_val))]; - char *val; - int err; - - encode_mod_path(mod, vnd, "data", path, sizeof(path)); - if (name) { - strcat(path, "/"); - strncat(path, name, 8); - } - - if (data_len) { - val = settings_str_from_bytes(data, data_len, - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model publication as value"); - return -EINVAL; - } - err = settings_save_one(path, val); - } else { - err = settings_save_one(path, NULL); - } - - if (err) { - BT_ERR("Failed to store %s value", path); - } else { - BT_DBG("Stored %s value", path); - } - return err; -} - -static struct conf_handler bt_mesh_settings_conf_handler = { - .ch_name = "bt_mesh", - .ch_get = NULL, - .ch_set = mesh_set, - .ch_commit = mesh_commit, - .ch_export = NULL, -}; - -void bt_mesh_settings_init(void) -{ - int rc; - - rc = conf_register(&bt_mesh_settings_conf_handler); - - SYSINIT_PANIC_ASSERT_MSG(rc == 0, - "Failed to register bt_mesh_settings conf"); - - k_delayed_work_init(&pending_store, store_pending); -} - -#endif /* MYNEWT_VAL(BLE_MESH_SETTINGS) */ -#endif diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/settings.h b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/settings.h deleted file mode 100644 index 9060a14a7..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/settings.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -void bt_mesh_store_net(void); -void bt_mesh_store_iv(bool only_duration); -void bt_mesh_store_seq(void); -void bt_mesh_store_rpl(struct bt_mesh_rpl *rpl); -void bt_mesh_store_subnet(uint16_t net_idx); -void bt_mesh_store_app_key(uint16_t app_idx); -void bt_mesh_store_hb_pub(void); -void bt_mesh_store_cfg(void); -void bt_mesh_store_mod_bind(struct bt_mesh_model *mod); -void bt_mesh_store_mod_sub(struct bt_mesh_model *mod); -void bt_mesh_store_mod_pub(struct bt_mesh_model *mod); -void bt_mesh_store_label(void); -void bt_mesh_store_cdb(void); -void bt_mesh_store_cdb_node(const struct bt_mesh_cdb_node *node); -void bt_mesh_store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub); -void bt_mesh_store_cdb_app_key(const struct bt_mesh_cdb_app_key *app); - -void bt_mesh_clear_net(void); -void bt_mesh_clear_subnet(uint16_t net_idx); -void bt_mesh_clear_app_key(uint16_t app_idx); -void bt_mesh_clear_rpl(void); -void bt_mesh_clear_cdb_node(struct bt_mesh_cdb_node *node); -void bt_mesh_clear_cdb_subnet(struct bt_mesh_cdb_subnet *sub); -void bt_mesh_clear_cdb_app_key(struct bt_mesh_cdb_app_key *app); - -void bt_mesh_settings_init(void); diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/shell.c b/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/shell.c deleted file mode 100644 index f8951b827..000000000 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimble/nimble/host/mesh/src/shell.c +++ /dev/null @@ -1,3690 +0,0 @@ -/** @file - * @brief Bluetooth Mesh shell - * - */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "nimble/porting/nimble/include/syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_MESH) - -#if MYNEWT_VAL(BLE_MESH_SHELL) - -#include -#include -#include -#include "shell/shell.h" -#include "console/console.h" -#include "mesh/mesh.h" -#include "mesh/main.h" -#include "mesh/glue.h" -#include "mesh/testing.h" - -/* Private includes for raw Network & Transport layer access */ -#include "net.h" -#include "rpl.h" -#include "access.h" -#include "mesh_priv.h" -#include "lpn.h" -#include "transport.h" -#include "foundation.h" -#include "settings.h" - -#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS) -#include "mesh/model_srv.h" -#include "mesh/model_cli.h" -#include "light_model.h" -#endif - -/* This should be higher priority (lower value) than main task priority */ -#define BLE_MESH_SHELL_TASK_PRIO 126 -#define BLE_MESH_SHELL_STACK_SIZE 768 - -OS_TASK_STACK_DEFINE(g_blemesh_shell_stack, BLE_MESH_SHELL_STACK_SIZE); - -struct os_task mesh_shell_task; -static struct os_eventq mesh_shell_queue; - -#define CID_NVAL 0xffff -#define CID_VENDOR 0x05C3 - -/* Vendor Model data */ -#define VND_MODEL_ID_1 0x1234 - -/* Default net, app & dev key values, unless otherwise specified */ -static const uint8_t default_key[16] = { - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, -}; - -static struct { - uint16_t local; - uint16_t dst; - uint16_t net_idx; - uint16_t app_idx; -} net = { - .local = BT_MESH_ADDR_UNASSIGNED, - .dst = BT_MESH_ADDR_UNASSIGNED, -}; - -#define CUR_FAULTS_MAX 4 - -static uint8_t cur_faults[CUR_FAULTS_MAX]; -static uint8_t reg_faults[CUR_FAULTS_MAX * 2]; - -static void get_faults(uint8_t *faults, uint8_t faults_size, uint8_t *dst, uint8_t *count) -{ - uint8_t i, limit = *count; - - for (i = 0, *count = 0; i < faults_size && *count < limit; i++) { - if (faults[i]) { - *dst++ = faults[i]; - (*count)++; - } - } -} - -static int fault_get_cur(struct bt_mesh_model *model, uint8_t *test_id, - uint16_t *company_id, uint8_t *faults, uint8_t *fault_count) -{ - printk("Sending current faults\n"); - - *test_id = 0x00; - *company_id = CID_VENDOR; - - get_faults(cur_faults, sizeof(cur_faults), faults, fault_count); - - return 0; -} - -static int fault_get_reg(struct bt_mesh_model *model, uint16_t cid, - uint8_t *test_id, uint8_t *faults, uint8_t *fault_count) -{ - if (cid != CID_VENDOR) { - printk("Faults requested for unknown Company ID 0x%04x\n", cid); - return -EINVAL; - } - - printk("Sending registered faults\n"); - - *test_id = 0x00; - - get_faults(reg_faults, sizeof(reg_faults), faults, fault_count); - - return 0; -} - -static int fault_clear(struct bt_mesh_model *model, uint16_t cid) -{ - if (cid != CID_VENDOR) { - return -EINVAL; - } - - memset(reg_faults, 0, sizeof(reg_faults)); - - return 0; -} - -static int fault_test(struct bt_mesh_model *model, uint8_t test_id, - uint16_t cid) -{ - if (cid != CID_VENDOR) { - return -EINVAL; - } - - if (test_id != 0x00) { - return -EINVAL; - } - - return 0; -} - -static const struct bt_mesh_health_srv_cb health_srv_cb = { - .fault_get_cur = fault_get_cur, - .fault_get_reg = fault_get_reg, - .fault_clear = fault_clear, - .fault_test = fault_test, -}; - -static struct bt_mesh_health_srv health_srv = { - .cb = &health_srv_cb, -}; - -static struct bt_mesh_model_pub health_pub; - -static void -health_pub_init(void) -{ - health_pub.msg = BT_MESH_HEALTH_FAULT_MSG(CUR_FAULTS_MAX); -} -#if MYNEWT_VAL(BLE_MESH_CFG_CLI) - -static struct bt_mesh_cfg_cli cfg_cli = { -}; - -#endif /* MYNEWT_VAL(BLE_MESH_CFG_CLI) */ - -#if MYNEWT_VAL(BLE_MESH_HEALTH_CLI) -void show_faults(uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count) -{ - size_t i; - - if (!fault_count) { - printk("Health Test ID 0x%02x Company ID 0x%04x: no faults\n", - test_id, cid); - return; - } - - printk("Health Test ID 0x%02x Company ID 0x%04x Fault Count %zu:\n", - test_id, cid, fault_count); - - for (i = 0; i < fault_count; i++) { - printk("\t0x%02x\n", faults[i]); - } -} - -static void health_current_status(struct bt_mesh_health_cli *cli, uint16_t addr, - uint8_t test_id, uint16_t cid, uint8_t *faults, - size_t fault_count) -{ - printk("Health Current Status from 0x%04x\n", addr); - show_faults(test_id, cid, faults, fault_count); -} - -static struct bt_mesh_health_cli health_cli = { - .current_status = health_current_status, -}; - -#endif /* MYNEWT_VAL(BLE_MESH_HEALTH_CLI) */ - -#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS) -static struct bt_mesh_gen_model_cli gen_onoff_cli; -static struct bt_mesh_model_pub gen_onoff_cli_pub; -static struct bt_mesh_model_pub gen_onoff_srv_pub; -static struct bt_mesh_gen_model_cli gen_level_cli; -static struct bt_mesh_model_pub gen_level_cli_pub; -static struct bt_mesh_model_pub gen_level_srv_pub; -static struct bt_mesh_model_pub light_lightness_pub; -static struct bt_mesh_gen_onoff_srv gen_onoff_srv = { - .get = light_model_gen_onoff_get, - .set = light_model_gen_onoff_set, -}; -static struct bt_mesh_gen_level_srv gen_level_srv = { - .get = light_model_gen_level_get, - .set = light_model_gen_level_set, -}; -static struct bt_mesh_light_lightness_srv light_lightness_srv = { - .get = light_model_light_lightness_get, - .set = light_model_light_lightness_set, -}; - -void bt_mesh_set_gen_onoff_srv_cb(int (*get)(struct bt_mesh_model *model, uint8_t *state), - int (*set)(struct bt_mesh_model *model, uint8_t state)) -{ - gen_onoff_srv.get = get; - gen_onoff_srv.set = set; -} - -void bt_mesh_set_gen_level_srv_cb(int (*get)(struct bt_mesh_model *model, int16_t *level), - int (*set)(struct bt_mesh_model *model, int16_t level)) -{ - gen_level_srv.get = get; - gen_level_srv.set = set; -} - -void bt_mesh_set_light_lightness_srv_cb(int (*get)(struct bt_mesh_model *model, int16_t *level), - int (*set)(struct bt_mesh_model *model, int16_t level)) -{ - light_lightness_srv.get = get; - light_lightness_srv.set = set; -} -#endif - -static struct bt_mesh_model root_models[] = { - BT_MESH_MODEL_CFG_SRV, - BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), -#if MYNEWT_VAL(BLE_MESH_CFG_CLI) - BT_MESH_MODEL_CFG_CLI(&cfg_cli), -#endif -#if MYNEWT_VAL(BLE_MESH_HEALTH_CLI) - BT_MESH_MODEL_HEALTH_CLI(&health_cli), -#endif -#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS) - BT_MESH_MODEL_GEN_ONOFF_SRV(&gen_onoff_srv, &gen_onoff_srv_pub), - BT_MESH_MODEL_GEN_ONOFF_CLI(&gen_onoff_cli, &gen_onoff_cli_pub), - BT_MESH_MODEL_GEN_LEVEL_SRV(&gen_level_srv, &gen_level_srv_pub), - BT_MESH_MODEL_GEN_LEVEL_CLI(&gen_level_cli, &gen_level_cli_pub), - BT_MESH_MODEL_LIGHT_LIGHTNESS_SRV(&light_lightness_srv, &light_lightness_pub), -#endif -}; - -static struct bt_mesh_model vnd_models[] = { - BT_MESH_MODEL_VND(CID_VENDOR, VND_MODEL_ID_1, - BT_MESH_MODEL_NO_OPS, NULL, NULL), -}; - -static struct bt_mesh_elem elements[] = { - BT_MESH_ELEM(0, root_models, vnd_models), -}; - -static const struct bt_mesh_comp comp = { - .cid = CID_VENDOR, - .elem = elements, - .elem_count = ARRAY_SIZE(elements), -}; - -static uint8_t hex2val(char c) -{ - if (c >= '0' && c <= '9') { - return c - '0'; - } else if (c >= 'a' && c <= 'f') { - return c - 'a' + 10; - } else if (c >= 'A' && c <= 'F') { - return c - 'A' + 10; - } else { - return 0; - } -} - -int char2hex(char c, uint8_t *x) -{ - if (c >= '0' && c <= '9') { - *x = c - '0'; - } else if (c >= 'a' && c <= 'f') { - *x = c - 'a' + 10; - } else if (c >= 'A' && c <= 'F') { - *x = c - 'A' + 10; - } else { - return -EINVAL; - } - - return 0; -} - -int hex2char(uint8_t x, char *c) -{ - if (x <= 9) { - *c = x + '0'; - } else if (x <= 15) { - *c = x - 10 + 'a'; - } else { - return -EINVAL; - } - - return 0; -} - -size_t bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen) -{ - if ((hexlen + 1) < buflen * 2) { - return 0; - } - - for (size_t i = 0; i < buflen; i++) { - if (hex2char(buf[i] >> 4, &hex[2 * i]) < 0) { - return 0; - } - if (hex2char(buf[i] & 0xf, &hex[2 * i + 1]) < 0) { - return 0; - } - } - - hex[2 * buflen] = '\0'; - return 2 * buflen; -} - -static size_t hex2bin(const char *hex, uint8_t *bin, size_t bin_len) -{ - size_t len = 0; - - while (*hex && len < bin_len) { - bin[len] = hex2val(*hex++) << 4; - - if (!*hex) { - len++; - break; - } - - bin[len++] |= hex2val(*hex++); - } - - return len; -} - -static void prov_complete(uint16_t net_idx, uint16_t addr) -{ - printk("Local node provisioned, net_idx 0x%04x address 0x%04x\n", - net_idx, addr); - net.local = addr; - net.net_idx = net_idx, - net.dst = addr; -} - -static void prov_node_added(uint16_t net_idx, uint8_t uuid[16], uint16_t addr, - uint8_t num_elem) -{ - printk("Node provisioned, net_idx 0x%04x address " - "0x%04x elements %d", net_idx, addr, num_elem); - - net.net_idx = net_idx, - net.dst = addr; -} - -static void prov_input_complete(void) -{ - printk("Input complete"); -} - -static void prov_reset(void) -{ - printk("The local node has been reset and needs reprovisioning\n"); -} - -static int output_number(bt_mesh_output_action_t action, uint32_t number) -{ - printk("OOB Number: %lu\n", number); - return 0; -} - -static int output_string(const char *str) -{ - printk("OOB String: %s\n", str); - return 0; -} - -static bt_mesh_input_action_t input_act; -static uint8_t input_size; - -static int cmd_input_num(int argc, char *argv[]) -{ - int err; - - if (argc < 2) { - return -EINVAL; - } - - if (input_act != BT_MESH_ENTER_NUMBER) { - printk("A number hasn't been requested!\n"); - return 0; - } - - if (strlen(argv[1]) < input_size) { - printk("Too short input (%u digits required)\n", - input_size); - return 0; - } - - err = bt_mesh_input_number(strtoul(argv[1], NULL, 10)); - if (err) { - printk("Numeric input failed (err %d)\n", err); - return 0; - } - - input_act = BT_MESH_NO_INPUT; - return 0; -} - -struct shell_cmd_help cmd_input_num_help = { - NULL, "", NULL -}; - -static int cmd_input_str(int argc, char *argv[]) -{ - int err; - - if (argc < 2) { - return -EINVAL; - } - - if (input_act != BT_MESH_ENTER_STRING) { - printk("A string hasn't been requested!\n"); - return 0; - } - - if (strlen(argv[1]) < input_size) { - printk("Too short input (%u characters required)\n", - input_size); - return 0; - } - - err = bt_mesh_input_string(argv[1]); - if (err) { - printk("String input failed (err %d)\n", err); - return 0; - } - - input_act = BT_MESH_NO_INPUT; - return 0; -} - -struct shell_cmd_help cmd_input_str_help = { - NULL, "", NULL -}; - -static int input(bt_mesh_input_action_t act, uint8_t size) -{ - switch (act) { - case BT_MESH_ENTER_NUMBER: - printk("Enter a number (max %u digits) with: input-num \n", - size); - break; - case BT_MESH_ENTER_STRING: - printk("Enter a string (max %u chars) with: input-str \n", - size); - break; - default: - printk("Unknown input action %u (size %u) requested!\n", - act, size); - return -EINVAL; - } - - input_act = act; - input_size = size; - return 0; -} - -static const char *bearer2str(bt_mesh_prov_bearer_t bearer) -{ - switch (bearer) { - case BT_MESH_PROV_ADV: - return "PB-ADV"; - case BT_MESH_PROV_GATT: - return "PB-GATT"; - default: - return "unknown"; - } -} - -static void link_open(bt_mesh_prov_bearer_t bearer) -{ - printk("Provisioning link opened on %s\n", bearer2str(bearer)); -} - -static void link_close(bt_mesh_prov_bearer_t bearer) -{ - printk("Provisioning link closed on %s\n", bearer2str(bearer)); -} - -static uint8_t dev_uuid[16] = MYNEWT_VAL(BLE_MESH_DEV_UUID); - -static uint8_t static_val[16]; - -static struct bt_mesh_prov prov = { - .uuid = dev_uuid, - .link_open = link_open, - .link_close = link_close, - .complete = prov_complete, - .node_added = prov_node_added, - .reset = prov_reset, - .static_val = NULL, - .static_val_len = 0, - .output_size = MYNEWT_VAL(BLE_MESH_OOB_OUTPUT_SIZE), - .output_actions = MYNEWT_VAL(BLE_MESH_OOB_OUTPUT_ACTIONS), - .output_number = output_number, - .output_string = output_string, - .input_size = MYNEWT_VAL(BLE_MESH_OOB_INPUT_SIZE), - .input_actions = MYNEWT_VAL(BLE_MESH_OOB_INPUT_ACTIONS), - .input = input, - .input_complete = prov_input_complete, -}; - -static int cmd_static_oob(int argc, char *argv[]) -{ - if (argc < 2) { - prov.static_val = NULL; - prov.static_val_len = 0; - } else { - prov.static_val_len = hex2bin(argv[1], static_val, 16); - if (prov.static_val_len) { - prov.static_val = static_val; - } else { - prov.static_val = NULL; - } - } - - if (prov.static_val) { - printk("Static OOB value set (length %u)\n", - prov.static_val_len); - } else { - printk("Static OOB value cleared\n"); - } - - return 0; -} - -struct shell_cmd_help cmd_static_oob_help = { - NULL, "[val: 1-16 hex values]", NULL -}; - -static int cmd_uuid(int argc, char *argv[]) -{ - uint8_t uuid[16]; - size_t len; - - if (argc < 2) { - return -EINVAL; - } - - len = hex2bin(argv[1], uuid, sizeof(uuid)); - if (len < 1) { - return -EINVAL; - } - - memcpy(dev_uuid, uuid, len); - memset(dev_uuid + len, 0, sizeof(dev_uuid) - len); - - printk("Device UUID set\n"); - - return 0; -} - -struct shell_cmd_help cmd_uuid_help = { - NULL, "", NULL -}; - -static int cmd_reset(int argc, char *argv[]) -{ - uint16_t addr; - if (argc < 2) { - return -EINVAL; - } - - addr = strtoul(argv[1], NULL, 0); - - if (addr == net.local) { - bt_mesh_reset(); - printk("Local node reset complete"); - } else { - int err; - bool reset = false; - - err = bt_mesh_cfg_node_reset(net.net_idx, net.dst, &reset); - if (err) { - printk("Unable to send " - "Remote Node Reset (err %d)", err); - return 0; - } - - printk("Remote node reset complete"); - } - - return 0; -} - -struct shell_cmd_help cmd_reset_help = { - NULL, "", NULL -}; - -static uint8_t str2u8(const char *str) -{ - if (isdigit(str[0])) { - return strtoul(str, NULL, 0); - } - - return (!strcmp(str, "on") || !strcmp(str, "enable")); -} - -static bool str2bool(const char *str) -{ - return str2u8(str); -} - -#if MYNEWT_VAL(BLE_MESH_LOW_POWER) -static int cmd_lpn(int argc, char *argv[]) -{ - static bool enabled; - int err; - - if (argc < 2) { - printk("%s\n", enabled ? "enabled" : "disabled"); - return 0; - } - - if (str2bool(argv[1])) { - if (enabled) { - printk("LPN already enabled\n"); - return 0; - } - - err = bt_mesh_lpn_set(true); - if (err) { - printk("Enabling LPN failed (err %d)\n", err); - } else { - enabled = true; - } - } else { - if (!enabled) { - printk("LPN already disabled\n"); - return 0; - } - - err = bt_mesh_lpn_set(false); - if (err) { - printk("Enabling LPN failed (err %d)\n", err); - } else { - enabled = false; - } - } - - return 0; -} - -static int cmd_poll(int argc, char *argv[]) -{ - int err; - - err = bt_mesh_lpn_poll(); - if (err) { - printk("Friend Poll failed (err %d)\n", err); - } - - return 0; -} - -static void lpn_cb(uint16_t friend_addr, bool established) -{ - if (established) { - printk("Friendship (as LPN) established to Friend 0x%04x\n", - friend_addr); - } else { - printk("Friendship (as LPN) lost with Friend 0x%04x\n", - friend_addr); - } -} - -struct shell_cmd_help cmd_lpn_help = { - NULL, "", NULL -}; - -#endif /* MESH_LOW_POWER */ - -static int check_pub_addr_unassigned(void) -{ -#ifdef ARCH_sim - return 0; -#else - uint8_t zero_addr[BLE_DEV_ADDR_LEN] = { 0 }; - - return memcmp(MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), - zero_addr, BLE_DEV_ADDR_LEN) == 0; -#endif -} - -int cmd_mesh_init(int argc, char *argv[]) -{ - int err; - ble_addr_t addr; - - if (check_pub_addr_unassigned()) { - /* Use NRPA */ - err = ble_hs_id_gen_rnd(1, &addr); - assert(err == 0); - err = ble_hs_id_set_rnd(addr.val); - assert(err == 0); - - err = bt_mesh_init(addr.type, &prov, &comp); - } - else { - err = bt_mesh_init(0, &prov, &comp); - } - - if (err) { - printk("Mesh initialization failed (err %d)\n", err); - } - - printk("Mesh initialized\n"); - - if (IS_ENABLED(CONFIG_SETTINGS)) { - settings_load(); - } - - if (bt_mesh_is_provisioned()) { - printk("Mesh network restored from flash\n"); - } else { - printk("Use \"pb-adv on\" or \"pb-gatt on\" to enable" - " advertising\n"); - } - -#if MYNEWT_VAL(BLE_MESH_LOW_POWER) - bt_mesh_lpn_set_cb(lpn_cb); -#endif - - return 0; -} - -#if MYNEWT_VAL(BLE_MESH_GATT_PROXY) -static int cmd_ident(int argc, char *argv[]) -{ - int err; - - err = bt_mesh_proxy_identity_enable(); - if (err) { - printk("Failed advertise using Node Identity (err %d)\n", err); - } - - return 0; -} -#endif /* MESH_GATT_PROXY */ - -static int cmd_dst(int argc, char *argv[]) -{ - if (argc < 2) { - printk("Destination address: 0x%04x%s\n", net.dst, - net.dst == net.local ? " (local)" : ""); - return 0; - } - - if (!strcmp(argv[1], "local")) { - net.dst = net.local; - } else { - net.dst = strtoul(argv[1], NULL, 0); - } - - printk("Destination address set to 0x%04x%s\n", net.dst, - net.dst == net.local ? " (local)" : ""); - return 0; -} - -struct shell_cmd_help cmd_dst_help = { - NULL, "[destination address]", NULL -}; - -static int cmd_netidx(int argc, char *argv[]) -{ - if (argc < 2) { - printk("NetIdx: 0x%04x\n", net.net_idx); - return 0; - } - - net.net_idx = strtoul(argv[1], NULL, 0); - printk("NetIdx set to 0x%04x\n", net.net_idx); - return 0; -} - -struct shell_cmd_help cmd_netidx_help = { - NULL, "[NetIdx]", NULL -}; - -static int cmd_appidx(int argc, char *argv[]) -{ - if (argc < 2) { - printk("AppIdx: 0x%04x\n", net.app_idx); - return 0; - } - - net.app_idx = strtoul(argv[1], NULL, 0); - printk("AppIdx set to 0x%04x\n", net.app_idx); - return 0; -} - -struct shell_cmd_help cmd_appidx_help = { - NULL, "[AppIdx]", NULL -}; - -static int cmd_net_send(int argc, char *argv[]) -{ - struct os_mbuf *msg = NET_BUF_SIMPLE(32); - struct bt_mesh_msg_ctx ctx = { - .send_ttl = BT_MESH_TTL_DEFAULT, - .net_idx = net.net_idx, - .addr = net.dst, - .app_idx = net.app_idx, - - }; - struct bt_mesh_net_tx tx = { - .ctx = &ctx, - .src = net.local, - }; - size_t len; - int err = 0; - - if (argc < 2) { - err = -EINVAL; - goto done; - } - - net_buf_simple_init(msg, 0); - len = hex2bin(argv[1], msg->om_data, net_buf_simple_tailroom(msg) - 4); - net_buf_simple_add(msg, len); - - err = bt_mesh_trans_send(&tx, msg, NULL, NULL); - if (err) { - printk("Failed to send (err %d)\n", err); - } - -done: - os_mbuf_free_chain(msg); - return err; -} - -struct shell_cmd_help cmd_net_send_help = { - NULL, "", NULL -}; - -static int cmd_rpl_clear(int argc, char *argv[]) -{ - bt_mesh_rpl_clear(); - return 0; -} - -#if MYNEWT_VAL(BLE_MESH_LOW_POWER) -static int cmd_lpn_subscribe(int argc, char *argv[]) -{ - uint16_t address; - - if (argc < 2) { - return -EINVAL; - } - - address = strtoul(argv[1], NULL, 0); - - printk("address 0x%04x", address); - - bt_mesh_lpn_group_add(address); - - return 0; -} - -struct shell_cmd_help cmd_lpn_subscribe_help = { - NULL, "", NULL -}; - -static int cmd_lpn_unsubscribe(int argc, char *argv[]) -{ - uint16_t address; - - if (argc < 2) { - return -EINVAL; - } - - address = strtoul(argv[1], NULL, 0); - - printk("address 0x%04x", address); - - bt_mesh_lpn_group_del(&address, 1); - - return 0; -} - -struct shell_cmd_help cmd_lpn_unsubscribe_help = { - NULL, "", NULL -}; -#endif - -#if MYNEWT_VAL(BLE_MESH_IV_UPDATE_TEST) -static int cmd_iv_update(int argc, char *argv[]) -{ - if (bt_mesh_iv_update()) { - printk("Transitioned to IV Update In Progress state\n"); - } else { - printk("Transitioned to IV Update Normal state\n"); - } - - printk("IV Index is 0x%08lx\n", bt_mesh.iv_index); - - return 0; -} - -static int cmd_iv_update_test(int argc, char *argv[]) -{ - bool enable; - - if (argc < 2) { - return -EINVAL; - } - - enable = str2bool(argv[1]); - if (enable) { - printk("Enabling IV Update test mode\n"); - } else { - printk("Disabling IV Update test mode\n"); - } - - bt_mesh_iv_update_test(enable); - - return 0; -} - -struct shell_cmd_help cmd_iv_update_test_help = { - NULL, "", NULL -}; -#endif - -#if MYNEWT_VAL(BLE_MESH_CFG_CLI) - -int cmd_timeout(int argc, char *argv[]) -{ - int32_t timeout; - - if (argc < 2) { - timeout = bt_mesh_cfg_cli_timeout_get(); - if (timeout == K_FOREVER) { - printk("Message timeout: forever\n"); - } else { - printk("Message timeout: %lu seconds\n", - timeout / 1000); - } - - return 0; - } - - timeout = strtol(argv[1], NULL, 0); - if (timeout < 0 || timeout > (INT32_MAX / 1000)) { - timeout = K_FOREVER; - } else { - timeout = timeout * 1000; - } - - bt_mesh_cfg_cli_timeout_set(timeout); - if (timeout == K_FOREVER) { - printk("Message timeout: forever\n"); - } else { - printk("Message timeout: %lu seconds\n", - timeout / 1000); - } - - return 0; -} - -struct shell_cmd_help cmd_timeout_help = { - NULL, "[timeout in seconds]", NULL -}; - - -static int cmd_get_comp(int argc, char *argv[]) -{ - struct os_mbuf *comp = NET_BUF_SIMPLE(32); - uint8_t status, page = 0x00; - int err = 0; - - if (argc > 1) { - page = strtol(argv[1], NULL, 0); - } - - net_buf_simple_init(comp, 0); - err = bt_mesh_cfg_comp_data_get(net.net_idx, net.dst, page, - &status, comp); - if (err) { - printk("Getting composition failed (err %d)\n", err); - goto done; - } - - if (status != 0x00) { - printk("Got non-success status 0x%02x\n", status); - goto done; - } - - printk("Got Composition Data for 0x%04x:\n", net.dst); - printk("\tCID 0x%04x\n", net_buf_simple_pull_le16(comp)); - printk("\tPID 0x%04x\n", net_buf_simple_pull_le16(comp)); - printk("\tVID 0x%04x\n", net_buf_simple_pull_le16(comp)); - printk("\tCRPL 0x%04x\n", net_buf_simple_pull_le16(comp)); - printk("\tFeatures 0x%04x\n", net_buf_simple_pull_le16(comp)); - - while (comp->om_len > 4) { - uint8_t sig, vnd; - uint16_t loc; - int i; - - loc = net_buf_simple_pull_le16(comp); - sig = net_buf_simple_pull_u8(comp); - vnd = net_buf_simple_pull_u8(comp); - - printk("\n\tElement @ 0x%04x:\n", loc); - - if (comp->om_len < ((sig * 2) + (vnd * 4))) { - printk("\t\t...truncated data!\n"); - break; - } - - if (sig) { - printk("\t\tSIG Models:\n"); - } else { - printk("\t\tNo SIG Models\n"); - } - - for (i = 0; i < sig; i++) { - uint16_t mod_id = net_buf_simple_pull_le16(comp); - - printk("\t\t\t0x%04x\n", mod_id); - } - - if (vnd) { - printk("\t\tVendor Models:\n"); - } else { - printk("\t\tNo Vendor Models\n"); - } - - for (i = 0; i < vnd; i++) { - uint16_t cid = net_buf_simple_pull_le16(comp); - uint16_t mod_id = net_buf_simple_pull_le16(comp); - - printk("\t\t\tCompany 0x%04x: 0x%04x\n", cid, mod_id); - } - } - -done: - os_mbuf_free_chain(comp); - return err; -} - -struct shell_cmd_help cmd_get_comp_help = { - NULL, "[page]", NULL -}; - -static int cmd_beacon(int argc, char *argv[]) -{ - uint8_t status; - int err; - - if (argc < 2) { - err = bt_mesh_cfg_beacon_get(net.net_idx, net.dst, &status); - } else { - uint8_t val = str2u8(argv[1]); - - err = bt_mesh_cfg_beacon_set(net.net_idx, net.dst, val, - &status); - } - - if (err) { - printk("Unable to send Beacon Get/Set message (err %d)\n", err); - return 0; - } - - printk("Beacon state is 0x%02x\n", status); - - return 0; -} - -static void print_unprovisioned_beacon(uint8_t uuid[16], - bt_mesh_prov_oob_info_t oob_info, - uint32_t *uri_hash) -{ - char uuid_hex_str[32 + 1]; - - bin2hex(uuid, 16, uuid_hex_str, sizeof(uuid_hex_str)); - - printk("UUID %s, OOB Info 0x%04x, URI Hash 0x%lx", - uuid_hex_str, oob_info, - (uri_hash == NULL ? 0 : *uri_hash)); -} - -static int cmd_beacon_listen(int argc, char *argv[]) -{ - uint8_t val = str2u8(argv[1]); - - if (val) { - prov.unprovisioned_beacon = print_unprovisioned_beacon; - } else { - prov.unprovisioned_beacon = NULL; - } - - return 0; -} - -struct shell_cmd_help cmd_beacon_help = { - NULL, "[val: off, on]", NULL -}; - -struct shell_cmd_help cmd_beacon_listen_help = { - NULL, "[val: off, on]", NULL -}; - -static int cmd_ttl(int argc, char *argv[]) -{ - uint8_t ttl; - int err; - - if (argc < 2) { - err = bt_mesh_cfg_ttl_get(net.net_idx, net.dst, &ttl); - } else { - uint8_t val = strtoul(argv[1], NULL, 0); - - err = bt_mesh_cfg_ttl_set(net.net_idx, net.dst, val, &ttl); - } - - if (err) { - printk("Unable to send Default TTL Get/Set (err %d)\n", err); - return 0; - } - - printk("Default TTL is 0x%02x\n", ttl); - - return 0; -} - -struct shell_cmd_help cmd_ttl_help = { - NULL, "[ttl: 0x00, 0x02-0x7f]", NULL -}; - -static int cmd_friend(int argc, char *argv[]) -{ - uint8_t frnd; - int err; - - if (argc < 2) { - err = bt_mesh_cfg_friend_get(net.net_idx, net.dst, &frnd); - } else { - uint8_t val = str2u8(argv[1]); - - err = bt_mesh_cfg_friend_set(net.net_idx, net.dst, val, &frnd); - } - - if (err) { - printk("Unable to send Friend Get/Set (err %d)\n", err); - return 0; - } - - printk("Friend is set to 0x%02x\n", frnd); - - return 0; -} - -struct shell_cmd_help cmd_friend_help = { - NULL, "[val: off, on]", NULL -}; - -static int cmd_gatt_proxy(int argc, char *argv[]) -{ - uint8_t proxy; - int err; - - if (argc < 2) { - err = bt_mesh_cfg_gatt_proxy_get(net.net_idx, net.dst, &proxy); - } else { - uint8_t val = str2u8(argv[1]); - - err = bt_mesh_cfg_gatt_proxy_set(net.net_idx, net.dst, val, - &proxy); - } - - if (err) { - printk("Unable to send GATT Proxy Get/Set (err %d)\n", err); - return 0; - } - - printk("GATT Proxy is set to 0x%02x\n", proxy); - - return 0; -} - -struct shell_cmd_help cmd_gatt_proxy_help = { - NULL, "[val: off, on]", NULL -}; - -static int cmd_net_transmit(int argc, char *argv[]) -{ - uint8_t transmit; - int err; - - if (argc < 2) { - err = bt_mesh_cfg_net_transmit_get(net.net_idx, - net.dst, &transmit); - } else { - if (argc != 3) { - printk("Wrong number of input arguments" - "(2 arguments are required)"); - return -EINVAL; - } - - uint8_t count, interval, new_transmit; - - count = strtoul(argv[1], NULL, 0); - interval = strtoul(argv[2], NULL, 0); - - new_transmit = BT_MESH_TRANSMIT(count, interval); - - err = bt_mesh_cfg_net_transmit_set(net.net_idx, net.dst, - new_transmit, &transmit); - } - - if (err) { - printk("Unable to send network transmit" - " Get/Set (err %d)", err); - return 0; - } - - printk("Transmit 0x%02x (count %u interval %ums)", - transmit, BT_MESH_TRANSMIT_COUNT(transmit), - BT_MESH_TRANSMIT_INT(transmit)); - - return 0; -} - -struct shell_cmd_help cmd_net_transmit_help = { - NULL, "[ ]", NULL -}; - -static int cmd_relay(int argc, char *argv[]) -{ - uint8_t relay, transmit; - int err; - - if (argc < 2) { - err = bt_mesh_cfg_relay_get(net.net_idx, net.dst, &relay, - &transmit); - } else { - uint8_t val = str2u8(argv[1]); - uint8_t count, interval, new_transmit; - - if (val) { - if (argc > 2) { - count = strtoul(argv[2], NULL, 0); - } else { - count = 2; - } - - if (argc > 3) { - interval = strtoul(argv[3], NULL, 0); - } else { - interval = 20; - } - - new_transmit = BT_MESH_TRANSMIT(count, interval); - } else { - new_transmit = 0; - } - - err = bt_mesh_cfg_relay_set(net.net_idx, net.dst, val, - new_transmit, &relay, &transmit); - } - - if (err) { - printk("Unable to send Relay Get/Set (err %d)\n", err); - return 0; - } - - printk("Relay is 0x%02x, Transmit 0x%02x (count %u interval %ums)\n", - relay, transmit, BT_MESH_TRANSMIT_COUNT(transmit), - BT_MESH_TRANSMIT_INT(transmit)); - - return 0; -} - -struct shell_cmd_help cmd_relay_help = { - NULL, "[val: off, on] [count: 0-7] [interval: 0-32]", NULL -}; - -static int cmd_net_key_add(int argc, char *argv[]) -{ - bool has_key_val = (argc > 2); - uint8_t key_val[16]; - uint16_t key_net_idx; - uint8_t status; - int err; - - if (argc < 2) { - return -EINVAL; - } - - key_net_idx = strtoul(argv[1], NULL, 0); - - if (has_key_val) { - size_t len; - - len = hex2bin(argv[3], key_val, sizeof(key_val)); - memset(key_val, 0, sizeof(key_val) - len); - } else { - memcpy(key_val, default_key, sizeof(key_val)); - } - - if (IS_ENABLED(CONFIG_BT_MESH_CDB)) { - struct bt_mesh_cdb_subnet *subnet; - - subnet = bt_mesh_cdb_subnet_get(key_net_idx); - if (subnet) { - if (has_key_val) { - printk("Subnet 0x%03x already has a value", key_net_idx); - return 0; - } - - memcpy(key_val, subnet->keys[0].net_key, 16); - } else { - subnet = bt_mesh_cdb_subnet_alloc(key_net_idx); - if (!subnet) { - printk("No space for subnet in cdb"); - return 0; - } - - memcpy(subnet->keys[0].net_key, key_val, 16); - bt_mesh_cdb_subnet_store(subnet); - } - } - - err = bt_mesh_cfg_net_key_add(net.net_idx, net.dst, key_net_idx, - key_val, &status); - if (err) { - printk("Unable to send NetKey Add (err %d)\n", err); - return 0; - } - - if (status) { - printk("NetKeyAdd failed with status 0x%02x\n", status); - } else { - printk("NetKey added with NetKey Index 0x%03x\n", key_net_idx); - } - - return 0; -} - -struct shell_cmd_help cmd_net_key_add_help = { - NULL, " [val]", NULL -}; - -static int cmd_net_key_get(int argc, char *argv[]) -{ - uint16_t keys[16]; - size_t cnt; - int err, i; - - cnt = ARRAY_SIZE(keys); - - err = bt_mesh_cfg_net_key_get(net.net_idx, net.dst, keys, &cnt); - if (err) { - printk("Unable to send NetKeyGet (err %d)", err); - return 0; - } - - printk("NetKeys known by 0x%04x:", net.dst); - for (i = 0; i < cnt; i++) { - printk("\t0x%03x", keys[i]); - } - - return 0; -} - -struct shell_cmd_help cmd_net_key_get_help = { - NULL, NULL, NULL -}; - -static int cmd_net_key_del(int argc, char *argv[]) -{ - uint16_t key_net_idx; - uint8_t status; - int err; - - key_net_idx = strtoul(argv[1], NULL, 0); - - err = bt_mesh_cfg_net_key_del(net.net_idx, net.dst, key_net_idx, - &status); - if (err) { - printk("Unable to send NetKeyDel (err %d)", err); - return 0; - } - - if (status) { - printk("NetKeyDel failed with status 0x%02x", - status); - } else { - printk("NetKey 0x%03x deleted", key_net_idx); - } - - return 0; -} - -struct shell_cmd_help cmd_net_key_del_help = { - NULL, "", NULL -}; - -static int cmd_app_key_add(int argc, char *argv[]) -{ - uint8_t key_val[16]; - uint16_t key_net_idx, key_app_idx; - bool has_key_val = (argc > 3); - uint8_t status; - int err; - - if (argc < 3) { - return -EINVAL; - } - - key_net_idx = strtoul(argv[1], NULL, 0); - key_app_idx = strtoul(argv[2], NULL, 0); - - if (has_key_val) { - size_t len; - - len = hex2bin(argv[3], key_val, sizeof(key_val)); - memset(key_val, 0, sizeof(key_val) - len); - } else { - memcpy(key_val, default_key, sizeof(key_val)); - } - - if (IS_ENABLED(CONFIG_BT_MESH_CDB)) { - struct bt_mesh_cdb_app_key *app_key; - - app_key = bt_mesh_cdb_app_key_get(key_app_idx); - if (app_key) { - if (has_key_val) { - printk("App key 0x%03x already has a value", key_app_idx); - return 0; - } - - memcpy(key_val, app_key->keys[0].app_key, 16); - } else { - app_key = bt_mesh_cdb_app_key_alloc(key_net_idx, - key_app_idx); - if (!app_key) { - printk("No space for app key in cdb"); - return 0; - } - - memcpy(app_key->keys[0].app_key, key_val, 16); - bt_mesh_cdb_app_key_store(app_key); - } - } - - err = bt_mesh_cfg_app_key_add(net.net_idx, net.dst, key_net_idx, - key_app_idx, key_val, &status); - if (err) { - printk("Unable to send App Key Add (err %d)\n", err); - return 0; - } - - if (status) { - printk("AppKeyAdd failed with status 0x%02x\n", status); - } else { - printk("AppKey added, NetKeyIndex 0x%04x AppKeyIndex 0x%04x\n", - key_net_idx, key_app_idx); - } - - return 0; -} - -struct shell_cmd_help cmd_app_key_add_help = { - NULL, " [val]", NULL -}; - -static int cmd_app_key_get(int argc, char *argv[]) -{ - uint16_t net_idx; - uint16_t keys[16]; - size_t cnt; - uint8_t status; - int err, i; - - net_idx = strtoul(argv[1], NULL, 0); - cnt = ARRAY_SIZE(keys); - - err = bt_mesh_cfg_app_key_get(net.net_idx, net.dst, net_idx, &status, - keys, &cnt); - if (err) { - printk("Unable to send AppKeyGet (err %d)", err); - return 0; - } - - if (status) { - printk("AppKeyGet failed with status 0x%02x", - status); - return 0; - } - - printk( - "AppKeys for NetKey 0x%03x known by 0x%04x:", net_idx, - net.dst); - for (i = 0; i < cnt; i++) { - printk("\t0x%03x", keys[i]); - } - - return 0; -} - -struct shell_cmd_help cmd_app_key_get_help = { - NULL, "", NULL -}; - -static int cmd_app_key_del(int argc, char *argv[]) -{ - uint16_t key_net_idx, key_app_idx; - uint8_t status; - int err; - - if (argc < 3) { - return -EINVAL; - } - - key_net_idx = strtoul(argv[1], NULL, 0); - key_app_idx = strtoul(argv[2], NULL, 0); - - err = bt_mesh_cfg_app_key_del(net.net_idx, net.dst, key_net_idx, - key_app_idx, &status); - if (err) { - printk("Unable to send App Key del(err %d)", err); - return 0; - } - - if (status) { - printk("AppKeyDel failed with status 0x%02x", - status); - } else { - printk("AppKey deleted, NetKeyIndex 0x%04x " - "AppKeyIndex 0x%04x", key_net_idx, key_app_idx); - } - - return 0; -} - -struct shell_cmd_help cmd_app_key_del_help = { - NULL, " ", NULL -}; - -static int cmd_mod_app_bind(int argc, char *argv[]) -{ - uint16_t elem_addr, mod_app_idx, mod_id, cid; - uint8_t status; - int err; - - if (argc < 4) { - return -EINVAL; - } - - elem_addr = strtoul(argv[1], NULL, 0); - mod_app_idx = strtoul(argv[2], NULL, 0); - mod_id = strtoul(argv[3], NULL, 0); - - if (argc > 4) { - cid = strtoul(argv[4], NULL, 0); - err = bt_mesh_cfg_mod_app_bind_vnd(net.net_idx, net.dst, - elem_addr, mod_app_idx, - mod_id, cid, &status); - } else { - err = bt_mesh_cfg_mod_app_bind(net.net_idx, net.dst, elem_addr, - mod_app_idx, mod_id, &status); - } - - if (err) { - printk("Unable to send Model App Bind (err %d)\n", err); - return 0; - } - - if (status) { - printk("Model App Bind failed with status 0x%02x\n", status); - } else { - printk("AppKey successfully bound\n"); - } - - return 0; -} - -struct shell_cmd_help cmd_mod_app_bind_help = { - NULL, " [Company ID]", NULL -}; - -static int cmd_mod_app_unbind(int argc, char *argv[]) -{ - uint16_t elem_addr, mod_app_idx, mod_id, cid; - uint8_t status; - int err; - - if (argc < 4) { - return -EINVAL; - } - - elem_addr = strtoul(argv[1], NULL, 0); - mod_app_idx = strtoul(argv[2], NULL, 0); - mod_id = strtoul(argv[3], NULL, 0); - - if (argc > 4) { - cid = strtoul(argv[4], NULL, 0); - err = bt_mesh_cfg_mod_app_unbind_vnd(net.net_idx, net.dst, - elem_addr, mod_app_idx, - mod_id, cid, &status); - } else { - err = bt_mesh_cfg_mod_app_unbind(net.net_idx, net.dst, - elem_addr, mod_app_idx, mod_id, &status); - } - - if (err) { - printk("Unable to send Model App Unbind (err %d)", - err); - return 0; - } - - if (status) { - printk("Model App Unbind failed with status 0x%02x", - status); - } else { - printk("AppKey successfully unbound"); - } - - return 0; -} - -struct shell_cmd_help cmd_mod_app_unbind_help = { - NULL, " [Company ID]", NULL -}; - -static int cmd_mod_app_get(int argc, - char *argv[]) -{ - uint16_t elem_addr, mod_id, cid; - uint16_t apps[16]; - uint8_t status; - size_t cnt; - int err, i; - - elem_addr = strtoul(argv[1], NULL, 0); - mod_id = strtoul(argv[2], NULL, 0); - cnt = ARRAY_SIZE(apps); - - if (argc > 3) { - cid = strtoul(argv[3], NULL, 0); - err = bt_mesh_cfg_mod_app_get_vnd(net.net_idx, net.dst, - elem_addr, mod_id, cid, - &status, apps, &cnt); - } else { - err = bt_mesh_cfg_mod_app_get(net.net_idx, net.dst, elem_addr, - mod_id, &status, apps, &cnt); - } - - if (err) { - printk("Unable to send Model App Get (err %d)", - err); - return 0; - } - - if (status) { - printk("Model App Get failed with status 0x%02x", - status); - } else { - printk( - "Apps bound to Element 0x%04x, Model 0x%04x %s:", - elem_addr, mod_id, argc > 3 ? argv[3] : "(SIG)"); - - if (!cnt) { - printk("\tNone."); - } - - for (i = 0; i < cnt; i++) { - printk("\t0x%04x", apps[i]); - } - } - - return 0; -} - -struct shell_cmd_help cmd_mod_app_get_help = { - NULL, " [Company ID]", NULL -}; - -static int cmd_mod_sub_add(int argc, char *argv[]) -{ - uint16_t elem_addr, sub_addr, mod_id, cid; - uint8_t status; - int err; - - if (argc < 4) { - return -EINVAL; - } - - elem_addr = strtoul(argv[1], NULL, 0); - sub_addr = strtoul(argv[2], NULL, 0); - mod_id = strtoul(argv[3], NULL, 0); - - if (argc > 4) { - cid = strtoul(argv[4], NULL, 0); - err = bt_mesh_cfg_mod_sub_add_vnd(net.net_idx, net.dst, - elem_addr, sub_addr, mod_id, - cid, &status); - } else { - err = bt_mesh_cfg_mod_sub_add(net.net_idx, net.dst, elem_addr, - sub_addr, mod_id, &status); - } - - if (err) { - printk("Unable to send Model Subscription Add (err %d)\n", err); - return 0; - } - - if (status) { - printk("Model Subscription Add failed with status 0x%02x\n", - status); - } else { - printk("Model subscription was successful\n"); - } - - return 0; -} - -struct shell_cmd_help cmd_mod_sub_add_help = { - NULL, " [Company ID]", NULL -}; - -static int cmd_mod_sub_del(int argc, char *argv[]) -{ - uint16_t elem_addr, sub_addr, mod_id, cid; - uint8_t status; - int err; - - if (argc < 4) { - return -EINVAL; - } - - elem_addr = strtoul(argv[1], NULL, 0); - sub_addr = strtoul(argv[2], NULL, 0); - mod_id = strtoul(argv[3], NULL, 0); - - if (argc > 4) { - cid = strtoul(argv[4], NULL, 0); - err = bt_mesh_cfg_mod_sub_del_vnd(net.net_idx, net.dst, - elem_addr, sub_addr, mod_id, - cid, &status); - } else { - err = bt_mesh_cfg_mod_sub_del(net.net_idx, net.dst, elem_addr, - sub_addr, mod_id, &status); - } - - if (err) { - printk("Unable to send Model Subscription Delete (err %d)\n", - err); - return 0; - } - - if (status) { - printk("Model Subscription Delete failed with status 0x%02x\n", - status); - } else { - printk("Model subscription deltion was successful\n"); - } - - return 0; -} - -struct shell_cmd_help cmd_mod_sub_del_help = { - NULL, " [Company ID]", NULL -}; - -static int cmd_mod_sub_add_va(int argc, char *argv[]) -{ - uint16_t elem_addr, sub_addr, mod_id, cid; - uint8_t label[16]; - uint8_t status; - size_t len; - int err; - - if (argc < 4) { - return -EINVAL; - } - - elem_addr = strtoul(argv[1], NULL, 0); - - len = hex2bin(argv[2], label, sizeof(label)); - memset(label + len, 0, sizeof(label) - len); - - mod_id = strtoul(argv[3], NULL, 0); - - if (argc > 4) { - cid = strtoul(argv[4], NULL, 0); - err = bt_mesh_cfg_mod_sub_va_add_vnd(net.net_idx, net.dst, - elem_addr, label, mod_id, - cid, &sub_addr, &status); - } else { - err = bt_mesh_cfg_mod_sub_va_add(net.net_idx, net.dst, - elem_addr, label, mod_id, - &sub_addr, &status); - } - - if (err) { - printk("Unable to send Mod Sub VA Add (err %d)\n", err); - return 0; - } - - if (status) { - printk("Mod Sub VA Add failed with status 0x%02x\n", - status); - } else { - printk("0x%04x subscribed to Label UUID %s (va 0x%04x)\n", - elem_addr, argv[2], sub_addr); - } - - return 0; -} - -struct shell_cmd_help cmd_mod_sub_add_va_help = { - NULL, "