diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..e5fdfc5a --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,80 @@ +name: WLED Build + +# Only included into other workflows +on: + workflow_call: + +jobs: + + get_default_envs: + name: Gather Environments + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + cache: 'pip' + - name: Install PlatformIO + run: pip install -r requirements.txt + - name: Get default environments + id: envs + run: | + echo "environments=$(pio project config --json-output | jq -cr '.[0][1][0][1]')" >> $GITHUB_OUTPUT + outputs: + environments: ${{ steps.envs.outputs.environments }} + + + build: + name: Build Enviornments + runs-on: ubuntu-latest + needs: get_default_envs + strategy: + fail-fast: false + matrix: + environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }} + steps: + - uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + cache: 'npm' + - run: npm ci + - name: Cache PlatformIO + uses: actions/cache@v4 + with: + path: | + ~/.platformio/.cache + ~/.buildcache + build_output + key: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-${{ hashFiles('wled00/**', 'usermods/**') }} + restore-keys: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}- + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + cache: 'pip' + - name: Install PlatformIO + run: pip install -r requirements.txt + - name: Build firmware + run: pio run -e ${{ matrix.environment }} + - uses: actions/upload-artifact@v4 + with: + name: firmware-${{ matrix.environment }} + path: | + build_output/release/*.bin + build_output/release/*_ESP02*.bin.gz + + + testCdata: + name: Test cdata.js + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + cache: 'npm' + - run: npm ci + - run: npm test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..27beec99 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,28 @@ +name: WLED Release CI + +on: + push: + tags: + - '*' + +jobs: + + wled_build: + uses: ./.github/workflows/build.yml + + release: + name: Create Release + runs-on: ubuntu-latest + needs: wled_build + steps: + - uses: actions/download-artifact@v4 + with: + merge-multiple: true + - name: Create draft release + uses: softprops/action-gh-release@v1 + with: + draft: True + files: | + *.bin + *.bin.gz + diff --git a/.github/workflows/wled-ci.yml b/.github/workflows/wled-ci.yml index 1dcab26a..3c862c18 100644 --- a/.github/workflows/wled-ci.yml +++ b/.github/workflows/wled-ci.yml @@ -1,94 +1,11 @@ name: WLED CI -on: [push, pull_request] +on: + push: + branches: + - '*' + pull_request: jobs: - - get_default_envs: - name: Gather Environments - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: '3.12' - cache: 'pip' - - name: Install PlatformIO - run: pip install -r requirements.txt - - name: Get default environments - id: envs - run: | - echo "environments=$(pio project config --json-output | jq -cr '.[0][1][0][1]')" >> $GITHUB_OUTPUT - outputs: - environments: ${{ steps.envs.outputs.environments }} - - - build: - name: Build Enviornments - runs-on: ubuntu-latest - needs: get_default_envs - strategy: - fail-fast: false - matrix: - environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }} - steps: - - uses: actions/checkout@v4 - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - cache: 'npm' - - run: npm ci - - name: Cache PlatformIO - uses: actions/cache@v4 - with: - path: | - ~/.platformio/.cache - ~/.buildcache - build_output - key: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-${{ hashFiles('wled00/**', 'usermods/**') }} - restore-keys: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}- - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.12' - cache: 'pip' - - name: Install PlatformIO - run: pip install -r requirements.txt - - name: Build firmware - run: pio run -e ${{ matrix.environment }} - - uses: actions/upload-artifact@v4 - with: - name: firmware-${{ matrix.environment }} - path: | - build_output/release/*.bin - build_output/release/*_ESP02*.bin.gz - release: - name: Create Release - runs-on: ubuntu-latest - needs: build - if: startsWith(github.ref, 'refs/tags/') - steps: - - uses: actions/download-artifact@v4 - with: - merge-multiple: true - - name: Create draft release - uses: softprops/action-gh-release@v1 - with: - draft: True - files: | - *.bin - *.bin.gz - - - testCdata: - name: Test cdata.js - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Use Node.js - uses: actions/setup-node@v4 - with: - node-version: '20.x' - cache: 'npm' - - run: npm ci - - run: npm test + wled_build: + uses: ./.github/workflows/build.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index e377418e..c570ac1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,35 @@ ## WLED changelog +#### Build 2410270 +- WLED 0.15.0-b7 release +- Re-license the WLED project from MIT to EUPL (#4194 by @Aircoookie) +- Fix alexa devices invisible/uncontrollable (#4214 by @Svennte) +- Add visual expand button on hover (#4172) +- Usermod: Audioreactive tuning and performance enhancements (by @softhack007) +- `/json/live` (JSON live data/peek) only enabled when WebSockets are disabled +- Various bugfixes and optimisations: #4179, #4215, #4219, #4222, #4223, #4224, #4228, #4230 + +#### Build 2410140 +- WLED 0.15.0-b6 release +- Added BRT timezone (#4188 by @LuisFadini) +- Fixed the positioning of the "Download the latest binary" button (#4184 by @maxi4329) +- Add WLED_AUTOSEGMENTS compile flag (#4183 by @PaoloTK) +- New 512kB FS parition map for 4MB devices +- Internal API change: Static PinManager & UsermodManager +- Change in Improv chip ID and version generation +- Various optimisations, bugfixes and enhancements (#4005, #4174 & #4175 by @Xevel, #4180, #4168, #4154, #4189 by @dosipod) + +#### Build 2409170 +- UI: Introduce common.js in settings pages (size optimisation) +- Add the ability to toggle the reception of palette synchronizations (#4137 by @felddy) +- Usermod/FX: Temperature usermod added Temperature effect (example usermod effect by @blazoncek) +- Fix AsyncWebServer version pin + #### Build 2409140 - Configure different kinds of busses at compile (#4107 by @PaoloTK) - BREAKING: removes LEDPIN and DEFAULT_LED_TYPE compile overrides - Fetch LED types from Bus classes (dynamic UI) (#4129 by @netmindz, @blazoncek, @dedehai) +- Temperature usermod: update OneWire to 2.3.8 (#4131 by @iammattcoleman) #### Build 2409100 - WLED 0.15.0-b5 release diff --git a/LICENSE b/LICENSE index 69325d21..cca21c00 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,294 @@ -MIT License +Copyright (c) 2016-present Christian Schwinne and individual WLED contributors +Licensed under the EUPL v. 1.2 or later -Copyright (c) 2016 Christian Schwinne + EUROPEAN UNION PUBLIC LICENCE v. 1.2 + EUPL © the European Union 2007, 2016 -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: +This European Union Public Licence (the ‘EUPL’) applies to the Work (as +defined below) which is provided under the terms of this Licence. Any use of +the Work, other than as authorised under this Licence is prohibited (to the +extent such use is covered by a right of the copyright holder of the Work). -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The Work is provided under the terms of this Licence when the Licensor (as +defined below) has placed the following notice immediately following the +copyright notice for the Work: -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. \ No newline at end of file + Licensed under the EUPL + +or has expressed by any other means his willingness to license under the EUPL. + +1. Definitions + +In this Licence, the following terms have the following meaning: + +- ‘The Licence’: this Licence. + +- ‘The Original Work’: the work or software distributed or communicated by the + Licensor under this Licence, available as Source Code and also as Executable + Code as the case may be. + +- ‘Derivative Works’: the works or software that could be created by the + Licensee, based upon the Original Work or modifications thereof. This + Licence does not define the extent of modification or dependence on the + Original Work required in order to classify a work as a Derivative Work; + this extent is determined by copyright law applicable in the country + mentioned in Article 15. + +- ‘The Work’: the Original Work or its Derivative Works. + +- ‘The Source Code’: the human-readable form of the Work which is the most + convenient for people to study and modify. + +- ‘The Executable Code’: any code which has generally been compiled and which + is meant to be interpreted by a computer as a program. + +- ‘The Licensor’: the natural or legal person that distributes or communicates + the Work under the Licence. + +- ‘Contributor(s)’: any natural or legal person who modifies the Work under + the Licence, or otherwise contributes to the creation of a Derivative Work. + +- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of + the Work under the terms of the Licence. + +- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending, + renting, distributing, communicating, transmitting, or otherwise making + available, online or offline, copies of the Work or providing access to its + essential functionalities at the disposal of any other natural or legal + person. + +2. Scope of the rights granted by the Licence + +The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +sublicensable licence to do the following, for the duration of copyright +vested in the Original Work: + +- use the Work in any circumstance and for all usage, +- reproduce the Work, +- modify the Work, and make Derivative Works based upon the Work, +- communicate to the public, including the right to make available or display + the Work or copies thereof to the public and perform publicly, as the case + may be, the Work, +- distribute the Work or copies thereof, +- lend and rent the Work or copies thereof, +- sublicense rights in the Work or copies thereof. + +Those rights can be exercised on any media, supports and formats, whether now +known or later invented, as far as the applicable law permits so. + +In the countries where moral rights apply, the Licensor waives his right to +exercise his moral right to the extent allowed by law in order to make +effective the licence of the economic rights here above listed. + +The Licensor grants to the Licensee royalty-free, non-exclusive usage rights +to any patents held by the Licensor, to the extent necessary to make use of +the rights granted on the Work under this Licence. + +3. Communication of the Source Code + +The Licensor may provide the Work either in its Source Code form, or as +Executable Code. If the Work is provided as Executable Code, the Licensor +provides in addition a machine-readable copy of the Source Code of the Work +along with each copy of the Work that the Licensor distributes or indicates, +in a notice following the copyright notice attached to the Work, a repository +where the Source Code is easily and freely accessible for as long as the +Licensor continues to distribute or communicate the Work. + +4. Limitations on copyright + +Nothing in this Licence is intended to deprive the Licensee of the benefits +from any exception or limitation to the exclusive rights of the rights owners +in the Work, of the exhaustion of those rights or of other applicable +limitations thereto. + +5. Obligations of the Licensee + +The grant of the rights mentioned above is subject to some restrictions and +obligations imposed on the Licensee. Those obligations are the following: + +Attribution right: The Licensee shall keep intact all copyright, patent or +trademarks notices and all notices that refer to the Licence and to the +disclaimer of warranties. The Licensee must include a copy of such notices and +a copy of the Licence with every copy of the Work he/she distributes or +communicates. The Licensee must cause any Derivative Work to carry prominent +notices stating that the Work has been modified and the date of modification. + +Copyleft clause: If the Licensee distributes or communicates copies of the +Original Works or Derivative Works, this Distribution or Communication will be +done under the terms of this Licence or of a later version of this Licence +unless the Original Work is expressly distributed only under this version of +the Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee +(becoming Licensor) cannot offer or impose any additional terms or conditions +on the Work or Derivative Work that alter or restrict the terms of the +Licence. + +Compatibility clause: If the Licensee Distributes or Communicates Derivative +Works or copies thereof based upon both the Work and another work licensed +under a Compatible Licence, this Distribution or Communication can be done +under the terms of this Compatible Licence. For the sake of this clause, +‘Compatible Licence’ refers to the licences listed in the appendix attached to +this Licence. Should the Licensee's obligations under the Compatible Licence +conflict with his/her obligations under this Licence, the obligations of the +Compatible Licence shall prevail. + +Provision of Source Code: When distributing or communicating copies of the +Work, the Licensee will provide a machine-readable copy of the Source Code or +indicate a repository where this Source will be easily and freely available +for as long as the Licensee continues to distribute or communicate the Work. + +Legal Protection: This Licence does not grant permission to use the trade +names, trademarks, service marks, or 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 copyright notice. + +6. Chain of Authorship + +The original Licensor warrants that the copyright in the Original Work granted +hereunder is owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each Contributor warrants that the copyright in the modifications he/she +brings to the Work are owned by him/her or licensed to him/her and that he/she +has the power and authority to grant the Licence. + +Each time You accept the Licence, the original Licensor and subsequent +Contributors grant You a licence to their contributions to the Work, under the +terms of this Licence. + +7. Disclaimer of Warranty + +The Work is a work in progress, which is continuously improved by numerous +Contributors. It is not a finished work and may therefore contain defects or +‘bugs’ inherent to this type of development. + +For the above reason, the Work is provided under the Licence on an ‘as is’ +basis and without warranties of any kind concerning the Work, including +without limitation merchantability, fitness for a particular purpose, absence +of defects or errors, accuracy, non-infringement of intellectual property +rights other than copyright as stated in Article 6 of this Licence. + +This disclaimer of warranty is an essential part of the Licence and a +condition for the grant of any rights to the Work. + +8. Disclaimer of Liability + +Except in the cases of wilful misconduct or damages directly caused to natural +persons, the Licensor will in no event be liable for any direct or indirect, +material or moral, damages of any kind, arising out of the Licence or of the +use of the Work, including without limitation, damages for loss of goodwill, +work stoppage, computer failure or malfunction, loss of data or any commercial +damage, even if the Licensor has been advised of the possibility of such +damage. However, the Licensor will be liable under statutory product liability +laws as far such laws apply to the Work. + +9. Additional agreements + +While distributing the Work, You may choose to conclude an additional +agreement, defining obligations or services consistent with this Licence. +However, if accepting obligations, You may act only on your own behalf and on +your sole responsibility, not on behalf of the original Licensor or 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 the fact You have accepted any warranty or additional +liability. + +10. Acceptance of the Licence + +The provisions of this Licence can be accepted by clicking on an icon ‘I +agree’ placed under the bottom of a window displaying the text of this Licence +or by affirming consent in any other similar way, in accordance with the rules +of applicable law. Clicking on that icon indicates your clear and irrevocable +acceptance of this Licence and all of its terms and conditions. + +Similarly, you irrevocably accept this Licence and all of its terms and +conditions by exercising any rights granted to You by Article 2 of this +Licence, such as the use of the Work, the creation by You of a Derivative Work +or the Distribution or Communication by You of the Work or copies thereof. + +11. Information to the public + +In case of any Distribution or Communication of the Work by means of +electronic communication by You (for example, by offering to download the Work +from a remote location) the distribution channel or media (for example, a +website) must at least provide to the public the information requested by the +applicable law regarding the Licensor, the Licence and the way it may be +accessible, concluded, stored and reproduced by the Licensee. + +12. Termination of the Licence + +The Licence and the rights granted hereunder will terminate automatically upon +any breach by the Licensee of the terms of the Licence. + +Such a termination will not terminate the licences of any person who has +received the Work from the Licensee under the Licence, provided such persons +remain in full compliance with the Licence. + +13. Miscellaneous + +Without prejudice of Article 9 above, the Licence represents the complete +agreement between the Parties as to the Work. + +If any provision of the Licence is invalid or unenforceable under applicable +law, this will not affect the validity or enforceability of the Licence as a +whole. Such provision will be construed or reformed so as necessary to make it +valid and enforceable. + +The European Commission may publish other linguistic versions or new versions +of this Licence or updated versions of the Appendix, so far this is required +and reasonable, without reducing the scope of the rights granted by the +Licence. New versions of the Licence will be published with a unique version +number. + +All linguistic versions of this Licence, approved by the European Commission, +have identical value. Parties can take advantage of the linguistic version of +their choice. + +14. Jurisdiction + +Without prejudice to specific agreement between parties, + +- any litigation resulting from the interpretation of this License, arising + between the European Union institutions, bodies, offices or agencies, as a + Licensor, and any Licensee, will be subject to the jurisdiction of the Court + of Justice of the European Union, as laid down in article 272 of the Treaty + on the Functioning of the European Union, + +- any litigation arising between other parties and resulting from the + interpretation of this License, will be subject to the exclusive + jurisdiction of the competent court where the Licensor resides or conducts + its primary business. + +15. Applicable Law + +Without prejudice to specific agreement between parties, + +- this Licence shall be governed by the law of the European Union Member State + where the Licensor has his seat, resides or has his registered office, + +- this licence shall be governed by Belgian law if the Licensor has no seat, + residence or registered office inside a European Union Member State. + +Appendix + +‘Compatible Licences’ according to Article 5 EUPL are: + +- GNU General Public License (GPL) v. 2, v. 3 +- GNU Affero General Public License (AGPL) v. 3 +- Open Software License (OSL) v. 2.1, v. 3.0 +- Eclipse Public License (EPL) v. 1.0 +- CeCILL v. 2.0, v. 2.1 +- Mozilla Public Licence (MPL) v. 2 +- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 +- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for + works other than software +- European Union Public Licence (EUPL) v. 1.1, v. 1.2 +- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong + Reciprocity (LiLiQ-R+). + +The European Commission may update this Appendix to later versions of the +above licences without producing a new version of the EUPL, as long as they +provide the rights granted in Article 2 of this Licence and protect the +covered Source Code from exclusive appropriation. + +All other changes or additions to this Appendix require the production of a +new EUPL version. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 415d8815..db709485 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,18 @@ { "name": "wled", - "version": "0.15.0-b5", + "version": "0.15.0-b7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "wled", - "version": "0.15.0-b5", + "version": "0.15.0-b7", "license": "ISC", "dependencies": { "clean-css": "^5.3.3", "html-minifier-terser": "^7.2.0", "inliner": "^1.13.1", - "nodemon": "^3.0.2" + "nodemon": "^3.1.7" } }, "node_modules/@jridgewell/gen-mapping": { diff --git a/package.json b/package.json index 721455bf..fbcb8ed8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wled", - "version": "0.15.0-b5", + "version": "0.15.0-dev", "description": "Tools for WLED project", "main": "tools/cdata.js", "directories": { @@ -27,5 +27,8 @@ "html-minifier-terser": "^7.2.0", "inliner": "^1.13.1", "nodemon": "^3.1.7" + }, + "engines": { + "node": ">=20.0.0" } } diff --git a/pio-scripts/output_bins.py b/pio-scripts/output_bins.py index 63365400..4d1594d8 100644 --- a/pio-scripts/output_bins.py +++ b/pio-scripts/output_bins.py @@ -19,8 +19,9 @@ def _create_dirs(dirs=["map", "release", "firmware"]): os.makedirs(os.path.join(OUTPUT_DIR, d), exist_ok=True) def create_release(source): - release_name = _get_cpp_define_value(env, "WLED_RELEASE_NAME") - if release_name: + release_name_def = _get_cpp_define_value(env, "WLED_RELEASE_NAME") + if release_name_def: + release_name = release_name_def.replace("\\\"", "") version = _get_cpp_define_value(env, "WLED_VERSION") release_file = os.path.join(OUTPUT_DIR, "release", f"WLED_{version}_{release_name}.bin") release_gz_file = release_file + ".gz" diff --git a/platformio.ini b/platformio.ini index 3005ba22..fe02213f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -197,6 +197,7 @@ build_flags = ; decrease code cache size and increase IRAM to fit all pixel functions -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ;; in case of linker errors like "section `.text1' will not fit in region `iram1_0_seg'" ; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED ;; (experimental) adds some extra heap, but may cause slowdown + -D NON32XFER_HANDLER ;; ask forgiveness for PROGMEM misuse lib_deps = #https://github.com/lorol/LITTLEFS.git @@ -259,7 +260,8 @@ lib_deps = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 ${env.lib_deps} # additional build flags for audioreactive -AR_build_flags = -D USERMOD_AUDIOREACTIVE +AR_build_flags = -D USERMOD_AUDIOREACTIVE + -D sqrt_internal=sqrtf ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster) AR_lib_deps = kosme/arduinoFFT @ 2.0.1 [esp32_idf_V4] @@ -343,7 +345,7 @@ platform = ${common.platform_wled_default} platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_4m1m} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP8266 #-DWLED_DISABLE_2D +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266\" #-DWLED_DISABLE_2D lib_deps = ${esp8266.lib_deps} monitor_filters = esp8266_exception_decoder @@ -352,13 +354,13 @@ extends = env:nodemcuv2 ;; using platform version and build options from WLED 0.14.0 platform = ${esp8266.platform_compat} platform_packages = ${esp8266.platform_packages_compat} -build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP8266_compat #-DWLED_DISABLE_2D +build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP8266_compat\" #-DWLED_DISABLE_2D ;; lib_deps = ${esp8266.lib_deps_compat} ;; experimental - use older NeoPixelBus 2.7.9 [env:nodemcuv2_160] extends = env:nodemcuv2 board_build.f_cpu = 160000000L -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP8266_160 #-DWLED_DISABLE_2D +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266_160\" #-DWLED_DISABLE_2D -D USERMOD_AUDIOREACTIVE [env:esp8266_2m] @@ -367,7 +369,7 @@ platform = ${common.platform_wled_default} platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_2m512k} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP02 +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02\" lib_deps = ${esp8266.lib_deps} [env:esp8266_2m_compat] @@ -375,12 +377,12 @@ extends = env:esp8266_2m ;; using platform version and build options from WLED 0.14.0 platform = ${esp8266.platform_compat} platform_packages = ${esp8266.platform_packages_compat} -build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP02_compat #-DWLED_DISABLE_2D +build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP02_compat\" #-DWLED_DISABLE_2D [env:esp8266_2m_160] extends = env:esp8266_2m board_build.f_cpu = 160000000L -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP02_160 +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02_160\" -D USERMOD_AUDIOREACTIVE [env:esp01_1m_full] @@ -389,7 +391,7 @@ platform = ${common.platform_wled_default} platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_1m128k} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP01\" -D WLED_DISABLE_OTA ; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM lib_deps = ${esp8266.lib_deps} @@ -398,12 +400,12 @@ extends = env:esp01_1m_full ;; using platform version and build options from WLED 0.14.0 platform = ${esp8266.platform_compat} platform_packages = ${esp8266.platform_packages_compat} -build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP01_compat -D WLED_DISABLE_OTA #-DWLED_DISABLE_2D +build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP01_compat\" -D WLED_DISABLE_OTA #-DWLED_DISABLE_2D [env:esp01_1m_full_160] extends = env:esp01_1m_full board_build.f_cpu = 160000000L -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP01_160 -D WLED_DISABLE_OTA +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP01_160\" -D WLED_DISABLE_OTA -D USERMOD_AUDIOREACTIVE ; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM @@ -412,7 +414,7 @@ board = esp32dev platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32 #-D WLED_DISABLE_BROWNOUT_DET +build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} lib_deps = ${esp32.lib_deps} ${esp32.AR_lib_deps} @@ -424,7 +426,7 @@ board = esp32dev platform = ${esp32_idf_V4.platform} platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_8M #-D WLED_DISABLE_BROWNOUT_DET +build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} lib_deps = ${esp32_idf_V4.lib_deps} ${esp32.AR_lib_deps} @@ -440,7 +442,7 @@ board = esp32dev platform = ${esp32_idf_V4.platform} platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_16M #-D WLED_DISABLE_BROWNOUT_DET +build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} lib_deps = ${esp32_idf_V4.lib_deps} ${esp32.AR_lib_deps} @@ -456,7 +458,7 @@ board_build.flash_mode = dio ;platform = ${esp32.platform} ;platform_packages = ${esp32.platform_packages} ;build_unflags = ${common.build_unflags} -;build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32_audioreactive #-D WLED_DISABLE_BROWNOUT_DET +;build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_audioreactive\" #-D WLED_DISABLE_BROWNOUT_DET ; ${esp32.AR_build_flags} ;lib_deps = ${esp32.lib_deps} ; ${esp32.AR_lib_deps} @@ -471,7 +473,7 @@ platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 +build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_Ethernet\" -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 ; -D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only ${esp32.AR_build_flags} lib_deps = ${esp32.lib_deps} @@ -487,7 +489,7 @@ board_build.f_flash = 80000000L board_build.flash_mode = qio board_build.partitions = ${esp32.extended_partitions} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_WROVER +build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_WROVER\" -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html -D DATA_PINS=25 ${esp32.AR_build_flags} @@ -501,7 +503,7 @@ platform_packages = ${esp32c3.platform_packages} framework = arduino board = esp32-c3-devkitm-1 board_build.partitions = ${esp32.default_partitions} -build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=ESP32-C3 +build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-C3\" -D WLED_WATCHDOG_TIMEOUT=0 -DLOLIN_WIFI_FIX ; seems to work much better with this -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB @@ -518,7 +520,7 @@ platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_16MB_opi +build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_16MB_opi\" -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 ;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") @@ -541,7 +543,7 @@ platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_8MB_opi +build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_8MB_opi\" -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 ;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") @@ -554,6 +556,33 @@ board_build.f_flash = 80000000L board_build.flash_mode = qio monitor_filters = esp32_exception_decoder +[env:esp32S3_wroom2] +;; For ESP32-S3 WROOM-2, a.k.a. ESP32-S3 DevKitC-1 v1.1 +;; with >= 16MB FLASH and >= 8MB PSRAM (memory_type: opi_opi) +platform = ${esp32s3.platform} +platform_packages = ${esp32s3.platform_packages} +board = esp32s3camlcd ;; this is the only standard board with "opi_opi" +board_build.arduino.memory_type = opi_opi +upload_speed = 921600 +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_WROOM-2\" + -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 + -D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip + ;; -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") + -DBOARD_HAS_PSRAM + -D LEDPIN=38 -D DATA_PINS=38 ;; buildin WS2812b LED + -D BTNPIN=0 -D RLYPIN=16 -D IRPIN=17 -D AUDIOPIN=-1 + -D WLED_DEBUG + ${esp32.AR_build_flags} + -D SR_DMTYPE=1 -D I2S_SDPIN=13 -D I2S_CKPIN=14 -D I2S_WSPIN=15 -D MCLK_PIN=4 ;; I2S mic +lib_deps = ${esp32s3.lib_deps} + ${esp32.AR_lib_deps} + +board_build.partitions = ${esp32.extreme_partitions} +board_upload.flash_size = 16MB +board_upload.maximum_size = 16777216 +monitor_filters = esp32_exception_decoder + [env:esp32s3_4M_qspi] ;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi) board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM @@ -561,7 +590,7 @@ platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_4M_qspi +build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_4M_qspi\" -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") -DBOARD_HAS_PSRAM -DLOLIN_WIFI_FIX ; seems to work much better with this @@ -582,7 +611,7 @@ board_build.partitions = ${esp32.default_partitions} board_build.flash_mode = qio board_build.f_flash = 80000000L build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=ESP32-S2 +build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S2\" -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index a9a0c3d0..a0120897 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -37,7 +37,7 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} ; *** To use the below defines/overrides, copy and paste each onto it's own line just below build_flags in the section above. ; ; Set a release name that may be used to distinguish required binary for flashing -; -D WLED_RELEASE_NAME=ESP32_MULTI_USREMODS +; -D WLED_RELEASE_NAME=\"ESP32_MULTI_USREMODS\" ; ; disable specific features ; -D WLED_DISABLE_OTA @@ -111,7 +111,6 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} ; ; Use 4 Line Display usermod with SPI display ; -D USERMOD_FOUR_LINE_DISPLAY -; -D USE_ALT_DISPlAY # mandatory ; -DFLD_SPI_DEFAULT ; -D FLD_TYPE=SSD1306_SPI64 ; -D FLD_PIN_CLOCKSPI=14 @@ -377,7 +376,6 @@ build_flags = ${common.build_flags} ${esp32.build_flags} -D USERMOD_DALLASTEMPERATURE -D USERMOD_FOUR_LINE_DISPLAY -D TEMPERATURE_PIN=23 - -D USE_ALT_DISPlAY ; new versions of USERMOD_FOUR_LINE_DISPLAY and USERMOD_ROTARY_ENCODER_UI -D USERMOD_AUDIOREACTIVE lib_deps = ${esp32.lib_deps} OneWire@~2.3.5 diff --git a/readme.md b/readme.md index 11c1733f..8c9a0880 100644 --- a/readme.md +++ b/readme.md @@ -12,7 +12,7 @@ # Welcome to my project WLED! ✨ -A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102! +A fast and feature-rich implementation of an ESP32 and ESP8266 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102! ## ⚙️ Features - WS2812FX library with more than 100 special effects @@ -21,7 +21,7 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control - Segments to set different effects and colors to user defined parts of the LED string - Settings page - configuration via the network - Access Point and station mode - automatic failsafe AP -- Up to 10 LED outputs per instance +- [Up to 10 LED outputs](https://kno.wled.ge/features/multi-strip/#esp32) per instance - Support for RGBW strips - Up to 250 user presets to save and load colors/effects easily, supports cycling through them. - Presets can be used to automatically execute API calls @@ -61,7 +61,7 @@ See [here](https://kno.wled.ge/basics/compatible-hardware)! ## ✌️ Other -Licensed under the MIT license +Licensed under the EUPL v1.2 license Credits [here](https://kno.wled.ge/about/contributors/)! Join the Discord server to discuss everything about WLED! @@ -80,5 +80,5 @@ If WLED really brightens up your day, you can [![](https://img.shields.io/badge/ If you are prone to photosensitive epilepsy, we recommended you do **not** use this software. If you still want to try, don't use strobe, lighting or noise modes or high effect speed settings. -As per the MIT license, I assume no liability for any damage to you or any other person or equipment. +As per the EUPL license, I assume no liability for any damage to you or any other person or equipment. diff --git a/tools/cdata.js b/tools/cdata.js index d65573a8..c5d3c6aa 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -101,6 +101,7 @@ function adoptVersionAndRepo(html) { async function minify(str, type = "plain") { const options = { collapseWhitespace: true, + conservativeCollapse: true, // preserve spaces in text collapseBooleanAttributes: true, collapseInlineTagWhitespace: true, minifyCSS: true, diff --git a/usermods/Analog_Clock/Analog_Clock.h b/usermods/Analog_Clock/Analog_Clock.h index 596f0acb..9d82f767 100644 --- a/usermods/Analog_Clock/Analog_Clock.h +++ b/usermods/Analog_Clock/Analog_Clock.h @@ -102,9 +102,9 @@ private: void secondsEffectSineFade(int16_t secondLed, Toki::Time const& time) { uint32_t ms = time.ms % 1000; - uint8_t b0 = (cos8(ms * 64 / 1000) - 128) * 2; + uint8_t b0 = (cos8_t(ms * 64 / 1000) - 128) * 2; setPixelColor(secondLed, gamma32(scale32(secondColor, b0))); - uint8_t b1 = (sin8(ms * 64 / 1000) - 128) * 2; + uint8_t b1 = (sin8_t(ms * 64 / 1000) - 128) * 2; setPixelColor(inc(secondLed, 1, secondsSegment), gamma32(scale32(secondColor, b1))); } diff --git a/usermods/Animated_Staircase/Animated_Staircase.h b/usermods/Animated_Staircase/Animated_Staircase.h index d1ec9bb7..54a9b333 100644 --- a/usermods/Animated_Staircase/Animated_Staircase.h +++ b/usermods/Animated_Staircase/Animated_Staircase.h @@ -425,10 +425,10 @@ class Animated_Staircase : public Usermod { } void appendConfigData() { - //oappend(SET_F("dd=addDropdown('staircase','selectfield');")); - //oappend(SET_F("addOption(dd,'1st value',0);")); - //oappend(SET_F("addOption(dd,'2nd value',1);")); - //oappend(SET_F("addInfo('staircase:selectfield',1,'additional info');")); // 0 is field type, 1 is actual field + //oappend(F("dd=addDropdown('staircase','selectfield');")); + //oappend(F("addOption(dd,'1st value',0);")); + //oappend(F("addOption(dd,'2nd value',1);")); + //oappend(F("addInfo('staircase:selectfield',1,'additional info');")); // 0 is field type, 1 is actual field } diff --git a/usermods/BME68X_v2/usermod_bme68x.h b/usermods/BME68X_v2/usermod_bme68x.h index 8e360515..aca24d0a 100644 --- a/usermods/BME68X_v2/usermod_bme68x.h +++ b/usermods/BME68X_v2/usermod_bme68x.h @@ -767,22 +767,22 @@ void UsermodBME68X::appendConfigData() { // snprintf_P(charbuffer, 127, PSTR("addInfo('%s:%s',1,'*) Set to minus to deactivate (all sensors)');"), UMOD_NAME, _nameTemp); oappend(charbuffer); /* Dropdown for Celsius/Fahrenheit*/ - oappend(SET_F("dd=addDropdown('")); + oappend(F("dd=addDropdown('")); oappend(UMOD_NAME); - oappend(SET_F("','")); + oappend(F("','")); oappend(_nameTempScale); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'Celsius',0);")); - oappend(SET_F("addOption(dd,'Fahrenheit',1);")); + oappend(F("');")); + oappend(F("addOption(dd,'Celsius',0);")); + oappend(F("addOption(dd,'Fahrenheit',1);")); /* i²C Address*/ - oappend(SET_F("dd=addDropdown('")); + oappend(F("dd=addDropdown('")); oappend(UMOD_NAME); - oappend(SET_F("','")); + oappend(F("','")); oappend(_nameI2CAdr); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'0x76',0x76);")); - oappend(SET_F("addOption(dd,'0x77',0x77);")); + oappend(F("');")); + oappend(F("addOption(dd,'0x76',0x76);")); + oappend(F("addOption(dd,'0x77',0x77);")); } /** diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index e91de850..b36c5f4d 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -478,29 +478,29 @@ class UsermodBattery : public Usermod void appendConfigData() { // Total: 462 Bytes - oappend(SET_F("td=addDropdown('Battery','type');")); // 34 Bytes - oappend(SET_F("addOption(td,'Unkown','0');")); // 28 Bytes - oappend(SET_F("addOption(td,'LiPo','1');")); // 26 Bytes - oappend(SET_F("addOption(td,'LiOn','2');")); // 26 Bytes - oappend(SET_F("addInfo('Battery:type',1,'requires reboot');")); // 81 Bytes - oappend(SET_F("addInfo('Battery:min-voltage',1,'v');")); // 38 Bytes - oappend(SET_F("addInfo('Battery:max-voltage',1,'v');")); // 38 Bytes - oappend(SET_F("addInfo('Battery:interval',1,'ms');")); // 36 Bytes - oappend(SET_F("addInfo('Battery:HA-discovery',1,'');")); // 38 Bytes - oappend(SET_F("addInfo('Battery:auto-off:threshold',1,'%');")); // 45 Bytes - oappend(SET_F("addInfo('Battery:indicator:threshold',1,'%');")); // 46 Bytes - oappend(SET_F("addInfo('Battery:indicator:duration',1,'s');")); // 45 Bytes + oappend(F("td=addDropdown('Battery','type');")); // 34 Bytes + oappend(F("addOption(td,'Unkown','0');")); // 28 Bytes + oappend(F("addOption(td,'LiPo','1');")); // 26 Bytes + oappend(F("addOption(td,'LiOn','2');")); // 26 Bytes + oappend(F("addInfo('Battery:type',1,'requires reboot');")); // 81 Bytes + oappend(F("addInfo('Battery:min-voltage',1,'v');")); // 38 Bytes + oappend(F("addInfo('Battery:max-voltage',1,'v');")); // 38 Bytes + oappend(F("addInfo('Battery:interval',1,'ms');")); // 36 Bytes + oappend(F("addInfo('Battery:HA-discovery',1,'');")); // 38 Bytes + oappend(F("addInfo('Battery:auto-off:threshold',1,'%');")); // 45 Bytes + oappend(F("addInfo('Battery:indicator:threshold',1,'%');")); // 46 Bytes + oappend(F("addInfo('Battery:indicator:duration',1,'s');")); // 45 Bytes // this option list would exeed the oappend() buffer // a list of all presets to select one from - // oappend(SET_F("bd=addDropdown('Battery:low-power-indicator', 'preset');")); - // the loop generates: oappend(SET_F("addOption(bd, 'preset name', preset id);")); + // oappend(F("bd=addDropdown('Battery:low-power-indicator', 'preset');")); + // the loop generates: oappend(F("addOption(bd, 'preset name', preset id);")); // for(int8_t i=1; i < 42; i++) { - // oappend(SET_F("addOption(bd, 'Preset#")); + // oappend(F("addOption(bd, 'Preset#")); // oappendi(i); - // oappend(SET_F("',")); + // oappend(F("',")); // oappendi(i); - // oappend(SET_F(");")); + // oappend(F(");")); // } } diff --git a/usermods/EXAMPLE_v2/usermod_v2_example.h b/usermods/EXAMPLE_v2/usermod_v2_example.h index 3d562b58..df05f3e3 100644 --- a/usermods/EXAMPLE_v2/usermod_v2_example.h +++ b/usermods/EXAMPLE_v2/usermod_v2_example.h @@ -287,11 +287,11 @@ class MyExampleUsermod : public Usermod { */ void appendConfigData() override { - oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":great")); oappend(SET_F("',1,'(this is a great config value)');")); - oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":testString")); oappend(SET_F("',1,'enter any string you want');")); - oappend(SET_F("dd=addDropdown('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F("','testInt');")); - oappend(SET_F("addOption(dd,'Nothing',0);")); - oappend(SET_F("addOption(dd,'Everything',42);")); + oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":great")); oappend(F("',1,'(this is a great config value)');")); + oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":testString")); oappend(F("',1,'enter any string you want');")); + oappend(F("dd=addDropdown('")); oappend(String(FPSTR(_name)).c_str()); oappend(F("','testInt');")); + oappend(F("addOption(dd,'Nothing',0);")); + oappend(F("addOption(dd,'Everything',42);")); } diff --git a/usermods/Internal_Temperature_v2/usermod_internal_temperature.h b/usermods/Internal_Temperature_v2/usermod_internal_temperature.h index 2236bfea..6d4d4577 100644 --- a/usermods/Internal_Temperature_v2/usermod_internal_temperature.h +++ b/usermods/Internal_Temperature_v2/usermod_internal_temperature.h @@ -50,7 +50,7 @@ public: #else // ESP32 ESP32S3 and ESP32C3 temperature = roundf(temperatureRead() * 10) / 10; #endif - + if(presetToActivate != 0){ // Check if temperature has exceeded the activation threshold if (temperature >= activationThreshold) { // Update the state flag if not already set @@ -58,7 +58,7 @@ public: isAboveThreshold = true; } // Check if a 'high temperature' preset is configured and it's not already active - if (presetToActivate != 0 && currentPreset != presetToActivate) { + if (currentPreset != presetToActivate) { // If a playlist is active, store it for reactivation later if (currentPlaylist > 0) { previousPlaylist = currentPlaylist; @@ -101,6 +101,7 @@ public: } } } + } #ifndef WLED_DISABLE_MQTT if (WLED_MQTT_CONNECTED) @@ -149,11 +150,11 @@ public: void appendConfigData() { // Display 'ms' next to the 'Loop Interval' setting - oappend(SET_F("addInfo('Internal Temperature:Loop Interval', 1, 'ms');")); + oappend(F("addInfo('Internal Temperature:Loop Interval', 1, 'ms');")); // Display '°C' next to the 'Activation Threshold' setting - oappend(SET_F("addInfo('Internal Temperature:Activation Threshold', 1, '°C');")); + oappend(F("addInfo('Internal Temperature:Activation Threshold', 1, '°C');")); // Display '0 = Disabled' next to the 'Preset To Activate' setting - oappend(SET_F("addInfo('Internal Temperature:Preset To Activate', 1, '0 = unused');")); + oappend(F("addInfo('Internal Temperature:Preset To Activate', 1, '0 = unused');")); } bool readFromConfig(JsonObject &root) diff --git a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h index 29070cf8..0deda181 100644 --- a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h +++ b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h @@ -511,8 +511,8 @@ void PIRsensorSwitch::addToConfig(JsonObject &root) void PIRsensorSwitch::appendConfigData() { - oappend(SET_F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++) { char str[128]; sprintf_P(str, PSTR("addInfo('PIRsensorSwitch:pin[]',%d,'','#%d');"), i, i); diff --git a/usermods/ST7789_display/ST7789_display.h b/usermods/ST7789_display/ST7789_display.h index 0dbada38..65f4cae5 100644 --- a/usermods/ST7789_display/ST7789_display.h +++ b/usermods/ST7789_display/ST7789_display.h @@ -377,10 +377,10 @@ class St7789DisplayUsermod : public Usermod { void appendConfigData() override { - oappend(SET_F("addInfo('ST7789:pin[]',0,'','SPI CS');")); - oappend(SET_F("addInfo('ST7789:pin[]',1,'','SPI DC');")); - oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI RST');")); - oappend(SET_F("addInfo('ST7789:pin[]',3,'','SPI BL');")); + oappend(F("addInfo('ST7789:pin[]',0,'','SPI CS');")); + oappend(F("addInfo('ST7789:pin[]',1,'','SPI DC');")); + oappend(F("addInfo('ST7789:pin[]',2,'','SPI RST');")); + oappend(F("addInfo('ST7789:pin[]',3,'','SPI BL');")); } /* diff --git a/usermods/Temperature/usermod_temperature.h b/usermods/Temperature/usermod_temperature.h index ad755eae..178bc05a 100644 --- a/usermods/Temperature/usermod_temperature.h +++ b/usermods/Temperature/usermod_temperature.h @@ -435,10 +435,10 @@ bool UsermodTemperature::readFromConfig(JsonObject &root) { } void UsermodTemperature::appendConfigData() { - oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasite)).c_str()); - oappend(SET_F("',1,'(if no Vcc connected)');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasitePin)).c_str()); - oappend(SET_F("',1,'(for external MOSFET)');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasite)).c_str()); + oappend(F("',1,'(if no Vcc connected)');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasitePin)).c_str()); + oappend(F("',1,'(for external MOSFET)');")); // 0 is field type, 1 is actual field } float UsermodTemperature::getTemperature() { diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index fde7afde..9c463e0a 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -75,7 +75,7 @@ static uint8_t soundAgc = 0; // Automagic gain control: 0 - n //static float volumeSmth = 0.0f; // either sampleAvg or sampleAgc depending on soundAgc; smoothed sample static float FFT_MajorPeak = 1.0f; // FFT: strongest (peak) frequency static float FFT_Magnitude = 0.0f; // FFT: volume (magnitude) of peak frequency -static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay() +static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getFrameTime() static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same time as samplePeak, but reset by transmitAudioData static unsigned long timeOfPeak = 0; // time of last sample peak detection. static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects @@ -191,8 +191,8 @@ constexpr uint16_t samplesFFT_2 = 256; // meaningfull part of FFT resul #define LOG_256 5.54517744f // log(256) // These are the input and output vectors. Input vectors receive computed results from FFT. -static float vReal[samplesFFT] = {0.0f}; // FFT sample inputs / freq output - these are our raw result bins -static float vImag[samplesFFT] = {0.0f}; // imaginary parts +static float* vReal = nullptr; // FFT sample inputs / freq output - these are our raw result bins +static float* vImag = nullptr; // imaginary parts // Create FFT object // lib_deps += https://github.com/kosme/arduinoFFT#develop @ 1.9.2 @@ -200,14 +200,9 @@ static float vImag[samplesFFT] = {0.0f}; // imaginary parts // #define FFT_SPEED_OVER_PRECISION // enables use of reciprocals (1/x etc) - not faster on ESP32 // #define FFT_SQRT_APPROXIMATION // enables "quake3" style inverse sqrt - slower on ESP32 // Below options are forcing ArduinoFFT to use sqrtf() instead of sqrt() -#define sqrt(x) sqrtf(x) // little hack that reduces FFT time by 10-50% on ESP32 -#define sqrt_internal sqrtf // see https://github.com/kosme/arduinoFFT/pull/83 - -#include - -/* Create FFT object with weighing factor storage */ -static ArduinoFFT FFT = ArduinoFFT( vReal, vImag, samplesFFT, SAMPLE_RATE, true); +// #define sqrt_internal sqrtf // see https://github.com/kosme/arduinoFFT/pull/83 - since v2.0.0 this must be done in build_flags +#include // FFT object is created in FFTcode // Helper functions // compute average of several FFT result bins @@ -226,6 +221,18 @@ void FFTcode(void * parameter) { DEBUGSR_PRINT("FFT started on core: "); DEBUGSR_PRINTLN(xPortGetCoreID()); + // allocate FFT buffers on first call + if (vReal == nullptr) vReal = (float*) calloc(sizeof(float), samplesFFT); + if (vImag == nullptr) vImag = (float*) calloc(sizeof(float), samplesFFT); + if ((vReal == nullptr) || (vImag == nullptr)) { + // something went wrong + if (vReal) free(vReal); vReal = nullptr; + if (vImag) free(vImag); vImag = nullptr; + return; + } + // Create FFT object with weighing factor storage + ArduinoFFT FFT = ArduinoFFT( vReal, vImag, samplesFFT, SAMPLE_RATE, true); + // see https://www.freertos.org/vtaskdelayuntil.html const TickType_t xFrequency = FFT_MIN_CYCLE * portTICK_PERIOD_MS; @@ -247,6 +254,7 @@ void FFTcode(void * parameter) // get a fresh batch of samples from I2S if (audioSource) audioSource->getSamples(vReal, samplesFFT); + memset(vImag, 0, samplesFFT * sizeof(float)); // set imaginary parts to 0 #if defined(WLED_DEBUG) || defined(SR_DEBUG) if (start < esp_timer_get_time()) { // filter out overflows @@ -265,8 +273,6 @@ void FFTcode(void * parameter) // find highest sample in the batch float maxSample = 0.0f; // max sample from FFT batch for (int i=0; i < samplesFFT; i++) { - // set imaginary parts to 0 - vImag[i] = 0; // pick our our current mic sample - we take the max value from all samples that go into FFT if ((vReal[i] <= (INT16_MAX - 1024)) && (vReal[i] >= (INT16_MIN + 1024))) //skip extreme values - normally these are artefacts if (fabsf((float)vReal[i]) > maxSample) maxSample = fabsf((float)vReal[i]); @@ -297,7 +303,7 @@ void FFTcode(void * parameter) #endif } else { // noise gate closed - only clear results as FFT was skipped. MIC samples are still valid when we do this. - memset(vReal, 0, sizeof(vReal)); + memset(vReal, 0, samplesFFT * sizeof(float)); FFT_MajorPeak = 1; FFT_Magnitude = 0.001; } @@ -530,8 +536,8 @@ static void detectSamplePeak(void) { #endif static void autoResetPeak(void) { - uint16_t MinShowDelay = MAX(50, strip.getMinShowDelay()); // Fixes private class variable compiler error. Unsure if this is the correct way of fixing the root problem. -THATDONFC - if (millis() - timeOfPeak > MinShowDelay) { // Auto-reset of samplePeak after a complete frame has passed. + uint16_t peakDelay = max(uint16_t(50), strip.getFrameTime()); + if (millis() - timeOfPeak > peakDelay) { // Auto-reset of samplePeak after at least one complete frame has passed. samplePeak = false; if (audioSyncEnabled == 0) udpSamplePeak = false; // this is normally reset by transmitAudioData } @@ -1879,57 +1885,59 @@ class AudioReactive : public Usermod { } - void appendConfigData() override + void appendConfigData(Print& uiScript) override { -#ifdef ARDUINO_ARCH_ESP32 - oappend(SET_F("dd=addDropdown('AudioReactive','digitalmic:type');")); + uiScript.print(F("ux='AudioReactive';")); // ux = shortcut for Audioreactive - fingers crossed that "ux" isn't already used as JS var, html post parameter or css style +#ifdef ARDUINO_ARCH_ESP32 + uiScript.print(F("uxp=ux+':digitalmic:pin[]';")); // uxp = shortcut for AudioReactive:digitalmic:pin[] + uiScript.print(F("dd=addDropdown(ux,'digitalmic:type');")); #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) - oappend(SET_F("addOption(dd,'Generic Analog',0);")); + uiScript.print(F("addOption(dd,'Generic Analog',0);")); #endif - oappend(SET_F("addOption(dd,'Generic I2S',1);")); - oappend(SET_F("addOption(dd,'ES7243',2);")); - oappend(SET_F("addOption(dd,'SPH0654',3);")); - oappend(SET_F("addOption(dd,'Generic I2S with Mclk',4);")); + uiScript.print(F("addOption(dd,'Generic I2S',1);")); + uiScript.print(F("addOption(dd,'ES7243',2);")); + uiScript.print(F("addOption(dd,'SPH0654',3);")); + uiScript.print(F("addOption(dd,'Generic I2S with Mclk',4);")); #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) - oappend(SET_F("addOption(dd,'Generic I2S PDM',5);")); + uiScript.print(F("addOption(dd,'Generic I2S PDM',5);")); #endif - oappend(SET_F("addOption(dd,'ES8388',6);")); + uiScript.print(F("addOption(dd,'ES8388',6);")); - oappend(SET_F("dd=addDropdown('AudioReactive','config:AGC');")); - oappend(SET_F("addOption(dd,'Off',0);")); - oappend(SET_F("addOption(dd,'Normal',1);")); - oappend(SET_F("addOption(dd,'Vivid',2);")); - oappend(SET_F("addOption(dd,'Lazy',3);")); + uiScript.print(F("dd=addDropdown(ux,'config:AGC');")); + uiScript.print(F("addOption(dd,'Off',0);")); + uiScript.print(F("addOption(dd,'Normal',1);")); + uiScript.print(F("addOption(dd,'Vivid',2);")); + uiScript.print(F("addOption(dd,'Lazy',3);")); - oappend(SET_F("dd=addDropdown('AudioReactive','dynamics:limiter');")); - oappend(SET_F("addOption(dd,'Off',0);")); - oappend(SET_F("addOption(dd,'On',1);")); - oappend(SET_F("addInfo('AudioReactive:dynamics:limiter',0,' On ');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('AudioReactive:dynamics:rise',1,'ms (♪ effects only)');")); - oappend(SET_F("addInfo('AudioReactive:dynamics:fall',1,'ms (♪ effects only)');")); + uiScript.print(F("dd=addDropdown(ux,'dynamics:limiter');")); + uiScript.print(F("addOption(dd,'Off',0);")); + uiScript.print(F("addOption(dd,'On',1);")); + uiScript.print(F("addInfo(ux+':dynamics:limiter',0,' On ');")); // 0 is field type, 1 is actual field + uiScript.print(F("addInfo(ux+':dynamics:rise',1,'ms (♪ effects only)');")); + uiScript.print(F("addInfo(ux+':dynamics:fall',1,'ms (♪ effects only)');")); - oappend(SET_F("dd=addDropdown('AudioReactive','frequency:scale');")); - oappend(SET_F("addOption(dd,'None',0);")); - oappend(SET_F("addOption(dd,'Linear (Amplitude)',2);")); - oappend(SET_F("addOption(dd,'Square Root (Energy)',3);")); - oappend(SET_F("addOption(dd,'Logarithmic (Loudness)',1);")); + uiScript.print(F("dd=addDropdown(ux,'frequency:scale');")); + uiScript.print(F("addOption(dd,'None',0);")); + uiScript.print(F("addOption(dd,'Linear (Amplitude)',2);")); + uiScript.print(F("addOption(dd,'Square Root (Energy)',3);")); + uiScript.print(F("addOption(dd,'Logarithmic (Loudness)',1);")); #endif - oappend(SET_F("dd=addDropdown('AudioReactive','sync:mode');")); - oappend(SET_F("addOption(dd,'Off',0);")); + uiScript.print(F("dd=addDropdown(ux,'sync:mode');")); + uiScript.print(F("addOption(dd,'Off',0);")); #ifdef ARDUINO_ARCH_ESP32 - oappend(SET_F("addOption(dd,'Send',1);")); + uiScript.print(F("addOption(dd,'Send',1);")); #endif - oappend(SET_F("addOption(dd,'Receive',2);")); + uiScript.print(F("addOption(dd,'Receive',2);")); #ifdef ARDUINO_ARCH_ESP32 - oappend(SET_F("addInfo('AudioReactive:digitalmic:type',1,'requires reboot!');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',0,'sd/data/dout','I2S SD');")); - oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',1,'ws/clk/lrck','I2S WS');")); - oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',2,'sck/bclk','I2S SCK');")); + uiScript.print(F("addInfo(ux+':digitalmic:type',1,'requires reboot!');")); // 0 is field type, 1 is actual field + uiScript.print(F("addInfo(uxp,0,'sd/data/dout','I2S SD');")); + uiScript.print(F("addInfo(uxp,1,'ws/clk/lrck','I2S WS');")); + uiScript.print(F("addInfo(uxp,2,'sck/bclk','I2S SCK');")); #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) - oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',3,'only use -1, 0, 1 or 3','I2S MCLK');")); + uiScript.print(F("addInfo(uxp,3,'only use -1, 0, 1 or 3','I2S MCLK');")); #else - oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',3,'master clock','I2S MCLK');")); + uiScript.print(F("addInfo(uxp,3,'master clock','I2S MCLK');")); #endif #endif } diff --git a/usermods/audioreactive/readme.md b/usermods/audioreactive/readme.md index 4668ca88..aad269c6 100644 --- a/usermods/audioreactive/readme.md +++ b/usermods/audioreactive/readme.md @@ -30,7 +30,7 @@ There are however plans to create a lightweight audioreactive for the 8266, with ### using latest _arduinoFFT_ library version 2.x The latest arduinoFFT release version should be used for audioreactive. -* `build_flags` = `-D USERMOD_AUDIOREACTIVE` +* `build_flags` = `-D USERMOD_AUDIOREACTIVE -D sqrt_internal=sqrtf` * `lib_deps`= `kosme/arduinoFFT @ 2.0.1` ## Configuration diff --git a/usermods/boblight/boblight.h b/usermods/boblight/boblight.h index 916f7da9..b04b78fa 100644 --- a/usermods/boblight/boblight.h +++ b/usermods/boblight/boblight.h @@ -305,14 +305,14 @@ class BobLightUsermod : public Usermod { } void appendConfigData() override { - //oappend(SET_F("dd=addDropdown('usermod','selectfield');")); - //oappend(SET_F("addOption(dd,'1st value',0);")); - //oappend(SET_F("addOption(dd,'2nd value',1);")); - oappend(SET_F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field + //oappend(F("dd=addDropdown('usermod','selectfield');")); + //oappend(F("addOption(dd,'1st value',0);")); + //oappend(F("addOption(dd,'2nd value',1);")); + oappend(F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field } void addToConfig(JsonObject& root) override { diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/usermod_multi_relay.h index 33a6cf85..c4446c7a 100644 --- a/usermods/multi_relay/usermod_multi_relay.h +++ b/usermods/multi_relay/usermod_multi_relay.h @@ -264,7 +264,7 @@ void MultiRelay::handleOffTimer() { void MultiRelay::InitHtmlAPIHandle() { // https://github.com/me-no-dev/ESPAsyncWebServer DEBUG_PRINTLN(F("Relays: Initialize HTML API")); - server.on(SET_F("/relays"), HTTP_GET, [this](AsyncWebServerRequest *request) { + server.on(F("/relays"), HTTP_GET, [this](AsyncWebServerRequest *request) { DEBUG_PRINTLN(F("Relays: HTML API")); String janswer; String error = ""; @@ -765,10 +765,10 @@ void MultiRelay::addToConfig(JsonObject &root) { } void MultiRelay::appendConfigData() { - oappend(SET_F("addInfo('MultiRelay:PCF8574-address',1,'(not hex!)');")); - oappend(SET_F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');")); - //oappend(SET_F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');")); - oappend(SET_F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); + oappend(F("addInfo('MultiRelay:PCF8574-address',1,'(not hex!)');")); + oappend(F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');")); + //oappend(F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');")); + oappend(F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); } /** diff --git a/usermods/pixels_dice_tray/pixels_dice_tray.h b/usermods/pixels_dice_tray/pixels_dice_tray.h index a1e45ba3..61348ebb 100644 --- a/usermods/pixels_dice_tray/pixels_dice_tray.h +++ b/usermods/pixels_dice_tray/pixels_dice_tray.h @@ -387,23 +387,23 @@ class PixelsDiceTrayUsermod : public Usermod { // To work around this, add info text to the end of the preceding item. // // See addInfo in wled00/data/settings_um.htm for details on what this function does. - oappend(SET_F( + oappend(F( "addInfo('DiceTray:ble_scan_duration',1,'

Set to \"*\" to " "connect to any die.
Leave Blank to disable.

Saving will replace \"*\" with die names.','');")); #if USING_TFT_DISPLAY - oappend(SET_F("ddr=addDropdown('DiceTray','rotation');")); - oappend(SET_F("addOption(ddr,'0 deg',0);")); - oappend(SET_F("addOption(ddr,'90 deg',1);")); - oappend(SET_F("addOption(ddr,'180 deg',2);")); - oappend(SET_F("addOption(ddr,'270 deg',3);")); - oappend(SET_F( + oappend(F("ddr=addDropdown('DiceTray','rotation');")); + oappend(F("addOption(ddr,'0 deg',0);")); + oappend(F("addOption(ddr,'90 deg',1);")); + oappend(F("addOption(ddr,'180 deg',2);")); + oappend(F("addOption(ddr,'270 deg',3);")); + oappend(F( "addInfo('DiceTray:rotation',1,'
DO NOT CHANGE " "SPI PINS.
CHANGES ARE IGNORED.','');")); - oappend(SET_F("addInfo('TFT:pin[]',0,'','SPI CS');")); - oappend(SET_F("addInfo('TFT:pin[]',1,'','SPI DC');")); - oappend(SET_F("addInfo('TFT:pin[]',2,'','SPI RST');")); - oappend(SET_F("addInfo('TFT:pin[]',3,'','SPI BL');")); + oappend(F("addInfo('TFT:pin[]',0,'','SPI CS');")); + oappend(F("addInfo('TFT:pin[]',1,'','SPI DC');")); + oappend(F("addInfo('TFT:pin[]',2,'','SPI RST');")); + oappend(F("addInfo('TFT:pin[]',3,'','SPI BL');")); #endif } diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index c6e17221..f10c78a2 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -310,22 +310,22 @@ void ShtUsermod::onMqttConnect(bool sessionPresent) { * @return void */ void ShtUsermod::appendConfigData() { - oappend(SET_F("dd=addDropdown('")); + oappend(F("dd=addDropdown('")); oappend(_name); - oappend(SET_F("','")); + oappend(F("','")); oappend(_shtType); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'SHT30',0);")); - oappend(SET_F("addOption(dd,'SHT31',1);")); - oappend(SET_F("addOption(dd,'SHT35',2);")); - oappend(SET_F("addOption(dd,'SHT85',3);")); - oappend(SET_F("dd=addDropdown('")); + oappend(F("');")); + oappend(F("addOption(dd,'SHT30',0);")); + oappend(F("addOption(dd,'SHT31',1);")); + oappend(F("addOption(dd,'SHT35',2);")); + oappend(F("addOption(dd,'SHT85',3);")); + oappend(F("dd=addDropdown('")); oappend(_name); - oappend(SET_F("','")); + oappend(F("','")); oappend(_unitOfTemp); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'Celsius',0);")); - oappend(SET_F("addOption(dd,'Fahrenheit',1);")); + oappend(F("');")); + oappend(F("addOption(dd,'Celsius',0);")); + oappend(F("addOption(dd,'Fahrenheit',1);")); } /** diff --git a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h index f712316b..707479df 100644 --- a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h +++ b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h @@ -96,7 +96,7 @@ void setup() { jsonTransitionOnce = true; strip.setTransition(0); //no transition effectCurrent = FX_MODE_COLOR_WIPE; - resetTimebase(); //make sure wipe starts from beginning + strip.resetTimebase(); //make sure wipe starts from beginning //set wipe direction Segment& seg = strip.getSegment(0); diff --git a/usermods/stairway_wipe_basic/wled06_usermod.ino b/usermods/stairway_wipe_basic/wled06_usermod.ino index c1264ebf..dc2159ee 100644 --- a/usermods/stairway_wipe_basic/wled06_usermod.ino +++ b/usermods/stairway_wipe_basic/wled06_usermod.ino @@ -86,7 +86,7 @@ void startWipe() bri = briLast; //turn on transitionDelayTemp = 0; //no transition effectCurrent = FX_MODE_COLOR_WIPE; - resetTimebase(); //make sure wipe starts from beginning + strip.resetTimebase(); //make sure wipe starts from beginning //set wipe direction Segment& seg = strip.getSegment(0); diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/platformio–override.sample.ini b/usermods/usermod_v2_four_line_display_ALT/platformio_override.sample.ini similarity index 59% rename from usermods/usermod_v2_rotary_encoder_ui_ALT/platformio–override.sample.ini rename to usermods/usermod_v2_four_line_display_ALT/platformio_override.sample.ini index 6b32c71f..e5963745 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/platformio–override.sample.ini +++ b/usermods/usermod_v2_four_line_display_ALT/platformio_override.sample.ini @@ -7,11 +7,12 @@ platform = ${esp32.platform} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags_esp32} - -D USERMOD_FOUR_LINE_DISPLAY -D USE_ALT_DISPlAY - -D USERMOD_ROTARY_ENCODER_UI -D ENCODER_DT_PIN=18 -D ENCODER_CLK_PIN=5 -D ENCODER_SW_PIN=19 -upload_speed = 460800 + -D USERMOD_FOUR_LINE_DISPLAY + -D FLD_TYPE=SH1106 + -D I2CSCLPIN=27 + -D I2CSDAPIN=26 + lib_deps = ${esp32.lib_deps} U8g2@~2.34.4 Wire - diff --git a/usermods/usermod_v2_four_line_display_ALT/readme.md b/usermods/usermod_v2_four_line_display_ALT/readme.md index a8f386da..39bb5d28 100644 --- a/usermods/usermod_v2_four_line_display_ALT/readme.md +++ b/usermods/usermod_v2_four_line_display_ALT/readme.md @@ -1,16 +1,8 @@ # I2C/SPI 4 Line Display Usermod ALT -Thank you to the authors of the original version of these usermods. It would not have been possible without them! -"usermod_v2_four_line_display" -"usermod_v2_rotary_encoder_ui" +This usermod could be used in compination with `usermod_v2_rotary_encoder_ui_ALT`. -The core of these usermods are a copy of the originals. The main changes are to the FourLineDisplay usermod. -The display usermod UI has been completely changed. - - -The changes made to the RotaryEncoder usermod were made to support the new UI in the display usermod. -Without the display, it functions identical to the original. -The original "usermod_v2_auto_save" will not work with the display just yet. +## Functionalities Press the encoder to cycle through the options: * Brightness @@ -18,26 +10,18 @@ Press the encoder to cycle through the options: * Intensity * Palette * Effect -* Main Color (only if display is used) -* Saturation (only if display is used) +* Main Color +* Saturation -Press and hold the encoder to display Network Info. If AP is active, it will display AP, SSID and password +Press and hold the encoder to display Network Info. If AP is active, it will display the AP, SSID and Password -Also shows if the timer is enabled +Also shows if the timer is enabled. [See the pair of usermods in action](https://www.youtube.com/watch?v=ulZnBt9z3TI) ## Installation -Please refer to the original `usermod_v2_rotary_encoder_ui` readme for the main instructions. - -Copy the example `platformio_override.sample.ini` from the usermod_v2_rotary_encoder_ui_ALT folder to the root directory of your particular build and rename it to `platformio_override.ini`. - -This file should be placed in the same directory as `platformio.ini`. - -Then, to activate this alternative usermod, add `#define USE_ALT_DISPlAY` (NOTE: CASE SENSITIVE) to the `usermods_list.cpp` file, - or add `-D USE_ALT_DISPlAY` to the original `platformio_override.ini.sample` file - +Copy the example `platformio_override.sample.ini` to the root directory of your particular build. ## Configuration diff --git a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h index dfab7e6f..684dd86e 100644 --- a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h +++ b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h @@ -1202,21 +1202,21 @@ void FourLineDisplayUsermod::onUpdateBegin(bool init) { //} void FourLineDisplayUsermod::appendConfigData() { - oappend(SET_F("dd=addDropdown('4LineDisplay','type');")); - oappend(SET_F("addOption(dd,'None',0);")); - oappend(SET_F("addOption(dd,'SSD1306',1);")); - oappend(SET_F("addOption(dd,'SH1106',2);")); - oappend(SET_F("addOption(dd,'SSD1306 128x64',3);")); - oappend(SET_F("addOption(dd,'SSD1305',4);")); - oappend(SET_F("addOption(dd,'SSD1305 128x64',5);")); - oappend(SET_F("addOption(dd,'SSD1309 128x64',9);")); - oappend(SET_F("addOption(dd,'SSD1306 SPI',6);")); - oappend(SET_F("addOption(dd,'SSD1306 SPI 128x64',7);")); - oappend(SET_F("addOption(dd,'SSD1309 SPI 128x64',8);")); - oappend(SET_F("addInfo('4LineDisplay:type',1,'
Change may require reboot','');")); - oappend(SET_F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');")); - oappend(SET_F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');")); - oappend(SET_F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');")); + oappend(F("dd=addDropdown('4LineDisplay','type');")); + oappend(F("addOption(dd,'None',0);")); + oappend(F("addOption(dd,'SSD1306',1);")); + oappend(F("addOption(dd,'SH1106',2);")); + oappend(F("addOption(dd,'SSD1306 128x64',3);")); + oappend(F("addOption(dd,'SSD1305',4);")); + oappend(F("addOption(dd,'SSD1305 128x64',5);")); + oappend(F("addOption(dd,'SSD1309 128x64',9);")); + oappend(F("addOption(dd,'SSD1306 SPI',6);")); + oappend(F("addOption(dd,'SSD1306 SPI 128x64',7);")); + oappend(F("addOption(dd,'SSD1309 SPI 128x64',8);")); + oappend(F("addInfo('4LineDisplay:type',1,'
Change may require reboot','');")); + oappend(F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');")); + oappend(F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');")); + oappend(F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');")); } /* diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/platformio_override.sample.ini b/usermods/usermod_v2_rotary_encoder_ui_ALT/platformio_override.sample.ini new file mode 100644 index 00000000..8a88fd6b --- /dev/null +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/platformio_override.sample.ini @@ -0,0 +1,14 @@ +[platformio] +default_envs = esp32dev + +[env:esp32dev] +board = esp32dev +platform = ${esp32.platform} +build_unflags = ${common.build_unflags} +build_flags = + ${common.build_flags_esp32} + -D USERMOD_ROTARY_ENCODER_UI + -D USERMOD_ROTARY_ENCODER_GPIO=INPUT + -D ENCODER_DT_PIN=21 + -D ENCODER_CLK_PIN=23 + -D ENCODER_SW_PIN=0 diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md b/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md index 10db879f..c46e8766 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md @@ -1,16 +1,8 @@ # Rotary Encoder UI Usermod ALT -Thank you to the authors of the original version of these usermods. It would not have been possible without them! -"usermod_v2_four_line_display" -"usermod_v2_rotary_encoder_ui" +This usermod supports the UI of the `usermod_v2_rotary_encoder_ui_ALT`. -The core of these usermods are a copy of the originals. The main changes are to the FourLineDisplay usermod. -The display usermod UI has been completely changed. - - -The changes made to the RotaryEncoder usermod were made to support the new UI in the display usermod. -Without the display, it functions identical to the original. -The original "usermod_v2_auto_save" will not work with the display just yet. +## Functionalities Press the encoder to cycle through the options: * Brightness @@ -21,8 +13,7 @@ Press the encoder to cycle through the options: * Main Color (only if display is used) * Saturation (only if display is used) -Press and hold the encoder to display Network Info - if AP is active, it will display the AP, SSID and Password +Press and hold the encoder to display Network Info. If AP is active, it will display the AP, SSID and Password Also shows if the timer is enabled. @@ -30,9 +21,7 @@ Also shows if the timer is enabled. ## Installation -Copy the example `platformio_override.sample.ini` to the root directory of your particular build and rename it to `platformio_override.ini`. - -To activate this alternative usermod, add `#define USE_ALT_DISPlAY` (NOTE: CASE SENSITIVE) to the `usermods_list.cpp` file, or add `-D USE_ALT_DISPlAY` to your `platformio_override.ini` file +Copy the example `platformio_override.sample.ini` to the root directory of your particular build. ### Define Your Options @@ -40,7 +29,6 @@ To activate this alternative usermod, add `#define USE_ALT_DISPlAY` (NOTE: CASE * `USERMOD_FOUR_LINE_DISPLAY` - define this to have this the Four Line Display mod included wled00\usermods_list.cpp also tells this usermod that the display is available (see the Four Line Display usermod `readme.md` for more details) -* `USE_ALT_DISPlAY` - Mandatory to use Four Line Display * `ENCODER_DT_PIN` - defaults to 18 * `ENCODER_CLK_PIN` - defaults to 5 * `ENCODER_SW_PIN` - defaults to 19 @@ -50,7 +38,7 @@ To activate this alternative usermod, add `#define USE_ALT_DISPlAY` (NOTE: CASE ### PlatformIO requirements -Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`. +No special requirements. ## Change Log diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h index 55715b7c..383c1193 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h @@ -1090,8 +1090,8 @@ void RotaryEncoderUIUsermod::addToConfig(JsonObject &root) { } void RotaryEncoderUIUsermod::appendConfigData() { - oappend(SET_F("addInfo('Rotary-Encoder:PCF8574-address',1,'(not hex!)');")); - oappend(SET_F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); + oappend(F("addInfo('Rotary-Encoder:PCF8574-address',1,'(not hex!)');")); + oappend(F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); } /** diff --git a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h index b66be290..7ecec08e 100644 --- a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h +++ b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h @@ -433,8 +433,8 @@ class WordClockUsermod : public Usermod void appendConfigData() { - oappend(SET_F("addInfo('WordClockUsermod:ledOffset', 1, 'Number of LEDs before the letters');")); - oappend(SET_F("addInfo('WordClockUsermod:Norddeutsch', 1, 'Viertel vor instead of Dreiviertel');")); + oappend(F("addInfo('WordClockUsermod:ledOffset', 1, 'Number of LEDs before the letters');")); + oappend(F("addInfo('WordClockUsermod:Norddeutsch', 1, 'Viertel vor instead of Dreiviertel');")); } /* diff --git a/usermods/wireguard/wireguard.h b/usermods/wireguard/wireguard.h index 8c88d000..8656a704 100644 --- a/usermods/wireguard/wireguard.h +++ b/usermods/wireguard/wireguard.h @@ -54,13 +54,13 @@ class WireguardUsermod : public Usermod { } void appendConfigData() { - oappend(SET_F("addInfo('WireGuard:host',1,'Server Hostname');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:port',1,'Server Port');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:ip',1,'Device IP');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:psk',1,'Pre Shared Key (optional)');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:pem',1,'Private Key');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:pub',1,'Public Key');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:tz',1,'POSIX timezone string');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:host',1,'Server Hostname');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:port',1,'Server Port');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:ip',1,'Device IP');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:psk',1,'Pre Shared Key (optional)');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:pem',1,'Private Key');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:pub',1,'Public Key');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:tz',1,'POSIX timezone string');")); // 0 is field type, 1 is actual field } void addToConfig(JsonObject& root) { diff --git a/wled00/FX.cpp b/wled00/FX.cpp index f3e82275..fd2118fd 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2,24 +2,10 @@ WS2812FX.cpp contains all effect methods Harm Aldick - 2016 www.aldick.org - LICENSE - The MIT License (MIT) + Copyright (c) 2016 Harm Aldick - 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. + Licensed under the EUPL v. 1.2 or later + Adapted from code originally licensed under the MIT license Modified heavily for WLED */ @@ -39,7 +25,7 @@ // effect utility functions uint8_t sin_gap(uint16_t in) { if (in & 0x100) return 0; - return sin8(in + 192); // correct phase shift of sine so that it starts and stops at 0 + return sin8_t(in + 192); // correct phase shift of sine so that it starts and stops at 0 } uint16_t triwave16(uint16_t in) { @@ -349,7 +335,7 @@ uint16_t mode_breath(void) { counter = (counter >> 2) + (counter >> 4); //0-16384 + 0-2048 if (counter < 16384) { if (counter > 8192) counter = 8192 - (counter - 8192); - var = sin16(counter) / 103; //close to parabolic in range 0-8192, max val. 23170 + var = sin16_t(counter) / 103; //close to parabolic in range 0-8192, max val. 23170 } unsigned lum = 30 + var; @@ -531,7 +517,7 @@ static uint16_t running_base(bool saw, bool dual=false) { } a = 255 - a; } - uint8_t s = dual ? sin_gap(a) : sin8(a); + uint8_t s = dual ? sin_gap(a) : sin8_t(a); uint32_t ca = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), s); if (dual) { unsigned b = (SEGLEN-1-i)*x_scale - counter; @@ -1893,16 +1879,16 @@ uint16_t mode_pride_2015(void) { unsigned sPseudotime = SEGENV.step; unsigned sHue16 = SEGENV.aux0; - uint8_t sat8 = beatsin88( 87, 220, 250); - uint8_t brightdepth = beatsin88( 341, 96, 224); - unsigned brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256)); - unsigned msmultiplier = beatsin88(147, 23, 60); + uint8_t sat8 = beatsin88_t( 87, 220, 250); + uint8_t brightdepth = beatsin88_t( 341, 96, 224); + unsigned brightnessthetainc16 = beatsin88_t( 203, (25 * 256), (40 * 256)); + unsigned msmultiplier = beatsin88_t(147, 23, 60); unsigned hue16 = sHue16;//gHue * 256; - unsigned hueinc16 = beatsin88(113, 1, 3000); + unsigned hueinc16 = beatsin88_t(113, 1, 3000); sPseudotime += duration * msmultiplier; - sHue16 += duration * beatsin88( 400, 5,9); + sHue16 += duration * beatsin88_t( 400, 5,9); unsigned brightnesstheta16 = sPseudotime; for (unsigned i = 0 ; i < SEGLEN; i++) { @@ -1910,7 +1896,7 @@ uint16_t mode_pride_2015(void) { uint8_t hue8 = hue16 >> 8; brightnesstheta16 += brightnessthetainc16; - unsigned b16 = sin16( brightnesstheta16 ) + 32768; + unsigned b16 = sin16_t( brightnesstheta16 ) + 32768; unsigned bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; @@ -1935,7 +1921,7 @@ uint16_t mode_juggle(void) { CRGB fastled_col; byte dothue = 0; for (int i = 0; i < 8; i++) { - int index = 0 + beatsin88((16 + SEGMENT.speed)*(i + 7), 0, SEGLEN -1); + int index = 0 + beatsin88_t((16 + SEGMENT.speed)*(i + 7), 0, SEGLEN -1); fastled_col = CRGB(SEGMENT.getPixelColor(index)); fastled_col |= (SEGMENT.palette==0)?CHSV(dothue, 220, 255):ColorFromPalette(SEGPALETTE, dothue, 255); SEGMENT.setPixelColor(index, fastled_col); @@ -1956,8 +1942,8 @@ uint16_t mode_palette() { constexpr mathType maxAngle = 0x8000; constexpr mathType staticRotationScale = 256; constexpr mathType animatedRotationScale = 1; - constexpr int16_t (*sinFunction)(uint16_t) = &sin16; - constexpr int16_t (*cosFunction)(uint16_t) = &cos16; + constexpr int16_t (*sinFunction)(uint16_t) = &sin16_t; + constexpr int16_t (*cosFunction)(uint16_t) = &cos16_t; #else using mathType = float; using wideMathType = float; @@ -1980,7 +1966,7 @@ uint16_t mode_palette() { const bool inputAnimateRotation = SEGMENT.check2; const bool inputAssumeSquare = SEGMENT.check3; - const angleType theta = (!inputAnimateRotation) ? (inputRotation * maxAngle / staticRotationScale) : (((strip.now * ((inputRotation >> 4) +1)) & 0xFFFF) * animatedRotationScale); + const angleType theta = (!inputAnimateRotation) ? ((inputRotation + 128) * maxAngle / staticRotationScale) : (((strip.now * ((inputRotation >> 4) +1)) & 0xFFFF) * animatedRotationScale); const mathType sinTheta = sinFunction(theta); const mathType cosTheta = cosFunction(theta); @@ -1999,7 +1985,7 @@ uint16_t mode_palette() { // So the rectangle needs to have exactly the right size. That size depends on the rotation. // This scale computation here only considers one dimension. You can think of it like the rectangle is always scaled so that // the left and right most points always match the left and right side of the display. - const mathType scale = std::abs(sinTheta) + (std::abs(cosTheta) * maxYOut / maxXOut); + const mathType scale = std::abs(sinTheta) + (std::abs(cosTheta) * maxYOut / maxXOut); // 2D simulation: // If we are dealing with a 1D setup, we assume that each segment represents one line on a 2-dimensional display. // The function is called once per segments, so we need to handle one line at a time. @@ -2030,8 +2016,8 @@ uint16_t mode_palette() { colorIndex = ((inputSize - 112) * colorIndex) / 16; } // Finally, shift the palette a bit. - const int paletteOffset = (!inputAnimateShift) ? (inputShift-128) : (((strip.now * ((inputShift >> 3) +1)) & 0xFFFF) >> 8); - colorIndex += paletteOffset; + const int paletteOffset = (!inputAnimateShift) ? (inputShift) : (((strip.now * ((inputShift >> 3) +1)) & 0xFFFF) >> 8); + colorIndex -= paletteOffset; const uint32_t color = SEGMENT.color_wheel((uint8_t)colorIndex); if (isMatrix) { SEGMENT.setPixelColorXY(x, y, color); @@ -2042,7 +2028,7 @@ uint16_t mode_palette() { } return FRAMETIME; } -static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Shift,Size,Rotation,,,Animate Shift,Animate Rotation,Anamorphic;;!;12;c1=128,c2=128,c3=128,o1=1,o2=1,o3=0"; +static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Shift,Size,Rotation,,,Animate Shift,Animate Rotation,Anamorphic;;!;12;ix=112,c1=0,o1=1,o2=0,o3=1"; // WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active @@ -2141,15 +2127,15 @@ uint16_t mode_colorwaves() { unsigned sPseudotime = SEGENV.step; unsigned sHue16 = SEGENV.aux0; - unsigned brightdepth = beatsin88(341, 96, 224); - unsigned brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256)); - unsigned msmultiplier = beatsin88(147, 23, 60); + unsigned brightdepth = beatsin88_t(341, 96, 224); + unsigned brightnessthetainc16 = beatsin88_t( 203, (25 * 256), (40 * 256)); + unsigned msmultiplier = beatsin88_t(147, 23, 60); unsigned hue16 = sHue16;//gHue * 256; - unsigned hueinc16 = beatsin88(113, 60, 300)*SEGMENT.intensity*10/255; // Use the Intensity Slider for the hues + unsigned hueinc16 = beatsin88_t(113, 60, 300)*SEGMENT.intensity*10/255; // Use the Intensity Slider for the hues sPseudotime += duration * msmultiplier; - sHue16 += duration * beatsin88(400, 5, 9); + sHue16 += duration * beatsin88_t(400, 5, 9); unsigned brightnesstheta16 = sPseudotime; for (int i = 0 ; i < SEGLEN; i++) { @@ -2163,7 +2149,7 @@ uint16_t mode_colorwaves() { } brightnesstheta16 += brightnessthetainc16; - unsigned b16 = sin16(brightnesstheta16) + 32768; + unsigned b16 = sin16_t(brightnesstheta16) + 32768; unsigned bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; @@ -2182,7 +2168,7 @@ static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!"; // colored stripes pulsing at a defined Beats-Per-Minute (BPM) uint16_t mode_bpm() { uint32_t stp = (strip.now / 20) & 0xFF; - uint8_t beat = beatsin8(SEGMENT.speed, 64, 255); + uint8_t beat = beatsin8_t(SEGMENT.speed, 64, 255); for (int i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(stp + (i * 2), false, PALETTE_SOLID_WRAP, 0, beat - stp + (i * 10))); } @@ -2198,7 +2184,7 @@ uint16_t mode_fillnoise8() { unsigned index = inoise8(i * SEGLEN, SEGENV.step + i * SEGLEN); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } - SEGENV.step += beatsin8(SEGMENT.speed, 1, 6); //10,1,4 + SEGENV.step += beatsin8_t(SEGMENT.speed, 1, 6); //10,1,4 return FRAMETIME; } @@ -2210,13 +2196,13 @@ uint16_t mode_noise16_1() { SEGENV.step += (1 + SEGMENT.speed/16); for (int i = 0; i < SEGLEN; i++) { - unsigned shift_x = beatsin8(11); // the x position of the noise field swings @ 17 bpm + unsigned shift_x = beatsin8_t(11); // the x position of the noise field swings @ 17 bpm unsigned shift_y = SEGENV.step/42; // the y position becomes slowly incremented unsigned real_x = (i + shift_x) * scale; // the x position of the noise field swings @ 17 bpm unsigned real_y = (i + shift_y) * scale; // the y position becomes slowly incremented uint32_t real_z = SEGENV.step; // the z position becomes quickly incremented unsigned noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down - unsigned index = sin8(noise * 3); // map LED color based on noise data + unsigned index = sin8_t(noise * 3); // map LED color based on noise data SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } @@ -2234,7 +2220,7 @@ uint16_t mode_noise16_2() { unsigned shift_x = SEGENV.step >> 6; // x as a function of time uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field unsigned noise = inoise16(real_x, 0, 4223) >> 8; // get the noise data and scale it down - unsigned index = sin8(noise * 3); // map led color based on noise data + unsigned index = sin8_t(noise * 3); // map led color based on noise data SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, noise)); } @@ -2255,7 +2241,7 @@ uint16_t mode_noise16_3() { uint32_t real_y = (i + shift_y) * scale; // based on the precalculated positions uint32_t real_z = SEGENV.step*8; unsigned noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down - unsigned index = sin8(noise * 3); // map led color based on noise data + unsigned index = sin8_t(noise * 3); // map led color based on noise data SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, noise)); } @@ -2335,13 +2321,13 @@ static const char _data_FX_MODE_COLORTWINKLE[] PROGMEM = "Colortwinkles@Fade spe //Calm effect, like a lake at night uint16_t mode_lake() { unsigned sp = SEGMENT.speed/10; - int wave1 = beatsin8(sp +2, -64,64); - int wave2 = beatsin8(sp +1, -64,64); - int wave3 = beatsin8(sp +2, 0,80); + int wave1 = beatsin8_t(sp +2, -64,64); + int wave2 = beatsin8_t(sp +1, -64,64); + int wave3 = beatsin8_t(sp +2, 0,80); for (int i = 0; i < SEGLEN; i++) { - int index = cos8((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; + int index = cos8_t((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; uint8_t lum = (index > wave3) ? index - wave3 : 0; SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, false, 0, lum)); } @@ -2514,15 +2500,15 @@ static uint16_t ripple_base() { propI /= 2; unsigned cx = rippleorigin >> 8; unsigned cy = rippleorigin & 0xFF; - unsigned mag = scale8(sin8((propF>>2)), amp); + unsigned mag = scale8(sin8_t((propF>>2)), amp); if (propI > 0) SEGMENT.drawCircle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag), true); } else #endif { int left = rippleorigin - propI -1; - int right = rippleorigin + propI +3; + int right = rippleorigin + propI +2; for (int v = 0; v < 4; v++) { - unsigned mag = scale8(cubicwave8((propF>>2)+(v-left)*64), amp); + unsigned mag = scale8(cubicwave8((propF>>2) + v * 64), amp); SEGMENT.setPixelColor(left + v, color_blend(SEGMENT.getPixelColor(left + v), col, mag)); // TODO SEGMENT.setPixelColor(right - v, color_blend(SEGMENT.getPixelColor(right - v), col, mag)); // TODO } @@ -2579,11 +2565,11 @@ static CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat) { // Overall twinkle speed (changed) unsigned ticks = ms / SEGENV.aux0; - unsigned fastcycle8 = ticks; - unsigned slowcycle16 = (ticks >> 8) + salt; - slowcycle16 += sin8(slowcycle16); + unsigned fastcycle8 = uint8_t(ticks); + uint16_t slowcycle16 = (ticks >> 8) + salt; + slowcycle16 += sin8_t(slowcycle16); slowcycle16 = (slowcycle16 * 2053) + 1384; - unsigned slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8); + uint8_t slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8); // Overall twinkle density. // 0 (NONE lit) to 8 (ALL lit at once). @@ -3152,7 +3138,7 @@ static const char _data_FX_MODE_ROLLINGBALLS[] PROGMEM = "Rolling Balls@!,# of b static uint16_t sinelon_base(bool dual, bool rainbow=false) { if (SEGLEN == 1) return mode_static(); SEGMENT.fade_out(SEGMENT.intensity); - unsigned pos = beatsin16(SEGMENT.speed/10,0,SEGLEN-1); + unsigned pos = beatsin16_t(SEGMENT.speed/10,0,SEGLEN-1); if (SEGENV.call == 0) SEGENV.aux0 = pos; uint32_t color1 = SEGMENT.color_from_palette(pos, true, false, 0); uint32_t color2 = SEGCOLOR(2); @@ -3561,7 +3547,7 @@ uint16_t mode_exploding_fireworks(void) if (segs <= (strip.getMaxSegments() /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs int maxSparks = maxData / sizeof(spark); //ESP8266: max. 21/42/85 sparks/seg, ESP32: max. 53/106/213 sparks/seg - unsigned numSparks = min(2 + ((rows*cols) >> 1), maxSparks); + unsigned numSparks = min(5 + ((rows*cols) >> 1), maxSparks); unsigned dataSize = sizeof(spark) * numSparks; if (!SEGENV.allocateData(dataSize + sizeof(float))) return mode_static(); //allocation failed float *dying_gravity = reinterpret_cast(SEGENV.data + dataSize); @@ -3616,7 +3602,8 @@ uint16_t mode_exploding_fireworks(void) * Size is proportional to the height. */ unsigned nSparks = flare->pos + random8(4); - nSparks = constrain(nSparks, 4, numSparks); + nSparks = std::max(nSparks, 4U); // This is not a standard constrain; numSparks is not guaranteed to be at least 4 + nSparks = std::min(nSparks, numSparks); // initialize sparks if (SEGENV.aux0 == 2) { @@ -3868,13 +3855,13 @@ uint16_t mode_plasma(void) { if (SEGENV.call == 0) { SEGENV.aux0 = random8(0,2); // add a bit of randomness } - unsigned thisPhase = beatsin8(6+SEGENV.aux0,-64,64); - unsigned thatPhase = beatsin8(7+SEGENV.aux0,-64,64); + unsigned thisPhase = beatsin8_t(6+SEGENV.aux0,-64,64); + unsigned thatPhase = beatsin8_t(7+SEGENV.aux0,-64,64); for (unsigned i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows: unsigned colorIndex = cubicwave8((i*(2+ 3*(SEGMENT.speed >> 5))+thisPhase) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change. - + cos8((i*(1+ 2*(SEGMENT.speed >> 5))+thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish. - unsigned thisBright = qsub8(colorIndex, beatsin8(7,0, (128 - (SEGMENT.intensity>>1)))); + + cos8_t((i*(1+ 2*(SEGMENT.speed >> 5))+thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish. + unsigned thisBright = qsub8(colorIndex, beatsin8_t(7,0, (128 - (SEGMENT.intensity>>1)))); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, PALETTE_SOLID_WRAP, 0, thisBright)); } @@ -4001,10 +3988,10 @@ static CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, u unsigned wavescale_half = (wavescale >> 1) + 20; waveangle += ((120 + SEGMENT.intensity) * i); //original 250 * i - unsigned s16 = sin16(waveangle) + 32768; + unsigned s16 = sin16_t(waveangle) + 32768; unsigned cs = scale16(s16, wavescale_half) + wavescale_half; ci += (cs * i); - unsigned sindex16 = sin16(ci) + 32768; + unsigned sindex16 = sin16_t(ci) + 32768; unsigned sindex8 = scale16(sindex16, 240); return ColorFromPalette(p, sindex8, bri, LINEARBLEND); } @@ -4031,39 +4018,39 @@ uint16_t mode_pacifica() // Increment the four "color index start" counters, one for each wave layer. // Each is incremented at a different speed, and the speeds vary over time. - unsigned sCIStart1 = SEGENV.aux0, sCIStart2 = SEGENV.aux1, sCIStart3 = SEGENV.step, sCIStart4 = SEGENV.step >> 16; + unsigned sCIStart1 = SEGENV.aux0, sCIStart2 = SEGENV.aux1, sCIStart3 = SEGENV.step & 0xFFFF, sCIStart4 = (SEGENV.step >> 16); uint32_t deltams = (FRAMETIME >> 2) + ((FRAMETIME * SEGMENT.speed) >> 7); uint64_t deltat = (strip.now >> 2) + ((strip.now * SEGMENT.speed) >> 7); strip.now = deltat; - unsigned speedfactor1 = beatsin16(3, 179, 269); - unsigned speedfactor2 = beatsin16(4, 179, 269); + unsigned speedfactor1 = beatsin16_t(3, 179, 269); + unsigned speedfactor2 = beatsin16_t(4, 179, 269); uint32_t deltams1 = (deltams * speedfactor1) / 256; uint32_t deltams2 = (deltams * speedfactor2) / 256; uint32_t deltams21 = (deltams1 + deltams2) / 2; - sCIStart1 += (deltams1 * beatsin88(1011,10,13)); - sCIStart2 -= (deltams21 * beatsin88(777,8,11)); - sCIStart3 -= (deltams1 * beatsin88(501,5,7)); - sCIStart4 -= (deltams2 * beatsin88(257,4,6)); + sCIStart1 += (deltams1 * beatsin88_t(1011,10,13)); + sCIStart2 -= (deltams21 * beatsin88_t(777,8,11)); + sCIStart3 -= (deltams1 * beatsin88_t(501,5,7)); + sCIStart4 -= (deltams2 * beatsin88_t(257,4,6)); SEGENV.aux0 = sCIStart1; SEGENV.aux1 = sCIStart2; - SEGENV.step = sCIStart4; SEGENV.step = (SEGENV.step << 16) + sCIStart3; + SEGENV.step = (sCIStart4 << 16) | (sCIStart3 & 0xFFFF); // Clear out the LED array to a dim background blue-green //SEGMENT.fill(132618); - unsigned basethreshold = beatsin8( 9, 55, 65); + unsigned basethreshold = beatsin8_t( 9, 55, 65); unsigned wave = beat8( 7 ); for (int i = 0; i < SEGLEN; i++) { CRGB c = CRGB(2, 6, 10); // Render each of four layers, with different scales and speeds, that vary over time - c += pacifica_one_layer(i, pacifica_palette_1, sCIStart1, beatsin16(3, 11 * 256, 14 * 256), beatsin8(10, 70, 130), 0-beat16(301)); - c += pacifica_one_layer(i, pacifica_palette_2, sCIStart2, beatsin16(4, 6 * 256, 9 * 256), beatsin8(17, 40, 80), beat16(401)); - c += pacifica_one_layer(i, pacifica_palette_3, sCIStart3, 6 * 256 , beatsin8(9, 10,38) , 0-beat16(503)); - c += pacifica_one_layer(i, pacifica_palette_3, sCIStart4, 5 * 256 , beatsin8(8, 10,28) , beat16(601)); + c += pacifica_one_layer(i, pacifica_palette_1, sCIStart1, beatsin16_t(3, 11 * 256, 14 * 256), beatsin8_t(10, 70, 130), 0-beat16(301)); + c += pacifica_one_layer(i, pacifica_palette_2, sCIStart2, beatsin16_t(4, 6 * 256, 9 * 256), beatsin8_t(17, 40, 80), beat16(401)); + c += pacifica_one_layer(i, pacifica_palette_3, sCIStart3, 6 * 256 , beatsin8_t(9, 10,38) , 0-beat16(503)); + c += pacifica_one_layer(i, pacifica_palette_3, sCIStart4, 5 * 256 , beatsin8_t(8, 10,28) , beat16(601)); // Add extra 'white' to areas where the four layers of light have lined up brightly - unsigned threshold = scale8( sin8( wave), 20) + basethreshold; + unsigned threshold = scale8( sin8_t( wave), 20) + basethreshold; wave += 7; unsigned l = c.getAverageLight(); if (l > threshold) { @@ -4077,7 +4064,7 @@ uint16_t mode_pacifica() c.green = scale8(c.green, 200); c |= CRGB( 2, 5, 7); - SEGMENT.setPixelColor(i, c.red, c.green, c.blue); + SEGMENT.setPixelColor(i, c); } strip.now = nowOld; @@ -4187,7 +4174,7 @@ uint16_t mode_twinkleup(void) { // A very short twinkle routine for (int i = 0; i < SEGLEN; i++) { unsigned ranstart = random8(); // The starting value (aka brightness) for each pixel. Must be consistent each time through the loop for this to work. - unsigned pixBri = sin8(ranstart + 16 * strip.now/(256-SEGMENT.speed)); + unsigned pixBri = sin8_t(ranstart + 16 * strip.now/(256-SEGMENT.speed)); if (random8() > SEGMENT.intensity) pixBri = 0; SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(random8()+strip.now/100, false, PALETTE_SOLID_WRAP, 0), pixBri)); } @@ -4230,7 +4217,7 @@ uint16_t mode_noisepal(void) { // Slow noise SEGMENT.setPixelColor(i, color.red, color.green, color.blue); } - SEGENV.aux0 += beatsin8(10,1,4); // Moving along the distance. Vary it a bit with a sine wave. + SEGENV.aux0 += beatsin8_t(10,1,4); // Moving along the distance. Vary it a bit with a sine wave. return FRAMETIME; } @@ -4312,7 +4299,7 @@ uint16_t mode_chunchun(void) for (unsigned i = 0; i < numBirds; i++) { counter -= span; - unsigned megumin = sin16(counter) + 0x8000; + unsigned megumin = sin16_t(counter) + 0x8000; unsigned bird = uint32_t(megumin * SEGLEN) >> 16; uint32_t c = SEGMENT.color_from_palette((i * 255)/ numBirds, false, false, 0); // no palette wrapping bird = constrain(bird, 0U, SEGLEN-1U); @@ -4481,7 +4468,7 @@ uint16_t mode_washing_machine(void) { SEGENV.step += (speed * 2048) / (512 - SEGMENT.speed); for (int i = 0; i < SEGLEN; i++) { - uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7)); + uint8_t col = sin8_t(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(col, false, PALETTE_SOLID_WRAP, 3)); } @@ -4510,7 +4497,7 @@ uint16_t mode_blends(void) { unsigned offset = 0; for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, pixels[offset++]); - if (offset > pixelLen) offset = 0; + if (offset >= pixelLen) offset = 0; } return FRAMETIME; @@ -4644,7 +4631,7 @@ uint16_t mode_tv_simulator(void) { return FRAMETIME; } -static const char _data_FX_MODE_TV_SIMULATOR[] PROGMEM = "TV Simulator@!,!;;"; +static const char _data_FX_MODE_TV_SIMULATOR[] PROGMEM = "TV Simulator@!,!;;!;01"; /* @@ -4837,8 +4824,8 @@ static const char _data_FX_MODE_PERLINMOVE[] PROGMEM = "Perlin Move@!,# of pixel uint16_t mode_wavesins(void) { for (int i = 0; i < SEGLEN; i++) { - uint8_t bri = sin8(strip.now/4 + i * SEGMENT.intensity); - uint8_t index = beatsin8(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); // custom3 is reduced resolution slider + uint8_t bri = sin8_t(strip.now/4 + i * SEGMENT.intensity); + uint8_t index = beatsin8_t(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); // custom3 is reduced resolution slider //SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, index, bri, LINEARBLEND)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, bri)); } @@ -4860,9 +4847,9 @@ uint16_t mode_FlowStripe(void) { for (int i = 0; i < SEGLEN; i++) { int c = (abs(i - hl) / hl) * 127; - c = sin8(c); - c = sin8(c / 2 + t); - byte b = sin8(c + t/8); + c = sin8_t(c); + c = sin8_t(c / 2 + t); + byte b = sin8_t(c + t/8); SEGMENT.setPixelColor(i, CHSV(b + hue, 255, 255)); } @@ -4889,14 +4876,14 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma unsigned long t = strip.now/128; // timebase // outer stars for (size_t i = 0; i < 8; i++) { - x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i); - y = beatsin8(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + t * i); + x = beatsin8_t(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i); + y = beatsin8_t(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + t * i); SEGMENT.addPixelColorXY(x, y, SEGMENT.color_from_palette(i*32, false, PALETTE_SOLID_WRAP, SEGMENT.check1?0:255)); } // inner stars for (size_t i = 0; i < 4; i++) { - x = beatsin8(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + t * i); - y = beatsin8(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + t * i); + x = beatsin8_t(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + t * i); + y = beatsin8_t(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + t * i); SEGMENT.addPixelColorXY(x, y, SEGMENT.color_from_palette(255-i*64, false, PALETTE_SOLID_WRAP, SEGMENT.check1?0:255)); } // central white dot @@ -4930,10 +4917,10 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so SEGENV.aux0++; // hue SEGMENT.fadeToBlackBy(40); for (size_t i = 0; i < numLines; i++) { - byte x1 = beatsin8(2 + SEGMENT.speed/16, 0, (cols - 1)); - byte x2 = beatsin8(1 + SEGMENT.speed/16, 0, (rows - 1)); - byte y1 = beatsin8(5 + SEGMENT.speed/16, 0, (cols - 1), 0, i * 24); - byte y2 = beatsin8(3 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 48 + 64); + byte x1 = beatsin8_t(2 + SEGMENT.speed/16, 0, (cols - 1)); + byte x2 = beatsin8_t(1 + SEGMENT.speed/16, 0, (rows - 1)); + byte y1 = beatsin8_t(5 + SEGMENT.speed/16, 0, (cols - 1), 0, i * 24); + byte y2 = beatsin8_t(3 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 48 + 64); CRGB color = ColorFromPalette(SEGPALETTE, i * 255 / numLines + (SEGENV.aux0&0xFF), 255, LINEARBLEND); byte xsteps = abs8(x1 - y1) + 1; @@ -4972,8 +4959,8 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa SEGMENT.fadeToBlackBy(64); for (int i = 0; i < cols; i++) { - SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND)); - SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10+128), LINEARBLEND)); } SEGMENT.blur(SEGMENT.intensity>>3); @@ -5002,8 +4989,8 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma SEGMENT.fadeToBlackBy(135); for (int i = 0; i < rows; i++) { - int x = beatsin8(speeds, 0, cols - 1, 0, i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, i * freq + 128); - int x1 = beatsin8(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq); + int x = beatsin8_t(speeds, 0, cols - 1, 0, i * freq) + beatsin8_t(speeds - 7, 0, cols - 1, 0, i * freq + 128); + int x1 = beatsin8_t(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8_t(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq); unsigned hue = (i * 128 / rows) + ms; // skip every 4th row every now and then (fade it more) if ((i + ms / 8) & 3) { @@ -5104,9 +5091,9 @@ uint16_t mode_2DFrizzles(void) { // By: Stepko https://editor.so SEGMENT.fadeToBlackBy(16); for (size_t i = 8; i > 0; i--) { - SEGMENT.addPixelColorXY(beatsin8(SEGMENT.speed/8 + i, 0, cols - 1), - beatsin8(SEGMENT.intensity/8 - i, 0, rows - 1), - ColorFromPalette(SEGPALETTE, beatsin8(12, 0, 255), 255, LINEARBLEND)); + SEGMENT.addPixelColorXY(beatsin8_t(SEGMENT.speed/8 + i, 0, cols - 1), + beatsin8_t(SEGMENT.intensity/8 - i, 0, rows - 1), + ColorFromPalette(SEGPALETTE, beatsin8_t(12, 0, 255), 255, LINEARBLEND)); } SEGMENT.blur(SEGMENT.custom1>>3); @@ -5238,7 +5225,7 @@ uint16_t mode_2DHiphotic() { // By: ldirko https://edit for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(sin8(cos8(x * SEGMENT.speed/16 + a / 3) + sin8(y * SEGMENT.intensity/16 + a / 4) + a), false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(sin8_t(cos8_t(x * SEGMENT.speed/16 + a / 3) + sin8_t(y * SEGMENT.intensity/16 + a / 4) + a), false, PALETTE_SOLID_WRAP, 0)); } } @@ -5314,8 +5301,8 @@ uint16_t mode_2DJulia(void) { // An animated Julia set reAl = -0.94299f; // PixelBlaze example imAg = 0.3162f; - reAl += sin_t((float)strip.now/305.f)/20.f; - imAg += sin_t((float)strip.now/405.f)/20.f; + reAl += (float)sin16_t(strip.now * 34) / 655340.f; + imAg += (float)sin16_t(strip.now * 26) / 655340.f; dx = (xmax - xmin) / (cols); // Scale the delta x and y values to our matrix size. dy = (ymax - ymin) / (rows); @@ -5378,10 +5365,10 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline //for (int i=0; i < 4*(cols+rows); i ++) { for (int i=0; i < 256; i ++) { - //float xlocn = float(sin8(now/4+i*(SEGMENT.speed>>5))) / 255.0f; - //float ylocn = float(cos8(now/4+i*2)) / 255.0f; - uint_fast8_t xlocn = sin8(phase/2 + (i*SEGMENT.speed)/32); - uint_fast8_t ylocn = cos8(phase/2 + i*2); + //float xlocn = float(sin8_t(now/4+i*(SEGMENT.speed>>5))) / 255.0f; + //float ylocn = float(cos8_t(now/4+i*2)) / 255.0f; + uint_fast8_t xlocn = sin8_t(phase/2 + (i*SEGMENT.speed)/32); + uint_fast8_t ylocn = cos8_t(phase/2 + i*2); xlocn = (cols < 2) ? 1 : (map(2*xlocn, 0,511, 0,2*(cols-1)) +1) /2; // softhack007: "(2* ..... +1) /2" for proper rounding ylocn = (rows < 2) ? 1 : (map(2*ylocn, 0,511, 0,2*(rows-1)) +1) /2; // "rows > 1" is needed to avoid div/0 in map() SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0)); @@ -5481,8 +5468,8 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have int y3 = map(inoise8(strip.now * speed, 25355, 22685), 0, 255, 0, rows-1); // and one Lissajou function - int x1 = beatsin8(23 * speed, 0, cols-1); - int y1 = beatsin8(28 * speed, 0, rows-1); + int x1 = beatsin8_t(23 * speed, 0, cols-1); + int y1 = beatsin8_t(28 * speed, 0, rows-1); for (int y = 0; y < rows; y++) { for (int x = 0; x < cols; x++) { @@ -5647,7 +5634,7 @@ uint16_t mode_2DPulser(void) { // By: ldirko https://edi SEGMENT.fadeToBlackBy(8 - (SEGMENT.intensity>>5)); uint32_t a = strip.now / (18 - SEGMENT.speed / 16); int x = (a / 14) % cols; - int y = map((sin8(a * 5) + sin8(a * 4) + sin8(a * 2)), 0, 765, rows-1, 0); + int y = map((sin8_t(a * 5) + sin8_t(a * 4) + sin8_t(a * 2)), 0, 765, rows-1, 0); SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, map(y, 0, rows-1, 0, 255), 255, LINEARBLEND)); SEGMENT.blur(SEGMENT.intensity>>4); @@ -5673,10 +5660,10 @@ uint16_t mode_2DSindots(void) { // By: ldirko http SEGMENT.fadeToBlackBy(SEGMENT.custom1>>3); byte t1 = strip.now / (257 - SEGMENT.speed); // 20; - byte t2 = sin8(t1) / 4 * 2; + byte t2 = sin8_t(t1) / 4 * 2; for (int i = 0; i < 13; i++) { - int x = sin8(t1 + i * SEGMENT.intensity/8)*(cols-1)/255; // max index now 255x15/255=15! - int y = sin8(t2 + i * SEGMENT.intensity/8)*(rows-1)/255; // max index now 255x15/255=15! + int x = sin8_t(t1 + i * SEGMENT.intensity/8)*(cols-1)/255; // max index now 255x15/255=15! + int y = sin8_t(t2 + i * SEGMENT.intensity/8)*(rows-1)/255; // max index now 255x15/255=15! SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, i * 255 / 13, 255, LINEARBLEND)); } SEGMENT.blur(SEGMENT.custom2>>3); @@ -5703,12 +5690,12 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g SEGMENT.blur(SEGMENT.custom3>>1); // Use two out-of-sync sine waves - int i = beatsin8(19, kBorderWidth, cols-kBorderWidth); - int j = beatsin8(22, kBorderWidth, cols-kBorderWidth); - int k = beatsin8(17, kBorderWidth, cols-kBorderWidth); - int m = beatsin8(18, kBorderWidth, rows-kBorderWidth); - int n = beatsin8(15, kBorderWidth, rows-kBorderWidth); - int p = beatsin8(20, kBorderWidth, rows-kBorderWidth); + int i = beatsin8_t(19, kBorderWidth, cols-kBorderWidth); + int j = beatsin8_t(22, kBorderWidth, cols-kBorderWidth); + int k = beatsin8_t(17, kBorderWidth, cols-kBorderWidth); + int m = beatsin8_t(18, kBorderWidth, rows-kBorderWidth); + int n = beatsin8_t(15, kBorderWidth, rows-kBorderWidth); + int p = beatsin8_t(20, kBorderWidth, rows-kBorderWidth); SEGMENT.addPixelColorXY(i, m, ColorFromPalette(SEGPALETTE, strip.now/29, 255, LINEARBLEND)); SEGMENT.addPixelColorXY(j, n, ColorFromPalette(SEGPALETTE, strip.now/41, 255, LINEARBLEND)); @@ -5784,19 +5771,19 @@ uint16_t mode_2Dtartan(void) { // By: Elliott Kember https://editor.so uint8_t hue, bri; size_t intensity; - int offsetX = beatsin16(3, -360, 360); - int offsetY = beatsin16(2, -360, 360); + int offsetX = beatsin16_t(3, -360, 360); + int offsetY = beatsin16_t(2, -360, 360); int sharpness = SEGMENT.custom3 / 8; // 0-3 for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - hue = x * beatsin16(10, 1, 10) + offsetY; - intensity = bri = sin8(x * SEGMENT.speed/2 + offsetX); + hue = x * beatsin16_t(10, 1, 10) + offsetY; + intensity = bri = sin8_t(x * SEGMENT.speed/2 + offsetX); for (int i=0; i>= 8*sharpness; SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, intensity, LINEARBLEND)); hue = y * 3 + offsetX; - intensity = bri = sin8(y * SEGMENT.intensity/2 + offsetY); + intensity = bri = sin8_t(y * SEGMENT.intensity/2 + offsetY); for (int i=0; i>= 8*sharpness; SEGMENT.addPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, intensity, LINEARBLEND)); @@ -5831,9 +5818,9 @@ uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [ht SEGMENT.move(SEGENV.aux0, 1); for (size_t i = 0; i < 8; i++) { - int x = beatsin8(12 + i, 2, cols - 3); - int y = beatsin8(15 + i, 2, rows - 3); - CRGB color = ColorFromPalette(SEGPALETTE, beatsin8(12 + i, 0, 255), 255); + int x = beatsin8_t(12 + i, 2, cols - 3); + int y = beatsin8_t(15 + i, 2, rows - 3); + CRGB color = ColorFromPalette(SEGPALETTE, beatsin8_t(12 + i, 0, 255), 255); SEGMENT.addPixelColorXY(x, y, color); if (cols > 24 || rows > 24) { SEGMENT.addPixelColorXY(x+1, y, color); @@ -6229,8 +6216,8 @@ uint16_t mode_2Ddriftrose(void) { SEGMENT.fadeToBlackBy(32+(SEGMENT.speed>>3)); for (size_t i = 1; i < 37; i++) { float angle = radians(i * 10); - uint32_t x = (CX + (sin_t(angle) * (beatsin8(i, 0, L*2)-L))) * 255.f; - uint32_t y = (CY + (cos_t(angle) * (beatsin8(i, 0, L*2)-L))) * 255.f; + uint32_t x = (CX + (sin_t(angle) * (beatsin8_t(i, 0, L*2)-L))) * 255.f; + uint32_t y = (CY + (cos_t(angle) * (beatsin8_t(i, 0, L*2)-L))) * 255.f; SEGMENT.wu_pixel(x, y, CHSV(i * 10, 255, 255)); } SEGMENT.blur(SEGMENT.intensity>>4); @@ -6279,6 +6266,7 @@ uint16_t mode_2Dplasmarotozoom() { } } *a -= 0.03f + float(SEGENV.speed-128)*0.0002f; // rotation speed + if(*a < -6283.18530718f) *a += 6283.18530718f; // 1000*2*PI, protect sin/cos from very large input float values (will give wrong results) return FRAMETIME; } @@ -6426,8 +6414,8 @@ uint16_t mode_2DSwirl(void) { SEGMENT.blur(SEGMENT.custom1); - int i = beatsin8( 27*SEGMENT.speed/255, borderWidth, cols - borderWidth); - int j = beatsin8( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); + int i = beatsin8_t( 27*SEGMENT.speed/255, borderWidth, cols - borderWidth); + int j = beatsin8_t( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); int ni = (cols - 1) - i; int nj = (cols - 1) - j; @@ -6639,7 +6627,7 @@ uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. for (size_t i=0; ithisphase += beatsin8(6,-4,4); // You can change direction and speed individually. - plasmoip->thatphase += beatsin8(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline. + plasmoip->thisphase += beatsin8_t(6,-4,4); // You can change direction and speed individually. + plasmoip->thatphase += beatsin8_t(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline. for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows. // updated, similar to "plasma" effect - softhack007 uint8_t thisbright = cubicwave8(((i*(1 + (3*SEGMENT.speed/32)))+plasmoip->thisphase) & 0xFF)/2; - thisbright += cos8(((i*(97 +(5*SEGMENT.speed/32)))+plasmoip->thatphase) & 0xFF)/2; // Let's munge the brightness a bit and animate it all with the phases. + thisbright += cos8_t(((i*(97 +(5*SEGMENT.speed/32)))+plasmoip->thatphase) & 0xFF)/2; // Let's munge the brightness a bit and animate it all with the phases. uint8_t colorIndex=thisbright; if (volumeSmth * SEGMENT.intensity / 64 < thisbright) {thisbright = 0;} @@ -7280,7 +7268,7 @@ uint16_t mode_rocktaves(void) { // Rocktaves. Same note from eac frTemp -= 132.0f; // This should give us a base musical note of C3 frTemp = fabsf(frTemp * 2.1f); // Fudge factors to compress octave range starting at 0 and going to 255; - unsigned i = map(beatsin8(8+octCount*4, 0, 255, 0, octCount*8), 0, 255, 0, SEGLEN-1); + unsigned i = map(beatsin8_t(8+octCount*4, 0, 255, 0, octCount*8), 0, 255, 0, SEGLEN-1); i = constrain(i, 0U, SEGLEN-1U); SEGMENT.addPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette((uint8_t)frTemp, false, PALETTE_SOLID_WRAP, 0), volTemp)); @@ -7567,12 +7555,12 @@ uint16_t mode_2Ddistortionwaves() { unsigned a2 = a/2; unsigned a3 = a/3; - unsigned cx = beatsin8(10-speed,0,cols-1)*scale; - unsigned cy = beatsin8(12-speed,0,rows-1)*scale; - unsigned cx1 = beatsin8(13-speed,0,cols-1)*scale; - unsigned cy1 = beatsin8(15-speed,0,rows-1)*scale; - unsigned cx2 = beatsin8(17-speed,0,cols-1)*scale; - unsigned cy2 = beatsin8(14-speed,0,rows-1)*scale; + unsigned cx = beatsin8_t(10-speed,0,cols-1)*scale; + unsigned cy = beatsin8_t(12-speed,0,rows-1)*scale; + unsigned cx1 = beatsin8_t(13-speed,0,cols-1)*scale; + unsigned cy1 = beatsin8_t(15-speed,0,rows-1)*scale; + unsigned cx2 = beatsin8_t(17-speed,0,cols-1)*scale; + unsigned cy2 = beatsin8_t(14-speed,0,rows-1)*scale; unsigned xoffs = 0; for (int x = 0; x < cols; x++) { @@ -7582,17 +7570,17 @@ uint16_t mode_2Ddistortionwaves() { for (int y = 0; y < rows; y++) { yoffs += scale; - byte rdistort = cos8((cos8(((x<<3)+a )&255)+cos8(((y<<3)-a2)&255)+a3 )&255)>>1; - byte gdistort = cos8((cos8(((x<<3)-a2)&255)+cos8(((y<<3)+a3)&255)+a+32 )&255)>>1; - byte bdistort = cos8((cos8(((x<<3)+a3)&255)+cos8(((y<<3)-a) &255)+a2+64)&255)>>1; + byte rdistort = cos8_t((cos8_t(((x<<3)+a )&255)+cos8_t(((y<<3)-a2)&255)+a3 )&255)>>1; + byte gdistort = cos8_t((cos8_t(((x<<3)-a2)&255)+cos8_t(((y<<3)+a3)&255)+a+32 )&255)>>1; + byte bdistort = cos8_t((cos8_t(((x<<3)+a3)&255)+cos8_t(((y<<3)-a) &255)+a2+64)&255)>>1; byte valueR = rdistort+ w* (a- ( ((xoffs - cx) * (xoffs - cx) + (yoffs - cy) * (yoffs - cy))>>7 )); byte valueG = gdistort+ w* (a2-( ((xoffs - cx1) * (xoffs - cx1) + (yoffs - cy1) * (yoffs - cy1))>>7 )); byte valueB = bdistort+ w* (a3-( ((xoffs - cx2) * (xoffs - cx2) + (yoffs - cy2) * (yoffs - cy2))>>7 )); - valueR = gamma8(cos8(valueR)); - valueG = gamma8(cos8(valueG)); - valueB = gamma8(cos8(valueB)); + valueR = gamma8(cos8_t(valueR)); + valueG = gamma8(cos8_t(valueG)); + valueB = gamma8(cos8_t(valueB)); SEGMENT.setPixelColorXY(x, y, RGBW32(valueR, valueG, valueB, 0)); } @@ -7749,8 +7737,10 @@ uint16_t mode_2Doctopus() { const int C_Y = (rows / 2) + ((SEGMENT.custom2 - 128)*rows)/255; for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - rMap[XY(x, y)].angle = 40.7436f * atan2f((y - C_Y), (x - C_X)); // avoid 128*atan2()/PI - rMap[XY(x, y)].radius = hypotf((x - C_X), (y - C_Y)) * mapp; //thanks Sutaburosu + int dx = (x - C_X); + int dy = (y - C_Y); + rMap[XY(x, y)].angle = int(40.7436f * atan2_t(dy, dx)); // avoid 128*atan2()/PI + rMap[XY(x, y)].radius = sqrtf(dx * dx + dy * dy) * mapp; //thanks Sutaburosu } } } @@ -7760,8 +7750,8 @@ uint16_t mode_2Doctopus() { for (int y = 0; y < rows; y++) { byte angle = rMap[XY(x,y)].angle; byte radius = rMap[XY(x,y)].radius; - //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); - unsigned intensity = sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step/2) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); + //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8_t(sin8_t((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); + unsigned intensity = sin8_t(sin8_t((angle * 4 - radius) / 4 + SEGENV.step/2) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); intensity = map((intensity*intensity) & 0xFFFF, 0, 65535, 0, 255); // add a bit of non-linearity for cleaner display CRGB c = ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity); SEGMENT.setPixelColorXY(x, y, c); @@ -7769,7 +7759,7 @@ uint16_t mode_2Doctopus() { } return FRAMETIME; } -static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offset Y,Legs;;!;2;"; +static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offset Y,Legs,fasttan;;!;2;"; //Waving Cell @@ -7786,7 +7776,7 @@ uint16_t mode_2Dwavingcell() { uint8_t aY = SEGMENT.custom2/16 + 1; uint8_t aZ = SEGMENT.custom3 + 1; for (int x = 0; x < cols; x++) for (int y = 0; y = virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit + if ((unsigned)x >= virtualWidth() || (unsigned)y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit uint8_t _bri_t = currentBri(); if (_bri_t < 255) { @@ -266,7 +251,7 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) // returns RGBW values of pixel uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const { if (!isActive()) return 0; // not active - if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit + if ((unsigned)x >= virtualWidth() || (unsigned)y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit if (reverse ) x = virtualWidth() - x - 1; if (reverse_y) y = virtualHeight() - y - 1; if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 1bbfa365..88fec3d8 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -2,24 +2,10 @@ WS2812FX_fcn.cpp contains all utility functions Harm Aldick - 2016 www.aldick.org - LICENSE - The MIT License (MIT) + Copyright (c) 2016 Harm Aldick - 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. + Licensed under the EUPL v. 1.2 or later + Adapted from code originally licensed under the MIT license Modified heavily for WLED */ @@ -89,6 +75,7 @@ CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); // was CRG CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR); uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only) +uint16_t Segment::_transitionprogress = 0xFFFF; #ifndef WLED_DISABLE_MODE_BLEND bool Segment::_modeBlend = false; @@ -226,7 +213,7 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { case 0: //default palette. Exceptions for specific effects above targetPalette = PartyColors_p; break; case 1: //randomly generated palette - targetPalette = _randomPalette; //random palette is generated at intervals in handleRandomPalette() + targetPalette = _randomPalette; //random palette is generated at intervals in handleRandomPalette() break; case 2: {//primary color only CRGB prim = gamma32(colors[0]); @@ -250,23 +237,11 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,sec,sec,sec); } break;} - case 6: //Party colors - targetPalette = PartyColors_p; break; - case 7: //Cloud colors - targetPalette = CloudColors_p; break; - case 8: //Lava colors - targetPalette = LavaColors_p; break; - case 9: //Ocean colors - targetPalette = OceanColors_p; break; - case 10: //Forest colors - targetPalette = ForestColors_p; break; - case 11: //Rainbow colors - targetPalette = RainbowColors_p; break; - case 12: //Rainbow stripe colors - targetPalette = RainbowStripeColors_p; break; default: //progmem palettes if (pal>245) { targetPalette = strip.customPalettes[255-pal]; // we checked bounds above + } else if (pal < 13) { // palette 6 - 12, fastled palettes + targetPalette = *fastledPalettes[pal-6]; } else { byte tcp[72]; memcpy_P(tcp, (byte*)pgm_read_dword(&(gGradientPalettes[pal-13])), 72); @@ -331,12 +306,12 @@ void Segment::stopTransition() { } // transition progression between 0-65535 -uint16_t IRAM_ATTR Segment::progress() const { +inline void Segment::updateTransitionProgress() { + _transitionprogress = 0xFFFFU; if (isInTransition()) { unsigned diff = millis() - _t->_start; - if (_t->_dur > 0 && diff < _t->_dur) return diff * 0xFFFFU / _t->_dur; + if (_t->_dur > 0 && diff < _t->_dur) _transitionprogress = diff * 0xFFFFU / _t->_dur; } - return 0xFFFFU; } #ifndef WLED_DISABLE_MODE_BLEND @@ -456,7 +431,7 @@ void Segment::handleRandomPalette() { if ((uint16_t)((uint16_t)(millis() / 1000U) - _lastPaletteChange) > randomPaletteChangeTime){ _newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette(); _lastPaletteChange = (uint16_t)(millis() / 1000U); - _lastPaletteBlend = (uint16_t)((uint16_t)millis() - 512); // starts blending immediately + _lastPaletteBlend = (uint16_t)((uint16_t)millis() - 512); // starts blending immediately } // if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls) @@ -523,46 +498,53 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t } -bool Segment::setColor(uint8_t slot, uint32_t c) { //returns true if changed - if (slot >= NUM_COLORS || c == colors[slot]) return false; +Segment &Segment::setColor(uint8_t slot, uint32_t c) { + if (slot >= NUM_COLORS || c == colors[slot]) return *this; if (!_isRGB && !_hasW) { - if (slot == 0 && c == BLACK) return false; // on/off segment cannot have primary color black - if (slot == 1 && c != BLACK) return false; // on/off segment cannot have secondary color non black + if (slot == 0 && c == BLACK) return *this; // on/off segment cannot have primary color black + if (slot == 1 && c != BLACK) return *this; // on/off segment cannot have secondary color non black } if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change colors[slot] = c; stateChanged = true; // send UDP/WS broadcast - return true; + return *this; } -void Segment::setCCT(uint16_t k) { +Segment &Segment::setCCT(uint16_t k) { if (k > 255) { //kelvin value, convert to 0-255 if (k < 1900) k = 1900; if (k > 10091) k = 10091; k = (k - 1900) >> 5; } - if (cct == k) return; - if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change - cct = k; - stateChanged = true; // send UDP/WS broadcast + if (cct != k) { + //DEBUGFX_PRINTF_P(PSTR("- Starting CCT transition: %d\n"), k); + startTransition(strip.getTransition()); // start transition prior to change + cct = k; + stateChanged = true; // send UDP/WS broadcast + } + return *this; } -void Segment::setOpacity(uint8_t o) { - if (opacity == o) return; - if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change - opacity = o; - stateChanged = true; // send UDP/WS broadcast +Segment &Segment::setOpacity(uint8_t o) { + if (opacity != o) { + //DEBUGFX_PRINTF_P(PSTR("- Starting opacity transition: %d\n"), o); + startTransition(strip.getTransition()); // start transition prior to change + opacity = o; + stateChanged = true; // send UDP/WS broadcast + } + return *this; } -void Segment::setOption(uint8_t n, bool val) { +Segment &Segment::setOption(uint8_t n, bool val) { bool prevOn = on; if (fadeTransition && n == SEG_OPTION_ON && val != prevOn) startTransition(strip.getTransition()); // start transition prior to change if (val) options |= 0x01 << n; else options &= ~(0x01 << n); if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET)) stateChanged = true; // send UDP/WS broadcast + return *this; } -void Segment::setMode(uint8_t fx, bool loadDefaults) { +Segment &Segment::setMode(uint8_t fx, bool loadDefaults) { // skip reserved while (fx < strip.getModeCount() && strncmp_P("RSVD", strip.getModeData(fx), 4) == 0) fx++; if (fx >= strip.getModeCount()) fx = 0; // set solid mode @@ -594,9 +576,10 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) { markForReset(); stateChanged = true; // send UDP/WS broadcast } + return *this; } -void Segment::setPalette(uint8_t pal) { +Segment &Segment::setPalette(uint8_t pal) { if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; // built in palettes if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // custom palettes if (pal != palette) { @@ -604,37 +587,24 @@ void Segment::setPalette(uint8_t pal) { palette = pal; stateChanged = true; // send UDP/WS broadcast } + return *this; } // 2D matrix -uint16_t IRAM_ATTR Segment::virtualWidth() const { +unsigned IRAM_ATTR Segment::virtualWidth() const { unsigned groupLen = groupLength(); unsigned vWidth = ((transpose ? height() : width()) + groupLen - 1) / groupLen; if (mirror) vWidth = (vWidth + 1) /2; // divide by 2 if mirror, leave at least a single LED return vWidth; } -uint16_t IRAM_ATTR Segment::virtualHeight() const { +unsigned IRAM_ATTR Segment::virtualHeight() const { unsigned groupLen = groupLength(); unsigned vHeight = ((transpose ? width() : height()) + groupLen - 1) / groupLen; if (mirror_y) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED return vHeight; } -uint16_t IRAM_ATTR_YN Segment::nrOfVStrips() const { - unsigned vLen = 1; -#ifndef WLED_DISABLE_2D - if (is2D()) { - switch (map1D2D) { - case M12_pBar: - vLen = virtualWidth(); - break; - } - } -#endif - return vLen; -} - // Constants for mapping mode "Pinwheel" #ifndef WLED_DISABLE_2D constexpr int Pinwheel_Steps_Small = 72; // no holes up to 16x16 @@ -787,7 +757,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) // Odd rays start further from center if prevRay started at center. static int prevRay = INT_MIN; // previous ray number if ((i % 2 == 1) && (i - 1 == prevRay || i + 1 == prevRay)) { - int jump = min(vW/3, vH/3); // can add 2 if using medium pinwheel + int jump = min(vW/3, vH/3); // can add 2 if using medium pinwheel posx += inc_x * jump; posy += inc_y * jump; } @@ -1201,10 +1171,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_ //do not call this method from system context (network callback) void WS2812FX::finalizeInit() { //reset segment runtimes - for (segment &seg : _segments) { - seg.markForReset(); - seg.resetIfRequired(); - } + restartRuntime(); // for the lack of better place enumerate ledmaps here // if we do it in json.cpp (serializeInfo()) we are getting flashes on LEDs @@ -1226,7 +1193,7 @@ void WS2812FX::finalizeInit() { static_assert(validatePinsAndTypes(defDataTypes, defNumTypes, defNumPins), "The default pin list defined in DATA_PINS does not match the pin requirements for the default buses defined in LED_TYPES"); - + unsigned prevLen = 0; unsigned pinsIndex = 0; for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { @@ -1237,7 +1204,7 @@ void WS2812FX::finalizeInit() { // if we need more pins than available all outputs have been configured if (pinsIndex + busPins > defNumPins) break; - + // Assign all pins first so we can check for conflicts on this bus for (unsigned j = 0; j < busPins && j < OUTPUT_MAX_PINS; j++) defPin[j] = defDataPins[pinsIndex + j]; @@ -1308,14 +1275,9 @@ void WS2812FX::finalizeInit() { _isOffRefreshRequired |= bus->isOffRefreshRequired() && !bus->isPWM(); // use refresh bit for phase shift with analog unsigned busEnd = bus->getStart() + bus->getLength(); if (busEnd > _length) _length = busEnd; - #ifdef ESP8266 - // why do we need to reinitialise GPIO3??? - //if (!bus->isDigital() || bus->is2Pin()) continue; - //uint8_t pins[5]; - //if (!bus->getPins(pins)) continue; - //BusDigital* bd = static_cast(bus); - //if (pins[0] == 3) bd->reinit(); - #endif + + // This must be done after all buses have been created, as some kinds (parallel I2S) interact + bus->begin(); } Segment::maxWidth = _length; @@ -1331,7 +1293,14 @@ void WS2812FX::finalizeInit() { void WS2812FX::service() { unsigned long nowUp = millis(); // Be aware, millis() rolls over every 49 days now = nowUp + timebase; - if (nowUp - _lastShow < MIN_SHOW_DELAY || _suspend) return; + if (_suspend) return; + unsigned long elapsed = nowUp - _lastServiceShow; + + if (elapsed <= MIN_FRAME_DELAY) return; // keep wifi alive - no matter if triggered or unlimited + if ( !_triggered && (_targetFps != FPS_UNLIMITED)) { // unlimited mode = no frametime + if (elapsed < _frametime) return; // too early for service + } + bool doShow = false; _isServicing = true; @@ -1348,10 +1317,10 @@ void WS2812FX::service() { if (!seg.isActive()) continue; // last condition ensures all solid segments are updated at the same time - if (nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC)) + if (nowUp >= seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC)) { doShow = true; - unsigned delay = FRAMETIME; + unsigned frameDelay = FRAMETIME; if (!seg.freeze) { //only run effect function if not frozen int oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based) @@ -1371,7 +1340,7 @@ void WS2812FX::service() { // overwritten by later effect. To enable seamless blending for every effect, additional LED buffer // would need to be allocated for each effect and then blended together for each pixel. [[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition - delay = (*_mode[seg.mode])(); // run new/current mode + frameDelay = (*_mode[seg.mode])(); // run new/current mode #ifndef WLED_DISABLE_MODE_BLEND if (modeBlending && seg.mode != tmpMode) { Segment::tmpsegd_t _tmpSegData; @@ -1380,16 +1349,16 @@ void WS2812FX::service() { _virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed) unsigned d2 = (*_mode[tmpMode])(); // run old mode seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state) - delay = MIN(delay,d2); // use shortest delay + frameDelay = min(frameDelay,d2); // use shortest delay Segment::modeBlend(false); // unset semaphore } #endif seg.call++; - if (seg.isInTransition() && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition + if (seg.isInTransition() && frameDelay > FRAMETIME) frameDelay = FRAMETIME; // force faster updates during transition BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments } - seg.next_time = nowUp + delay; + seg.next_time = nowUp + frameDelay; } _segment_index++; } @@ -1398,15 +1367,16 @@ void WS2812FX::service() { _triggered = false; #ifdef WLED_DEBUG - if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); + if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); #endif if (doShow) { yield(); Segment::handleRandomPalette(); // slowly transition random palette; move it into for loop when each segment has individual random palette show(); + _lastServiceShow = nowUp; // update timestamp, for precise FPS control } #ifdef WLED_DEBUG - if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); + if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); #endif } @@ -1416,7 +1386,7 @@ void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) { BusManager::setPixelColor(i, col); } -uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) const { +uint32_t IRAM_ATTR WS2812FX::getPixelColor(unsigned i) const { i = getMappedPixelIndex(i); if (i >= _length) return 0; return BusManager::getPixelColor(i); @@ -1426,18 +1396,20 @@ void WS2812FX::show() { // avoid race condition, capture _callback value show_callback callback = _callback; if (callback) callback(); + unsigned long showNow = millis(); // some buses send asynchronously and this method will return before // all of the data has been sent. // See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods BusManager::show(); - unsigned long showNow = millis(); size_t diff = showNow - _lastShow; - size_t fpsCurr = 200; - if (diff > 0) fpsCurr = 1000 / diff; - _cumulativeFps = (3 * _cumulativeFps + fpsCurr +2) >> 2; // "+2" for proper rounding (2/4 = 0.5) - _lastShow = showNow; + + if (diff > 0) { // skip calculation if no time has passed + size_t fpsCurr = (1000 << FPS_CALC_SHIFT) / diff; // fixed point math + _cumulativeFps = (FPS_CALC_AVG * _cumulativeFps + fpsCurr + FPS_CALC_AVG / 2) / (FPS_CALC_AVG + 1); // "+FPS_CALC_AVG/2" for proper rounding + _lastShow = showNow; + } } /** @@ -1454,12 +1426,13 @@ bool WS2812FX::isUpdating() const { */ uint16_t WS2812FX::getFps() const { if (millis() - _lastShow > 2000) return 0; - return _cumulativeFps +1; + return (FPS_MULTIPLIER * _cumulativeFps) >> FPS_CALC_SHIFT; // _cumulativeFps is stored in fixed point } void WS2812FX::setTargetFps(uint8_t fps) { - if (fps > 0 && fps <= 120) _targetFps = fps; - _frametime = 1000 / _targetFps; + if (fps <= 250) _targetFps = fps; + if (_targetFps > 0) _frametime = 1000 / _targetFps; + else _frametime = MIN_FRAME_DELAY; // unlimited mode } void WS2812FX::setMode(uint8_t segid, uint8_t m) { @@ -1507,7 +1480,7 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) { BusManager::setBrightness(b); if (!direct) { unsigned long t = millis(); - if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) trigger(); //apply brightness change immediately if no refresh soon + if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_FRAME_DELAY) trigger(); //apply brightness change immediately if no refresh soon } } diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 620b7312..9e4607a0 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -179,7 +179,7 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) //_buffering = bc.doubleBuffer; uint16_t lenToCreate = bc.count; if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus - _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr, _frequencykHz); + _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr); _valid = (_busPtr != nullptr); DEBUG_PRINTF_P(PSTR("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n"), _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], is2Pin(bc.type)?_pins[1]:255, _iType, _milliAmpsPerLed, _milliAmpsMax); } @@ -439,9 +439,9 @@ std::vector BusDigital::getLEDTypes() { }; } -void BusDigital::reinit() { +void BusDigital::begin() { if (!_valid) return; - PolyBus::begin(_busPtr, _iType, _pins); + PolyBus::begin(_busPtr, _iType, _pins, _frequencykHz); } void BusDigital::cleanup() { @@ -1275,7 +1275,7 @@ void BusManager::on() { if (busses[i]->isDigital() && busses[i]->getPins(pins)) { if (pins[0] == LED_BUILTIN || pins[1] == LED_BUILTIN) { BusDigital *bus = static_cast(busses[i]); - bus->reinit(); + bus->begin(); break; } } diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 80758977..f78a76a0 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -86,6 +86,7 @@ class Bus { virtual ~Bus() {} //throw the bus under the bus + virtual void begin() {}; virtual void show() = 0; virtual bool canShow() const { return true; } virtual void setStatusPixel(uint32_t c) {} @@ -222,7 +223,7 @@ class BusDigital : public Bus { uint16_t getLEDCurrent() const override { return _milliAmpsPerLed; } uint16_t getUsedCurrent() const override { return _milliAmpsTotal; } uint16_t getMaxCurrent() const override { return _milliAmpsMax; } - void reinit(); + void begin() override; void cleanup(); static std::vector getLEDTypes(); diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index 84c32f46..d2a18c9d 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -336,7 +336,7 @@ class PolyBus { // initialize SPI bus speed for DotStar methods template - static void beginDotStar(void* busPtr, int8_t sck, int8_t miso, int8_t mosi, int8_t ss, uint16_t clock_kHz = 0U) { + static void beginDotStar(void* busPtr, int8_t sck, int8_t miso, int8_t mosi, int8_t ss, uint16_t clock_kHz /* 0 == use default */) { T dotStar_strip = static_cast(busPtr); #ifdef ESP8266 dotStar_strip->Begin(); @@ -363,7 +363,7 @@ class PolyBus { tm1914_strip->SetPixelSettings(NeoTm1914Settings()); //NeoTm1914_Mode_DinFdinAutoSwitch, NeoTm1914_Mode_DinOnly, NeoTm1914_Mode_FdinOnly } - static void begin(void* busPtr, uint8_t busType, uint8_t* pins, uint16_t clock_kHz = 0U) { + static void begin(void* busPtr, uint8_t busType, uint8_t* pins, uint16_t clock_kHz /* only used by DotStar */) { switch (busType) { case I_NONE: break; #ifdef ESP8266 @@ -480,7 +480,7 @@ class PolyBus { } } - static void* create(uint8_t busType, uint8_t* pins, uint16_t len, uint8_t channel, uint16_t clock_kHz = 0U) { + static void* create(uint8_t busType, uint8_t* pins, uint16_t len, uint8_t channel) { #if defined(ARDUINO_ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)) // NOTE: "channel" is only used on ESP32 (and its variants) for RMT channel allocation // since 0.15.0-b3 I2S1 is favoured for classic ESP32 and moved to position 0 (channel 0) so we need to subtract 1 for correct RMT allocation @@ -597,7 +597,7 @@ class PolyBus { case I_HS_P98_3: busPtr = new B_HS_P98_3(len, pins[1], pins[0]); break; case I_SS_P98_3: busPtr = new B_SS_P98_3(len, pins[1], pins[0]); break; } - begin(busPtr, busType, pins, clock_kHz); + return busPtr; } diff --git a/wled00/button.cpp b/wled00/button.cpp index f02ed3d6..4d6f954f 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -215,6 +215,7 @@ void handleAnalog(uint8_t b) briLast = bri; bri = 0; } else { + if (bri == 0) strip.restartRuntime(); bri = aRead; } } else if (macroDoublePress[b] == 249) { diff --git a/wled00/const.h b/wled00/const.h index 94681a13..bfd06aac 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -53,7 +53,7 @@ #else #define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX) #if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM - #define WLED_MAX_BUSSES 4 // will allow 2 digital & 2 analog RGB + #define WLED_MAX_BUSSES 6 // will allow 2 digital & 2 analog RGB or 6 PWM white #define WLED_MAX_DIGITAL_CHANNELS 2 //#define WLED_MAX_ANALOG_CHANNELS 6 #define WLED_MIN_VIRTUAL_BUSSES 3 diff --git a/wled00/data/cpal/cpal.htm b/wled00/data/cpal/cpal.htm index b58c0987..8fa715bc 100644 --- a/wled00/data/cpal/cpal.htm +++ b/wled00/data/cpal/cpal.htm @@ -167,9 +167,10 @@
-
- Currently in use custom palettes -
+
+
+ Currently in use custom palettes +
@@ -187,7 +188,7 @@ Available static palettes - + @@ -204,6 +205,13 @@ var paletteName = []; // Holds the names of the palettes after load. var svgSave = '' var svgEdit = '' + var svgDist = '' + var svgTrash = '' + + const distDiv = gId("distDiv"); + distDiv.addEventListener('click', distribute); + distDiv.setAttribute('title', 'Distribute colors equally'); + distDiv.innerHTML = svgDist; function recOf() { rect = gradientBox.getBoundingClientRect(); @@ -433,7 +441,7 @@ renderY = e.srcElement.getBoundingClientRect().y + 13; trash.id = "trash"; - trash.innerHTML = ''; + trash.innerHTML = svgTrash; trash.style.position = "absolute"; trash.style.left = (renderX) + "px"; trash.style.top = (renderY) + "px"; @@ -712,9 +720,27 @@ } } + function distribute() { + let colorMarkers = [...gradientBox.querySelectorAll('.color-marker')]; + colorMarkers.sort((a, b) => a.getAttribute('data-truepos') - b.getAttribute('data-truepos')); + colorMarkers = colorMarkers.slice(1, -1); + const spacing = Math.round(256 / (colorMarkers.length + 1)); + + colorMarkers.forEach((e, i) => { + const markerId = e.id.match(/\d+/)[0]; + const trueCol = e.getAttribute("data-truecol"); + gradientBox.removeChild(e); + gradientBox.removeChild(gId(`colorPicker${markerId}`)); + gradientBox.removeChild(gId(`colorPickerMarker${markerId}`)); + gradientBox.removeChild(gId(`deleteMarker${markerId}`)); + addC(spacing * (i + 1), trueCol); + }); + } + function rgbToHex(r, g, b) { const hex = ((r << 16) | (g << 8) | b).toString(16); return "#" + "0".repeat(6 - hex.length) + hex; } + diff --git a/wled00/data/index.css b/wled00/data/index.css index c4e85f73..31e2daa9 100644 --- a/wled00/data/index.css +++ b/wled00/data/index.css @@ -97,6 +97,7 @@ button { .labels { margin: 0; padding: 8px 0 2px 0; + font-size: 19px; } #namelabel { @@ -144,7 +145,7 @@ button { } .huge { - font-size: 42px; + font-size: 60px !important; } .segt, .plentry TABLE { @@ -584,6 +585,10 @@ button { z-index: 3; } +#rover .ibtn { + margin: 5px; +} + #ndlt { margin: 12px 0; } @@ -624,7 +629,7 @@ button { padding-bottom: 8px; } -.infobtn { +#info .ibtn { margin: 5px; } @@ -848,7 +853,7 @@ input[type=range]::-moz-range-thumb { width: 135px; } -#nodes .infobtn { +#nodes .ibtn { margin: 0; } @@ -886,12 +891,12 @@ a.btn { line-height: 28px; } -/* Quick color select Black button (has white border) */ -.qcsb { +/* Quick color select Black and White button (has white/black border, depending on the theme) */ +.qcsb, .qcsw { width: 26px; height: 26px; line-height: 26px; - border: 1px solid #fff; + border: 1px solid var(--c-f); } /* Hex color input wrapper div */ @@ -1036,7 +1041,7 @@ textarea { .segname .flr, .pname .flr { transform: rotate(0deg); - right: -6px; + /*right: -6px;*/ } /* segment power wrapper */ @@ -1295,6 +1300,14 @@ TD .checkmark, TD .radiomark { width: 100%; } +#segutil { + margin-bottom: 12px; +} + +#segcont > div:first-child, #fxFind { + margin-top: 4px; +} + /* Simplify segments */ .simplified #segcont .lstI { margin-top: 4px; @@ -1331,6 +1344,11 @@ TD .checkmark, TD .radiomark { box-shadow: 0 0 10px 4px var(--c-1); } +.lstI .flr:hover { + background: var(--c-6); + border-radius: 100%; +} + #pcont .selected:not([class*="expanded"]) { bottom: 52px; top: 42px; @@ -1429,6 +1447,11 @@ dialog { position: relative; } +.presin { + width: 100%; + box-sizing: border-box; +} + .btn-s, .btn-n { border: 1px solid var(--c-2); @@ -1524,7 +1547,7 @@ dialog { #info table .btn, #nodes table .btn { width: 200px; } - #info .infobtn, #nodes .infobtn { + #info .ibtn, #nodes .ibtn { width: 145px; } #info div, #nodes div, #nodes a.btn { diff --git a/wled00/data/index.htm b/wled00/data/index.htm index 86b3b187..8adec791 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -106,7 +106,7 @@
-
+

@@ -304,10 +304,10 @@
Loading...

- - - - + + + +

Made with ❤︎ by Aircoookie and the WLED community @@ -318,7 +318,7 @@
WLED instances
Loading...
- +
@@ -331,8 +331,8 @@
?


To use built-in effects, use an override button below.
You can return to realtime mode by pressing the star in the top left corner.
- -
+ +
For best performance, it is recommended to turn off the streaming source when not in use. diff --git a/wled00/data/index.js b/wled00/data/index.js index d9c64bdf..1482c27b 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -2827,7 +2827,7 @@ function search(field, listId = null) { // restore default preset sorting if no search term is entered if (!search) { - if (listId === 'pcont') { populatePresets(); return; } + if (listId === 'pcont') { populatePresets(); return; } if (listId === 'pallist') { let id = parseInt(d.querySelector('#pallist input[name="palette"]:checked').value); // preserve selected palette populatePalettes(); @@ -2846,12 +2846,16 @@ function search(field, listId = null) { // filter list items but leave (Default & Solid) always visible const listItems = gId(listId).querySelectorAll('.lstI'); - listItems.forEach((listItem,i)=>{ - if (listId!=='pcont' && i===0) return; + listItems.forEach((listItem, i) => { + if (listId !== 'pcont' && i === 0) return; const listItemName = listItem.querySelector('.lstIname').innerText.toUpperCase(); const searchIndex = listItemName.indexOf(field.value.toUpperCase()); - listItem.style.display = (searchIndex < 0) ? 'none' : ''; - listItem.dataset.searchIndex = searchIndex; + if (searchIndex < 0) { + listItem.dataset.searchIndex = Number.MAX_SAFE_INTEGER; + } else { + listItem.dataset.searchIndex = searchIndex; + } + listItem.style.display = (searchIndex < 0) && !listItem.classList.contains("selected") ? 'none' : ''; }); // sort list items by search index and name @@ -2920,11 +2924,11 @@ function filterFx() { inputField.value = ''; inputField.focus(); clean(inputField.nextElementSibling); - gId("fxlist").querySelectorAll('.lstI').forEach((listItem,i) => { + gId("fxlist").querySelectorAll('.lstI').forEach((listItem, i) => { const listItemName = listItem.querySelector('.lstIname').innerText; let hide = false; - gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { if (e.checked && !listItemName.includes(e.dataset.flt)) hide = i>0 /*true*/; }); - listItem.style.display = hide ? 'none' : ''; + gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { if (e.checked && !listItemName.includes(e.dataset.flt)) hide = i > 0 /*true*/; }); + listItem.style.display = hide && !listItem.classList.contains("selected") ? 'none' : ''; }); } diff --git a/wled00/data/settings_2D.htm b/wled00/data/settings_2D.htm index a70ca76b..e372b3e2 100644 --- a/wled00/data/settings_2D.htm +++ b/wled00/data/settings_2D.htm @@ -54,8 +54,8 @@ Orientation:
Serpentine:
Dimensions (WxH): x
-Offset X: -Y:
(offset from top-left corner in # LEDs) +Offset X: +Y:
(offset from top-left corner in # LEDs) `; p.insertAdjacentHTML("beforeend", b); } diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 393a3628..d70a2440 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -6,7 +6,7 @@ LED Settings