diff --git a/.github/getWorkflowMatrix.py b/.github/getWorkflowMatrix.py index c62e2c694..877080b63 100755 --- a/.github/getWorkflowMatrix.py +++ b/.github/getWorkflowMatrix.py @@ -33,9 +33,10 @@ def get(info: GettableInfo): returnArray.add(line.split('=')[1].strip()) break elif info == GettableInfo.FLAGS: - with open('docs/firmware/osw_os.md') as f: + with open('docs/firmware/flags.md') as f: for line in f: - match = re.match(r'^`(.+)` \| .+ \| (.+)$', line) + # this parses a row with the format: "| `flag` | description | requirements |" + match = re.match(r'^\| `(.+)`\s+\| .+ \| (.+) \|$', line) if match is None: continue feature = match.group(1).strip() @@ -75,4 +76,4 @@ def get(info: GettableInfo): ap.add_argument('info', type=GettableInfo) args = ap.parse_args() - print(json.dumps(list(get(args.info)))) \ No newline at end of file + print(json.dumps(list(get(args.info)))) diff --git a/.github/workflows/test-OSW.yml b/.github/workflows/test-OSW.yml index ccfaf0cfa..e5cdabfe0 100644 --- a/.github/workflows/test-OSW.yml +++ b/.github/workflows/test-OSW.yml @@ -88,5 +88,22 @@ jobs: uses: actions/upload-artifact@v3 with: name: firmwares - path: | - *.bin + path: "*.bin" + + # do this last step seperately to avoid race conditions with firmware upload + create-release: + runs-on: ubuntu-latest + needs: build-OSW + if: startsWith(github.ref, 'refs/tags/v') + steps: + - uses: actions/download-artifact@v3 + with: + pattern: "*.bin" + merge-multiple: true + - name: Create release and upload firmware to it + uses: softprops/action-gh-release@v2 + with: + files: "firmwares/*.bin" + draft: true + prerelease: true + generate_release_notes: true diff --git a/.gitignore b/.gitignore index 9a1272157..7209c23f0 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .pio -.vscode +/.vscode/*.json .DS_Store screenshots /build \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 0347f309b..afe3a1712 100644 --- a/.gitmodules +++ b/.gitmodules @@ -20,6 +20,9 @@ path = lib/LUA url = https://github.com/lua/lua.git branch = v5.3 +[submodule "lib/BMI270-API"] + path = lib/BMI270-API + url = https://github.com/Open-Smartwatch/BMI270-Sensor-API.git [submodule "emulator/lib/ArduinoJson"] path = emulator/lib/ArduinoJson url = https://github.com/bblanchon/ArduinoJson.git @@ -42,3 +45,6 @@ [submodule "emulator/lib/ImGUI_TestEngine"] path = emulator/lib/ImGUI_TestEngine url = https://github.com/ocornut/imgui_test_engine.git +[submodule "lib/BMP581-API"] + path = lib/BMP581-API + url = https://github.com/boschsensortec/BMP5-Sensor-API.git diff --git a/.vscode/launch.json b/.vscode/launch.json.sample similarity index 100% rename from .vscode/launch.json rename to .vscode/launch.json.sample diff --git a/README.md b/README.md index cd93cfa18..fa3c75624 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,19 @@ 1. Install [PlatformIO Core](https://docs.platformio.org/en/latest/core/installation.html) or [PlatformIO IDE](https://docs.platformio.org/en/latest/integration/ide/vscode.html#ide-vscode) (which installs PlatformIO core automatically), as well as the packages specified in `scripts/requirements.txt` (e.g. `pip install -r scripts/requirements.txt`). 2. **For LUA-scripting support (see env:LIGHT_EDITION_DEV_LUA)**: Install [SWIG](http://www.swig.org/Doc4.0/SWIGDocumentation.html#Preface_installation) (also available in most package managers, e.g. `brew install swig` or `apt install swig`) -3. Then clone this repository: +3. **As this repository contains binary data (e.g. schematics or images), make sure to have `git-lfs` installed!** Cloning this repository without `git-lfs` will result in missing or broken files. +4. Then clone this repository: ```bash $ git clone --recurse-submodules https://github.com/Open-Smartwatch/open-smartwatch-os.git ``` - **As this repository contains binary data (e.g. schematics or images), make sure to have `git-lfs` installed!** Cloning this repository without `git-lfs` will result in missing or broken files. -4. To update the sources later on, run: +5. To update the sources / packages later on, run: ```bash + # pull new changes and update submodules $ git pull - $ git submodule update --init --recursive + $ git submodule sync # make sure to propagate origin-changes + $ git submodule update --init --recursive # update / create theis commits + # update the PlatformIO packages + $ pio pkg update # use the small terminal-icon in the bottom left corner of VSCode ``` ## Build @@ -36,7 +40,7 @@ Open the cloned repo in VSCode: $ code open-smartwatch-os ``` -You may rename the file `include/config.h.example` to `include/config.h` and adapt the values according to your requirements. That config is *only applied once* after you wiped the flash of the watch or changed the config-version numer in `osw_config.h` (...). +You may rename the file `include/config.h.example` to `include/config.h` and adapt the values according to your requirements. That config is *only applied once* after you wiped the flash of the watch or changed the config-version number in `osw_config.h` (...). ### CLI @@ -145,6 +149,10 @@ $ ./emulator.run You also may extend the `cmake`-command with `-DCMAKE_BUILD_TYPE=Release` to get an even faster and smaller binary. +#### Debugging with VSCode + +Take alook into the `.vscode` folder - there should be a `launch.json.sample` file. Copy it to `launch.json` and adjust the paths (if you are using Windows) to your needs. Then you can start debugging the emulator with VSCode via "Run and Debug". + ### With Docker If a library is unavailable, you can still use the emulator using docker (e.g. on Ubuntu 20.04 SDL2 is too old). Proceed with a typical docker installation. Showing an application running in docker requires some additional steps: diff --git a/docs/config.yml b/docs/config.yml index 0af12368b..06e505a60 100644 --- a/docs/config.yml +++ b/docs/config.yml @@ -1,11 +1,12 @@ # This file is similar to the mkdocs.nav configuration option, but it will be mounted under mkdocs.nav.Firmware only! -- 'OSW-OS': - - firmware/getting_started.md - - firmware/osw_os.md - - firmware/troubleshooting.md -- 'Applications': - - 'Watchfaces': 'firmware/apps/watchfaces.md' - - 'Tools': 'firmware/apps/tools.md' - - 'Games': 'firmware/apps/games.md' - - 'OSW Weather': 'firmware/apps/OswWeather.md' \ No newline at end of file +- "OSW-OS": + - firmware/getting_started.md + - firmware/flags.md + - firmware/troubleshooting.md + - firmware/support.md +- "Applications": + - "Watchfaces": "firmware/apps/watchfaces.md" + - "Tools": "firmware/apps/tools.md" + - "Games": "firmware/apps/games.md" + - "OSW Weather": "firmware/apps/OswWeather.md" diff --git a/docs/firmware/apps/OswWeather.md b/docs/firmware/apps/OswWeather.md index 319cb832f..2bf8a3ac2 100644 --- a/docs/firmware/apps/OswWeather.md +++ b/docs/firmware/apps/OswWeather.md @@ -6,9 +6,9 @@ Author: [@LorenzoSciacca](https://github.com/Lorenzosciacca) Add the flag `OSW_FEATURE_WEATHER` to the file `platformio.ini`: ```ini ; Example code block (make sure to use the one from the platformio config!) -[env:LIGHT_EDITION_V3_2] +[env:LIGHT_EDITION_V3_3] build_flags = - -D OSW_TARGET_PLATFORM_HEADER='"platform/LIGHT_EDITION_V3_2.h"' + -D OSW_TARGET_PLATFORM_HEADER='"platform/LIGHT_EDITION_V3_3.h"' -D OSW_FEATURE_STATS_STEPS -D OSW_FEATURE_WIFI ; ADD THIS LINE build_type = debug @@ -32,7 +32,7 @@ It's possible to configure the app from both the web UI and the configuration fi 4. Save ### Without web UI -If you want to configure the app without using the web UI you can set the followings values in config_defaults.h: +If you want to configure the app without using the web UI you can set the following values in config_defaults.h: - `OPENWEATHERMAP_APIKEY`, the api key - `OPENWEATHERMAP_CITY`, city name - `OPENWEATHERMAP__STATE_CODE`, the two letter iso code of the country of your interest @@ -170,7 +170,7 @@ Visit [this link](https://openweathermap.org/weather-conditions#Weather-Conditio ## Using the emulator -To use this app while using the OSW emulator, in order to retireve the data, it is necessary to perform the API request using the browser and to save the response in `file_weather.json` in the `/build` folder. +To use this app while using the OSW emulator, in order to retrieve the data, it is necessary to perform the API request using the browser and to save the response in `file_weather.json` in the `/build` folder. diff --git a/docs/firmware/apps/watchfaces.md b/docs/firmware/apps/watchfaces.md index bd17d4c16..3ba2e2610 100644 --- a/docs/firmware/apps/watchfaces.md +++ b/docs/firmware/apps/watchfaces.md @@ -81,7 +81,7 @@ Steps are shown as a hexadecimal number at side of the screen. The default Monotimer watchface. -Since a monotimer-clock has only a single hand, you read both the hours and minutes from the position of it. First, you read the hours by finding the nearest hour from the left (clockwise) of the hand. Then you read the Minutes by looking at the ticks between the hour tick and the hand. The smallest tick stands for a 5 minute intervall, the next bigger one for 15 minutes and the biggest one for 30 minutes (see image). For example, the clock from the image shows the time between 9:25 and 9:30. +Since a monotimer-clock has only a single hand, you read both the hours and minutes from the position of it. First, you read the hours by finding the nearest hour from the left (clockwise) of the hand. Then you read the Minutes by looking at the ticks between the hour tick and the hand. The smallest tick stands for a 5 minute interval, the next bigger one for 15 minutes and the biggest one for 30 minutes (see image). For example, the clock from the image shows the time between 9:25 and 9:30. The steps are displayed in the center of the clock. If the daily step goal is reached, the text color changes from InfoColor to SucessColor. diff --git a/docs/firmware/flags.md b/docs/firmware/flags.md new file mode 100644 index 000000000..768368027 --- /dev/null +++ b/docs/firmware/flags.md @@ -0,0 +1,46 @@ +# Feature Flags +The table below list all currently available features of the OSW-OS. These features can be manually enabled (or disabled) by modifying the `platformio.ini` and adding (or removing) their `-D`-Define lines. + +| Flag | Description | Requirements | +| ---------------------------- | ------------------------------------------------------------------------------------ | ---------------------------------- | +| `OSW_FEATURE_STATS_STEPS` | Enable step history (displayed on the watchfaces) | - | +| `OSW_FEATURE_WIFI` | Enable all wifi related functions (services, webinterface) | - | +| `OSW_FEATURE_WIFI_ONBOOT` | Allow the user to enable the wifi on boot | `OSW_FEATURE_WIFI` | +| `OSW_FEATURE_BLE_MEDIA_CTRL` | Enables media control via BLE | - | +| `OSW_FEATURE_LUA` | Enable LUA scripting support for apps | `LUA_C89_NUMBERS` | +| `SERVICE_BLE_COMPANION=1` | Enables the BLE Companion Service (unstable, requires custom smartphone application) | - | +| `DEBUG=1` | Enables debug logging to the console & additional utilities | - | +| `GPS_EDITION` | Configure the build for use with GPS (including apps, api, sensors) | `PROGMEM_TILES`, `BOARD_HAS_PSRAM` | +| `GPS_EDITION_ROTATED` | Replacement for `GPS_EDITION` to work with flipped boards | - | + +## Example Flags + +You want to know how to use some example code or see it in action? These flags enable various features that are not enabled by default - just search inside the source code for the flag to see how it works and what it does. + +| Flag | Description | Requirements | +| --------------------- | --------------------------------------------------------------------- | ------------ | +| `OSW_SERVICE_EXAMPLE` | Enable the example code to demonstrate how to write on services. | - | +| `OSW_APPS_EXAMPLES` | Enable the example code to demonstrate how to write own apps (v1/v2). | - | + +## Experimental Flags + +These flags should be available on all models. Because they are experimental, they are not enabled by default any may won't work or even compile. + +| Flag | Description | Requirements | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | +| `RAW_SCREEN_SERVER` | Capture the watchface and save it as a `*.png` file. | `OSW_FEATURE_WIFI` | +| `ANIMATION` | Animation can be used as the background of the watchface. | - | +| `OSW_FEATURE_BLE_MEDIA_CTRL` | See `OswAppBLEMediaCtrl.cpp` a tech demo to use the OSW as an external keyboard. OSW Light `v3.x` has insufficient memory,
`OswHal::getInstance()->disableDisplayBuffer()` is called to free memory
but slows down redraw speeds significantly. | - | +| `OSW_FEATURE_WEATHER` | You can monitor the weather through an OpenWeatherAPI. | `OSW_FEATURE_WIFI` | +| `GIF_BG` | Enable GIF support for the background of some watchfaces. | - | + +## Supported Flags per Device +The table below lists which features are available in which version of the OS by default. It is always our goal to also support older hardware revisions, but not all features can run properly using the old schematics. + +| Flag | `LIGHT_EDITION_V4_0` | `LIGHT_EDITION_V3_3` | `LIGHT_EDITION_DEV_LUA` | `GPS_EDITION_V3_1` | `GPS_EDITION_DEV_ROTATED` | +| ------------------------- | -------------------- | -------------------- | ----------------------- | ------------------ | ------------------------- | +| `OSW_FEATURE_STATS_STEPS` | ✓ | ✓ | ❌ | ✓ | ✓ | +| `OSW_FEATURE_WIFI` | ✓ | ✓ | ❌ | ✓ | ✓ | +| `OSW_FEATURE_WIFI_APST` | ❌ | ❌ | ❌ | ✓ | ✓ | +| `OSW_FEATURE_WIFI_ONBOOT` | ✓ | ❌ | ❌ | ✓ | ✓ | +| `OSW_FEATURE_LUA` | ❌ | ❌ | ✓ | ❌ | ❌ | diff --git a/docs/firmware/getting_started.md b/docs/firmware/getting_started.md index be4573729..251df3858 100644 --- a/docs/firmware/getting_started.md +++ b/docs/firmware/getting_started.md @@ -28,6 +28,9 @@ The following Youtube tutorial will guide you through this step: [https://youtu. ### USB Serial Drivers for WCH340E +!!! note "Tip" + Most Linux distributions already have the drivers shipped with the kernel, so you don't need to install them manually. In newer Ubuntu versions you may need to uninstall the `brltty` package to get the serial port working. + The Open-Smartwatch uses a `WCH340E` USB to serial controller. If your device is not detected as `COM?` or `/dev/cu.usbserial-?` or similar, please install the drivers from the manufacturer: [http://www.wch-ic.com/downloads/CH341SER_ZIP.html](http://www.wch-ic.com/downloads/CH341SER_ZIP.html) Please also see the trouble shooting section below if your device is not connected. @@ -38,14 +41,10 @@ Open git bash in your desired folder and clone the source code repository **recu git clone --recurse-submodules https://github.com/Open-Smartwatch/open-smartwatch-os.git -If you have cloned the repo without the recurse option, run `git submodule update`. +If you have cloned the repo without the recurse option, run `git submodule update --init`. !!! note "Tip" - After changing or updating/pulling a branch, run the command again to also update dependencies: - ```bash - git pull - git submodule update --init --recursive - ``` + After changing or updating/pulling a branch, run the commands notes inside the `README.md` to update the submodules and the PlatformIO packages. Then, open the directory with Visual Studio Code. @@ -68,4 +67,4 @@ Generally, you won't need to worry about GPIO assignment and initialisation as t **Keep in mind the PCB is flipped when inserted into the watch, EN/Reset is at the top left in this case:** - \ No newline at end of file + diff --git a/docs/firmware/osw_os.md b/docs/firmware/osw_os.md deleted file mode 100644 index 12bb66ab1..000000000 --- a/docs/firmware/osw_os.md +++ /dev/null @@ -1,45 +0,0 @@ -# Feature Flags -The table below list all currently available features of the OSW-OS. These features can be manually enabled (or disabled) by modifying the `platformio.ini` and adding (or removing) their `-D`-Define lines. - -Flag | Description | Requirements ------------ | ----------- | ----------- -`OSW_FEATURE_STATS_STEPS` | Enable step history (displayed on the watchfaces) | - -`OSW_FEATURE_WIFI` | Enable all wifi related functions (services, webinterface) | - -`OSW_FEATURE_WIFI_APST` | Allow the watch to enable wifi client and station simultaneously | `OSW_FEATURE_WIFI` -`OSW_FEATURE_WIFI_ONBOOT` | Allow the user to enable the wifi on boot | `OSW_FEATURE_WIFI` -`OSW_FEATURE_LUA` | Enable LUA scripting support for apps | `LUA_C89_NUMBERS` -`DEBUG=1` | Enables debug logging to the console & additional utilities | - -`GPS_EDITION` | Configure the build for use with GPS (including apps, api, sensors) | `PROGMEM_TILES`, `BOARD_HAS_PSRAM` -`GPS_EDITION_ROTATED` | Replacement for `GPS_EDITION` to work with flipped boards | - - -## Example Flags - -You want to know how to use some example code or see it in action? These flags enable vairous features that are not enabled by default - just search inside the source code for the flag to see how it works and what it does. - -Flag | Description | Requirements ------------ | ----------- | ----------- -`OSW_SERVICE_EXAMPLE` | Enable the example code to demonstrate how to write on services. | - -`OSW_APPS_EXAMPLES` | Enable the example code to demonstrate how to write own apps (v1/v2). | - - -## Experimental Flags - -These flags should be available on all models. Because they are experimental, they are not enabled by default any may won't work or even compile. - -Flag | Description | Requirements ------------ | ----------- | ----------- -`RAW_SCREEN_SERVER` | Capture the watchface and save it as a `*.png` file. | `OSW_FEATURE_WIFI` -`ANIMATION` | Animation can be used as the background of the watchface. | - -`OSW_FEATURE_BLE_MEDIA_CTRL` | See `OswAppBLEMediaCtrl.cpp` a tech demo to use the OSW as an external keyboard. OSW Light `v3.x` has insufficient memory,
`OswHal::getInstance()->disableDisplayBuffer()` is called to free memory
but slows down redraw speeds significantly. | - -`OSW_FEATURE_WEATHER` | You can monitor the weather through an OpenWeatherAPI. | `OSW_FEATURE_WIFI` -`GIF_BG` | Enable GIF support for the background of some watchfaces. | - - -## Supported Flags per Device -The table below lists which features are available in which version of the OS by default. It is always our goal to also support older hardware revisions, but not all features can run properly using the old schematics. - -Flag | `LIGHT_EDITION_V4_0` | `LIGHT_EDITION_V3_3` | `LIGHT_EDITION_V3_2` | `LIGHT_EDITION_DEV_LUA` | `GPS_EDITION_V3_1` | `GPS_EDITION_DEV_ROTATED` ------------ | ----------- | ----------- | ----------- | ----------- | ----------- | ----------- -`OSW_FEATURE_STATS_STEPS` | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ -`OSW_FEATURE_WIFI` | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ -`OSW_FEATURE_WIFI_APST` | ❌ | ❌ | ❌ | ❌ | ✓ | ✓ -`OSW_FEATURE_WIFI_ONBOOT` | ✓ | ❌ | ❌ | ❌ | ✓ | ✓ -`OSW_FEATURE_LUA` | ❌ | ❌ | ❌ | ✓ | ❌ | ❌ \ No newline at end of file diff --git a/docs/firmware/support.md b/docs/firmware/support.md new file mode 100644 index 000000000..89eaf1a0b --- /dev/null +++ b/docs/firmware/support.md @@ -0,0 +1,19 @@ +# Hardware Support +Over time, the operating system gained additional hardware support for non open-smartwatch environments. This page lists the supported hardware and how to use it (as well as unwanted features, so called "bugs"). You can also find all these configurations inside the `platformio.ini` file. + +## Official Hardware +...based on hardware schematics released by the OSW team and tested frequently. + +| Hardware | Status | Reference | +| -------------------------------------- | ------------ | --------------------------------------------------------- | +| `LIGHT_EDITION_V3_3` | Maintained | See "Hardware"-Documentation section | +| `EXPERIMENTAL_LIGHT_EDITION_V4_0` | Experimental | See "Hardware"-Documentation section | +| `EXPERIMENTAL_LIGHT_EDITION_V3_3_LUA` | Experimental | Same as `LIGHT_EDITION_V3_3`, but with LUA-script-support | +| `EXPERIMENTAL_GPS_EDITION_V3_1` | Experimental | See "Hardware"-Documentation section | +| `EXPERIMENTAL_GPS_EDITION_DEV_ROTATED` | Experimental | See "Hardware"-Documentation section | + +## 3rd Party Hardware + +| Hardware | Status | Reference | Known Issues | +| ------------------------------ | ------------ | --------------------------------- | ----------------------------------------------------------------------- | +| `3RD_PARTY_FLOW3R_C3CAMP_2023` | Experimental | [website](https://flow3r.garden/) | [PR368](https://github.com/Open-Smartwatch/open-smartwatch-os/pull/368) | diff --git a/docs/firmware/troubleshooting.md b/docs/firmware/troubleshooting.md index d5f2314f2..6d71360f6 100644 --- a/docs/firmware/troubleshooting.md +++ b/docs/firmware/troubleshooting.md @@ -1,29 +1,49 @@ # Troubleshooting -## Always double check the cable +## Build problems +...as we have some automations setup to always test-build many different configurations, we are quite sure that the code is working out of the box. If you have problems, maybe the following hints can help you. Or you found a bug... please let us know! -We have seen a number of "charge only" cables in the community. Try to upload using a different cable. +### Fixing `fatal error: Arduino_TFT.h: No such file or directory` -## Check the driver +You did not clone the repository with the `--recursive-submodules` flag. -Check the driver insertion. +!!! note "Tip" + After changing or updating/pulling a branch, run the commands notes inside the `README.md` to update the submodules and the PlatformIO packages. -## Arduino_TFT.h: No such file or directory +### Fixing `error: unknown type name ‘wait_queue_t’; did you mean ‘wait_event’?` -You did not clone the repository with the `--recursive-submodules` flag. +On Fedora Silverblue 34 `make` outputs `error: unknown type name ‘wait_queue_t’; did you mean ‘wait_event’?`. +This can be fixed by using [this fork from juliagoda](https://github.com/juliagoda/CH341SER). -!!! note "Tip" - After changing or updating/pulling a branch, run the command again to also update dependencies: - ```bash - git pull - git submodule update --init --recursive - ``` +### Fixing `raise UnidentifiedImageError(msg)` -## Failed to connect to ESP32: Timed out waiting for packet header +Open-Smartwatch can automatically embed assets (binary files) into the firmware. If you see this error, you may have forgotten to clone this repository with Git LFS enabled. Please see the `README.md` for instructions on how to clone the repository with Git LFS. -You did not hold down BTN1(FLASH) and then tap the RESET button on the watch whilst platform.io was trying to connect. +## Upload problems +You compiled the firmware successfully (`Successfully created esp32 image.`), but the upload fails for some reason. Here are some common problems and solutions. -## Fixing `error: unknown type name ‘wait_queue_t’; did you mean ‘wait_event’?` +### Always double check the USB-cable! -On Fedora Silverblue 34 `make` outputs `error: unknown type name ‘wait_queue_t’; did you mean ‘wait_event’?`. -This can be fixed by using [this fork from juliagoda](https://github.com/juliagoda/CH341SER). +We have seen a number of "charge-only" or broken cables in the community. Try to upload using a different cable. + +### Is the driver working correctly? + +On non-Linux machines you may need to install additional drivers, as noted in the [Getting Started](getting_started.md) guide. + +!!! note "Checking the connection (Linux only)" + If you are using Linux, make sure the device `/dev/ttyUSB0` or `/dev/ttyACM0` is present when you plug in the device. If it is not, the kernel is unable to communicate with the USB-to-serial chip on the device. + +### Driver is there, but device is busy + +On Linux, you may need to remove the `brltty` package to free up the serial port. + +```bash +sudo apt-get remove brltty +``` + +!!! info "What is brltty?" + `brltty` is a daemon that provides access to the Linux/Unix console (text mode) for a blind person using a refreshable braille display. It is not needed for most users, but is annoyingly always claiming all available serial ports and therefore blocking PlatformIO communication with the device. + +### Failed to connect to ESP32: Timed out waiting for packet header + +You did not hold down BTN1(FLASH) and then tap the RESET button on the watch whilst PlatformIO was trying to connect. diff --git a/emulator/include/Serial.h b/emulator/include/Serial.h index d4c610140..68d7e768e 100644 --- a/emulator/include/Serial.h +++ b/emulator/include/Serial.h @@ -44,6 +44,7 @@ class Serial_t { int read(); void println(); + void flush(); private: std::list inputBuffer; int bauds = 0; @@ -51,4 +52,4 @@ class Serial_t { bool addBufferNewline = true; }; -extern Serial_t Serial; \ No newline at end of file +extern Serial_t Serial; diff --git a/emulator/src/Emulator.cpp b/emulator/src/Emulator.cpp index c3f7b86ee..d34749a16 100644 --- a/emulator/src/Emulator.cpp +++ b/emulator/src/Emulator.cpp @@ -12,6 +12,7 @@ #include "../include/Display.h" #include "../include/Emulator.hpp" +#include "globals.h" #include "osw_ui.h" #include "osw_config.h" #include "osw_config_keys.h" @@ -318,6 +319,7 @@ void OswEmulator::doCleanup() { OswUI::resetInstance(); OswHal::resetInstance(); OswLogger::resetInstance(); + OswGlobals::resetGlobals(); this->cpustate = CPUState::deep; this->wantCleanup = false; } @@ -452,8 +454,32 @@ void OswEmulator::renderGUIFrameEmulator() { ImGui::InputFloat("Acceleration X", &OswHal::getInstance()->devices()->virtualDevice->values.accelerationX, 0.1f, 10); ImGui::InputFloat("Acceleration Y", &OswHal::getInstance()->devices()->virtualDevice->values.accelerationY, 0.1f, 10); ImGui::InputFloat("Acceleration Z", &OswHal::getInstance()->devices()->virtualDevice->values.accelerationZ, 0.1f, 10); + ImGui::InputInt("Magnetometer X", &OswHal::getInstance()->devices()->virtualDevice->values.magnetometerX, 0.1f, 10); + ImGui::InputInt("Magnetometer Y", &OswHal::getInstance()->devices()->virtualDevice->values.magnetometerY, 0.1f, 10); + ImGui::InputInt("Magnetometer Z", &OswHal::getInstance()->devices()->virtualDevice->values.magnetometerZ, 0.1f, 10); ImGui::InputInt("Magnetometer Azimuth", &OswHal::getInstance()->devices()->virtualDevice->values.magnetometerAzimuth, 1, 10); - ImGui::InputInt("Steps", (int*) &OswHal::getInstance()->devices()->virtualDevice->values.steps, 1, 10); // Warning - negative values will cause an underflow... ImGui has no conventient way of limiting the input range... + ImGui::InputInt("Steps", (int*) &OswHal::getInstance()->devices()->virtualDevice->values.steps, 1, 10); // Warning - negative values will cause an underflow... ImGui has no convenient way of limiting the input range... + // get string to display selected value + const char* str = "unknown"; + OswAccelerationProvider::ActivityMode& activityMode = OswHal::getInstance()->devices()->virtualDevice->values.activityMode; // take reference, for easier access + if(activityMode == OswAccelerationProvider::ActivityMode::STILL) + str = "still"; + else if(activityMode == OswAccelerationProvider::ActivityMode::WALK) + str = "walk"; + else if(activityMode == OswAccelerationProvider::ActivityMode::RUN) + str = "run"; + // display activity mode + if (ImGui::BeginCombo("Activity", str)) { + if(ImGui::Selectable("still", activityMode == OswAccelerationProvider::ActivityMode::STILL)) + OswHal::getInstance()->devices()->virtualDevice->values.activityMode = OswAccelerationProvider::ActivityMode::STILL; + else if(ImGui::Selectable("walk", activityMode == OswAccelerationProvider::ActivityMode::WALK)) + OswHal::getInstance()->devices()->virtualDevice->values.activityMode = OswAccelerationProvider::ActivityMode::WALK; + else if(ImGui::Selectable("run", activityMode == OswAccelerationProvider::ActivityMode::RUN)) + OswHal::getInstance()->devices()->virtualDevice->values.activityMode = OswAccelerationProvider::ActivityMode::RUN; + else if(ImGui::Selectable("unknown", activityMode == OswAccelerationProvider::ActivityMode::UNKNOWN)) + OswHal::getInstance()->devices()->virtualDevice->values.activityMode = OswAccelerationProvider::ActivityMode::UNKNOWN; + ImGui::EndCombo(); + } } else ImGui::Text(LANG_IMGUI_VIRTUAL_SENSORS_NOPE); ImGui::End(); @@ -491,8 +517,7 @@ void OswEmulator::renderGUIFrameEmulator() { // Create the combo-box if (ImGui::BeginCombo(key->label, std::get(this->configValuesCache[keyId]).c_str())) { for (size_t i = 0; i < options.size(); i++) { - bool isSelected = currentOption == i; - if (ImGui::Selectable(options[i].c_str(), &isSelected)) + if (ImGui::Selectable(options[i].c_str(), currentOption == i)) this->configValuesCache[keyId] = options[i]; } ImGui::EndCombo(); @@ -565,4 +590,4 @@ void OswEmulator::renderGUIFrameEmulator() { OswEmulator::CPUState OswEmulator::getCpuState() { return this->cpustate; -} \ No newline at end of file +} diff --git a/emulator/src/IO.cpp b/emulator/src/IO.cpp index 9dac4f491..0dcbd19a5 100644 --- a/emulator/src/IO.cpp +++ b/emulator/src/IO.cpp @@ -36,9 +36,6 @@ uint8_t digitalRead(int pin) { case OSW_DEVICE_TPS2115A_STATPWR: return OswEmulator::instance->isCharging() ? 1 : 0; break; - case TFT_LED: - return 255; // The emulator has always full brightness for now... - break; default: OSW_EMULATOR_THIS_IS_NOT_IMPLEMENTED; return LOW; diff --git a/emulator/src/Serial.cpp b/emulator/src/Serial.cpp index fae25e22d..973cd6b0d 100644 --- a/emulator/src/Serial.cpp +++ b/emulator/src/Serial.cpp @@ -38,6 +38,13 @@ void Serial_t::println() { std::cout << std::endl; } +void Serial_t::flush() { + if(this->bauds < 1) + return; + if(!this->buffered) + std::cout << std::flush; +} + int Serial_t::available() { char c; if(::read(STDIN_FILENO, &c, 1) > 0) { @@ -53,4 +60,4 @@ int Serial_t::read() { char c = this->inputBuffer.front(); this->inputBuffer.pop_front(); return c; -} \ No newline at end of file +} diff --git a/include/.gitignore b/include/.gitignore index 299bb98e5..0e56cf2f8 100644 --- a/include/.gitignore +++ b/include/.gitignore @@ -1 +1 @@ -config.h \ No newline at end of file +config.h diff --git a/include/Arduino_Canvas_Graphics2D.h b/include/Arduino_Canvas_Graphics2D.h index 6af1f571f..dfc28907b 100644 --- a/include/Arduino_Canvas_Graphics2D.h +++ b/include/Arduino_Canvas_Graphics2D.h @@ -3,6 +3,7 @@ #include #include +#include "config_defaults.h" class Arduino_Canvas_Graphics2D : public Graphics2DPrint { public: @@ -12,7 +13,7 @@ class Arduino_Canvas_Graphics2D : public Graphics2DPrint { * DIFFERENCES TO THE ORIGINAL Arduino_GFX library: * * setCursor -> setTextCursor * * fillScreen -> fill - * * drawArc has an entirely differnt function signature + * * drawArc has an entirely different function signature * * fillRoundRect -> fillRFrame * * fillRect -> fillFrame * * drawRect -> drawFrame @@ -22,12 +23,23 @@ class Arduino_Canvas_Graphics2D : public Graphics2DPrint { * we have copy-pasted this utility together... */ - void begin(int32_t speed = GFX_NOT_DEFINED); - void writePixelPreclipped(int16_t x, int16_t y, uint16_t color); - void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); - void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); void flush(); + inline void begin(int32_t speed = GFX_NOT_DEFINED) { + _output->begin(speed); + // _output->fillScreen(BLACK); + } + + inline void writePixelPreclipped(int16_t x, int16_t y, uint16_t color) { + this->drawPixel(x, y, color); + } + inline void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { + this->drawVLine(x, y, h, color); + } + inline void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { + this->drawHLine(x, y, w, color); + } + protected: Arduino_G* _output; int16_t _output_x, _output_y; diff --git a/include/OswAppV1.h b/include/OswAppV1.h index 01d076ec2..9b1e32875 100644 --- a/include/OswAppV1.h +++ b/include/OswAppV1.h @@ -15,4 +15,4 @@ class OswAppV1 { #endif }; -typedef OswAppV1 OswApp; // For backwards compatibility \ No newline at end of file +typedef OswAppV1 OswApp; // For backwards compatibility diff --git a/include/OswAppV2.h b/include/OswAppV2.h index 744086f44..9323676e2 100644 --- a/include/OswAppV2.h +++ b/include/OswAppV2.h @@ -56,7 +56,7 @@ class OswAppV2 { }; // We intentionally do not provide an operation to implicitly convert to OswHal* to prevent accidental use of the wrong instance }; - OswHalProxy hal; // You guys are needing that anyways (but you often cache incorrectly), so it is now given to you <3 + OswHalProxy hal; // You guys are needing that anyway (but you often cache incorrectly), so it is now given to you <3 class OswUiProxy { public: OswUI* operator->() { @@ -79,4 +79,4 @@ class OswAppV2 { std::array buttonLastSentState = {ButtonStateNames::UNDEFINED}; std::array buttonDoubleShortTimeout = {0}; std::array buttonIndicatorProgress = {0}; -}; \ No newline at end of file +}; diff --git a/include/OswIcon.h b/include/OswIcon.h index 5a1e1f522..07a8eab42 100644 --- a/include/OswIcon.h +++ b/include/OswIcon.h @@ -13,4 +13,4 @@ class OswIcon { OswIcon(uint16_t color): color(color) {}; virtual void draw(Graphics2D* gfx, int x, int y, float scale = 1, OswImage::Alignment xAlign = OswImage::Alignment::START, OswImage::Alignment yAlign = OswImage::Alignment::START) const = 0; -}; \ No newline at end of file +}; diff --git a/include/OswImage.h b/include/OswImage.h index 057a5e7e2..a0802588a 100644 --- a/include/OswImage.h +++ b/include/OswImage.h @@ -28,4 +28,4 @@ class OswImage { const unsigned short height; static void drawCallback(pngle_t* pngle, unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned char rgba[4]); -}; \ No newline at end of file +}; diff --git a/include/OswLogger.h b/include/OswLogger.h index b20dd200d..f81ff60ac 100644 --- a/include/OswLogger.h +++ b/include/OswLogger.h @@ -3,7 +3,7 @@ #include #include #include -#include // For Serial.print(ln) +#include #include #include @@ -58,6 +58,7 @@ class OswLogger { template void log(const char* file, const unsigned int line, const severity_t severity, T&& ... message) { std::lock_guard guard(this->m_lock); + OswSerial* serial = OswSerial::getInstance(); this->prefix(file, line, severity); do_in_order([&]() { @@ -67,50 +68,53 @@ class OswLogger { // Iterate over message to find '\n', which trigger new lines... for(auto& c : message) { if (c == '\n') { - Serial.println(); + serial->println(); this->prefix(file, line, severity); } else - Serial.print(c); + serial->putc(c); } } else if constexpr (std::is_same::value or std::is_same::value) { // Iterate over message to find '\n', which trigger new lines... for(auto& c : std::string_view(message)) { if (c == '\n') { - Serial.println(); + serial->println(); this->prefix(file, line, severity); } else - Serial.print(c); + serial->putc(c); } - } else - Serial.print(message); + } else { + serial->print(message); + } } ...); - Serial.println(); + serial->println(); }; void prefix(const char* file, const unsigned int line, const severity_t severity) { + OswSerial* serial = OswSerial::getInstance(); + switch(severity) { case severity_t::D: - Serial.print("D: "); + serial->print("D: "); break; case severity_t::I: - Serial.print("I: "); + serial->print("I: "); break; case severity_t::W: - Serial.print("W: "); + serial->print("W: "); break; case severity_t::E: - Serial.print("E: "); + serial->print("E: "); break; default: throw std::logic_error("Unknown severity level"); } #ifndef NDEBUG - Serial.print(file); - Serial.print("@"); - Serial.print(line); - Serial.print(": "); + serial->print(file); + serial->putc('@'); + serial->print(line); + serial->print(": "); #endif }; }; @@ -127,4 +131,4 @@ class OswLogger { #ifdef OSW_EMULATOR #define OSW_EMULATOR_THIS_IS_NOT_IMPLEMENTED OSW_LOG_W(__FUNCTION__, "() Not implemented!") -#endif \ No newline at end of file +#endif diff --git a/include/OswSerial.h b/include/OswSerial.h new file mode 100644 index 000000000..c9056ba80 --- /dev/null +++ b/include/OswSerial.h @@ -0,0 +1,92 @@ +#pragma once + +#include +#include +#include OSW_TARGET_PLATFORM_HEADER + +#if OSW_PLATFORM_HARDWARE_ESP32_USE_JTAG_SERIAL == 1 +#include // change this if needed, as this is specifically ESP32s2 +#include +#include +#else +#include +#endif + +/** + * @brief This class is not the fastest (only one byte at a time), but it is the most compatible + * + */ +class OswSerial { + public: + /** + * @brief Start / initialize serial communication (not all platforms may respect the baud rate) + * + * @param baud + */ + void begin(unsigned long baud); + + /** + * @brief Put one byte to the serial port (potentially buffered) + * + * If you only want to print a single character, prefer this method over print() + * + * @param c + */ + void putc(uint8_t c); + + /** + * @brief FLush out the outgoing buffer, if buffered + * + */ + void flush(); + + /** + * @brief Get one byte from the serial port + * + * @param c where to store the byte + * @return true if a byte was read + * @return false if no byte was read + */ + bool getc(uint8_t& c); + + /** + * @brief Print a string to the serial port and flush it + * + * @tparam T + * @param t + */ + template + void print(T t) { +#if OSW_PLATFORM_HARDWARE_ESP32_USE_JTAG_SERIAL == 1 + for(auto& c : String(t)) { + this->putc(c); + } + this->flush(); +#else + Serial.print(t); +#endif + } + + /** + * @brief Print a string to the serial port and flush it + * + * @tparam T + * @param t + */ + template + void println(T t) { + this->print(t); + this->println(); + } + + /** + * @brief Print a newline to the serial port and flush it + * + */ + void println(); + + static OswSerial* getInstance(); + static void resetInstance(); + private: + static OswSerial* instance; +}; diff --git a/include/animations/README.md b/include/animations/README.md index 0cd13996b..dfc6c7246 100644 --- a/include/animations/README.md +++ b/include/animations/README.md @@ -1,3 +1,3 @@ These files were just migrated from the old OSW-lib. -We should cleanup them at some point and maybe even create a unified `Animation` interface, to make it easier to use this animations in the future. \ No newline at end of file +We should cleanup them at some point and maybe even create a unified `Animation` interface, to make it easier to use this animations in the future. diff --git a/include/animations/anim_firework.h b/include/animations/anim_firework.h index 8f604a989..de93c0e75 100644 --- a/include/animations/anim_firework.h +++ b/include/animations/anim_firework.h @@ -39,4 +39,4 @@ class Firework { uint16_t color; long age; }; -#endif \ No newline at end of file +#endif diff --git a/include/animations/anim_water_ripple.h b/include/animations/anim_water_ripple.h index a0070b317..c86557e52 100644 --- a/include/animations/anim_water_ripple.h +++ b/include/animations/anim_water_ripple.h @@ -14,4 +14,4 @@ void calcWater(int8_t* buf1, int8_t* buf2, uint16_t width, uint16_t height, floa void mapWater(int8_t* buf, uint16_t width, uint16_t height, Graphics2D* background, Graphics2D* target, uint16_t offsetX, uint16_t offsetY); -#endif \ No newline at end of file +#endif diff --git a/include/apps/OswAppDrawer.h b/include/apps/OswAppDrawer.h index 9c7496b82..8cce800bd 100644 --- a/include/apps/OswAppDrawer.h +++ b/include/apps/OswAppDrawer.h @@ -39,6 +39,9 @@ class OswAppDrawer: public OswAppV2 { this->apps.at(category).emplace_back(nullptr); this->apps.at(category).back().set(); }; +#ifdef OSW_EMULATOR + void reset(); +#endif // Control functions, those will schedule their action for the next loop() of the drawer (preventing e.g. undefined behavior of switching apps while drawing) void showDrawer(); @@ -106,4 +109,4 @@ class OswAppDrawer: public OswAppV2 { // For UI testing purposes (to access private member "apps") // IMPORTANT: declaring such friend classes are the only changes in production code for testing purposes friend class TestDrawer; -}; \ No newline at end of file +}; diff --git a/include/apps/OswAppV2Compat.h b/include/apps/OswAppV2Compat.h index ea6b8736d..0e80588be 100644 --- a/include/apps/OswAppV2Compat.h +++ b/include/apps/OswAppV2Compat.h @@ -32,4 +32,4 @@ class OswAppV2Compat: public OswAppV2 { // For UI testing purposes (to access private member "app") friend class TestAppV2Compat; -}; \ No newline at end of file +}; diff --git a/include/apps/_experiments/OswAppWeatherEncoder.h b/include/apps/_experiments/OswAppWeatherEncoder.h index fd7344806..8d1fb0d4b 100644 --- a/include/apps/_experiments/OswAppWeatherEncoder.h +++ b/include/apps/_experiments/OswAppWeatherEncoder.h @@ -22,4 +22,4 @@ class OswAppWeatherEncoder { time_t timestamp; String updates; }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/_experiments/OswAppWeatherIconPrinter.h b/include/apps/_experiments/OswAppWeatherIconPrinter.h index 239cb8617..c8439fe73 100644 --- a/include/apps/_experiments/OswAppWeatherIconPrinter.h +++ b/include/apps/_experiments/OswAppWeatherIconPrinter.h @@ -26,4 +26,4 @@ class OswAppWeatherIconPrinter { uint32_t sunColor = rgb888(255, 250, 1); uint32_t dropletColor = rgb888(255,255,255); }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/_experiments/autumn.h b/include/apps/_experiments/autumn.h index 5050be2a6..86cddc4a9 100644 --- a/include/apps/_experiments/autumn.h +++ b/include/apps/_experiments/autumn.h @@ -15,4 +15,4 @@ class OswAppAutumn : public OswApp { private: }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/_experiments/dnatilt.h b/include/apps/_experiments/dnatilt.h index 7c802621c..47786914f 100644 --- a/include/apps/_experiments/dnatilt.h +++ b/include/apps/_experiments/dnatilt.h @@ -15,4 +15,4 @@ class OswAppDNATilt : public OswApp { private: }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/_experiments/fadein_display.h b/include/apps/_experiments/fadein_display.h index 981a6401b..1b6b50790 100644 --- a/include/apps/_experiments/fadein_display.h +++ b/include/apps/_experiments/fadein_display.h @@ -17,4 +17,4 @@ class OswAppFadeInDisplay : public OswApp { uint16_t _fadeDuration; }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/_experiments/fireworks.h b/include/apps/_experiments/fireworks.h index 3f253b0c0..3004d2e5d 100644 --- a/include/apps/_experiments/fireworks.h +++ b/include/apps/_experiments/fireworks.h @@ -15,4 +15,4 @@ class OswAppFireworks : public OswApp { private: }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/_experiments/magnetometer_calibrate.h b/include/apps/_experiments/magnetometer_calibrate.h index e6b818762..722cefb7d 100644 --- a/include/apps/_experiments/magnetometer_calibrate.h +++ b/include/apps/_experiments/magnetometer_calibrate.h @@ -15,4 +15,4 @@ class OswAppMagnetometerCalibrate : public OswApp { private: }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/_experiments/power_demo.h b/include/apps/_experiments/power_demo.h index 893a5d995..c58f26f5f 100644 --- a/include/apps/_experiments/power_demo.h +++ b/include/apps/_experiments/power_demo.h @@ -14,4 +14,4 @@ class OswAppPowerDemo : public OswApp { private: }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/_experiments/runtime_test.h b/include/apps/_experiments/runtime_test.h index a84792d93..26f4e512d 100644 --- a/include/apps/_experiments/runtime_test.h +++ b/include/apps/_experiments/runtime_test.h @@ -20,4 +20,4 @@ class OswAppRuntimeTest : public OswApp { }; #endif -#endif \ No newline at end of file +#endif diff --git a/include/apps/_experiments/show_display_size.h b/include/apps/_experiments/show_display_size.h index c6e6732ef..37cf7816f 100644 --- a/include/apps/_experiments/show_display_size.h +++ b/include/apps/_experiments/show_display_size.h @@ -14,4 +14,4 @@ class OswAppShowDisplaySize : public OswApp { private: }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/clock/OswAppAlarm.h b/include/apps/clock/OswAppAlarm.h index 51e2b7932..e88aa0bb1 100644 --- a/include/apps/clock/OswAppAlarm.h +++ b/include/apps/clock/OswAppAlarm.h @@ -47,4 +47,4 @@ class OswAppAlarm : public OswApp { friend class TestAlarm; }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/games/brick_breaker.h b/include/apps/games/brick_breaker.h index b0f3047d1..71c0cdcbf 100644 --- a/include/apps/games/brick_breaker.h +++ b/include/apps/games/brick_breaker.h @@ -1,5 +1,6 @@ -#ifndef OSW_APP_BRICK_BREAKER_H -#define OSW_APP_BRICK_BREAKER_H +#pragma once +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 #include #include @@ -29,8 +30,8 @@ class OswAppBrickBreaker : public OswApp { const int playerY = 184; const int gridW = 8; const int gridH = 4; - const float xSensitivity = 0.75; - const float ySensitivity = 0.75; + const float xSensitivity = 0.75f; + const float ySensitivity = 0.75f; const bool newGrid[4][8] = { {0, 0, 1, 1, 1, 1, 0, 0}, {0, 1, 1, 1, 1, 1, 1, 0}, {1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1} }; @@ -41,20 +42,20 @@ class OswAppBrickBreaker : public OswApp { unsigned long lastmove = 0; int lastpos = 0; - double ballPosx = 160; - double ballPosy = 120; - double ballSpdx = -2; - double ballSpdy = 4; - double absspd = 0; - double angleVar = 0; - double angleout = 0; - double angleout2 = 0; - double pHitPosition = 0; - double pHitAngle = 0; - double posAngle = 0; - double wallPosx = 0; - double wallPosy = 0; - double playerSpd = 0; + float ballPosx = 160; + float ballPosy = 120; + float ballSpdx = -2; + float ballSpdy = 4; + float absspd = 0; + float angleVar = 0; + float angleout = 0; + float angleout2 = 0; + float pHitPosition = 0; + float pHitAngle = 0; + float posAngle = 0; + float wallPosx = 0; + float wallPosy = 0; + float playerSpd = 0; bool scoreUpdated = false; bool grid[4][8] = {}; @@ -62,7 +63,7 @@ class OswAppBrickBreaker : public OswApp { int previousTime = 0; int gameStart = 0; - double spd = 1; + float spd = 1; float deltaSeconds = 0; @@ -92,5 +93,4 @@ class OswAppBrickBreaker : public OswApp { void waitingRoom(); }; - #endif diff --git a/include/apps/games/snake_game.h b/include/apps/games/snake_game.h index b421b971a..8c9dbf962 100644 --- a/include/apps/games/snake_game.h +++ b/include/apps/games/snake_game.h @@ -1,5 +1,6 @@ -#ifndef OSW_APP_SNAKE_GAME_H -#define OSW_APP_SNAKE_GAME_H +#pragma once +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 #include #include @@ -25,8 +26,8 @@ class OswAppSnakeGame : public OswApp { //#define demo 1 // Change these values if sensitivity is too much/low - const float xSensitivity = 0.75; - const float ySensitivity = 0.75; + const float xSensitivity = 0.75f; + const float ySensitivity = 0.75f; int score = 1; int snake[snakeLength][2] = {{10, 10}}; @@ -91,5 +92,4 @@ class OswAppSnakeGame : public OswApp { return deltaSeconds * score > 1; } }; - #endif diff --git a/include/apps/main/luaapp.h b/include/apps/main/luaapp.h index 4d3dce17d..ed1f4d899 100644 --- a/include/apps/main/luaapp.h +++ b/include/apps/main/luaapp.h @@ -31,4 +31,4 @@ class OswLuaApp : public OswApp { const char* file; }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/main/map.h b/include/apps/main/map.h index 6e2cc947d..990434a58 100644 --- a/include/apps/main/map.h +++ b/include/apps/main/map.h @@ -24,4 +24,4 @@ class OswAppMap : public OswApp { uint8_t _sat_count; // in the above array }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/tools/OswAppBLEMediaCtrl.h b/include/apps/tools/OswAppBLEMediaCtrl.h index aed7dc926..9822b2b1c 100644 --- a/include/apps/tools/OswAppBLEMediaCtrl.h +++ b/include/apps/tools/OswAppBLEMediaCtrl.h @@ -14,4 +14,4 @@ class OswAppBLEMediaCtrl : public OswApp { private: }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/tools/OswAppCalculator.h b/include/apps/tools/OswAppCalculator.h index 7755d28dc..30710960b 100644 --- a/include/apps/tools/OswAppCalculator.h +++ b/include/apps/tools/OswAppCalculator.h @@ -30,4 +30,4 @@ class OswAppCalculator : public OswApp { void setNum(int8_t position, uint8_t iNum); //is used to fill the array that will become the number String setOperator(int8_t position); //gets the input to set the operator String calculate(int iNum, char signOfNum1, String mathOperation, char signOfNum2); //calculates the output -}; \ No newline at end of file +}; diff --git a/include/apps/tools/OswAppDistStats.h b/include/apps/tools/OswAppDistStats.h index 7f3ff4af5..a22678405 100644 --- a/include/apps/tools/OswAppDistStats.h +++ b/include/apps/tools/OswAppDistStats.h @@ -1,6 +1,6 @@ -#ifdef OSW_FEATURE_STATS_STEPS - #pragma once +#include OSW_TARGET_PLATFORM_HEADER +#ifdef OSW_FEATURE_STATS_STEPS #include #include @@ -25,5 +25,4 @@ class OswAppDistStats : public OswApp { OswUI* ui; int32_t cursorPos = 0; // WeekDay position }; - -#endif \ No newline at end of file +#endif diff --git a/include/apps/tools/OswAppFitnessStats.h b/include/apps/tools/OswAppFitnessStats.h index f22cb3bde..f26b66592 100644 --- a/include/apps/tools/OswAppFitnessStats.h +++ b/include/apps/tools/OswAppFitnessStats.h @@ -1,4 +1,6 @@ #pragma once +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 #include #include @@ -17,4 +19,5 @@ class OswAppFitnessStats : public OswApp { private: OswUI* ui; -}; \ No newline at end of file +}; +#endif diff --git a/include/apps/tools/OswAppFlashLight.h b/include/apps/tools/OswAppFlashLight.h index bccd4370e..76825c881 100644 --- a/include/apps/tools/OswAppFlashLight.h +++ b/include/apps/tools/OswAppFlashLight.h @@ -20,5 +20,5 @@ class OswAppFlashLight : public OswAppV2 { virtual void onButton(Button id, bool up, OswAppV2::ButtonStateNames state) override; private: bool on = false; - short flashlightBrightness = 255; // seperat variable allows to change the Brightness -}; \ No newline at end of file + short flashlightBrightness = 255; // separate variable allows to change the Brightness +}; diff --git a/include/apps/tools/OswAppKcalStats.h b/include/apps/tools/OswAppKcalStats.h index c034260c0..2fb3ad6dc 100644 --- a/include/apps/tools/OswAppKcalStats.h +++ b/include/apps/tools/OswAppKcalStats.h @@ -1,6 +1,6 @@ -#ifdef OSW_FEATURE_STATS_STEPS - #pragma once +#include OSW_TARGET_PLATFORM_HEADER +#ifdef OSW_FEATURE_STATS_STEPS #include #include @@ -26,4 +26,4 @@ class OswAppKcalStats : public OswApp { OswUI* ui; }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/tools/OswAppPrintDebug.h b/include/apps/tools/OswAppPrintDebug.h index 26c992322..4bef9e2e7 100644 --- a/include/apps/tools/OswAppPrintDebug.h +++ b/include/apps/tools/OswAppPrintDebug.h @@ -1,5 +1,5 @@ -#ifndef NDEBUG #pragma once +#ifndef NDEBUG #include #include @@ -20,4 +20,4 @@ class OswAppPrintDebug : public OswApp { uint8_t x = 52; void printStatus(const char* setting, const char* value); }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/tools/OswAppStepStats.h b/include/apps/tools/OswAppStepStats.h index 336700acf..3b100266a 100644 --- a/include/apps/tools/OswAppStepStats.h +++ b/include/apps/tools/OswAppStepStats.h @@ -1,6 +1,6 @@ -#ifdef OSW_FEATURE_STATS_STEPS - #pragma once +#include OSW_TARGET_PLATFORM_HEADER +#ifdef OSW_FEATURE_STATS_STEPS #include #include @@ -26,5 +26,4 @@ class OswAppStepStats : public OswApp { int32_t cursorPos=0; OswUI* ui; }; - -#endif \ No newline at end of file +#endif diff --git a/include/apps/tools/OswAppTimeConfig.h b/include/apps/tools/OswAppTimeConfig.h index c69bc4d70..7a6811a8a 100644 --- a/include/apps/tools/OswAppTimeConfig.h +++ b/include/apps/tools/OswAppTimeConfig.h @@ -23,4 +23,4 @@ class OswAppTimeConfig : public OswApp { int8_t manualSettingStep = 0; int16_t manualSettingTimestamp[11]; OswUI* ui = nullptr; -}; \ No newline at end of file +}; diff --git a/include/apps/tools/OswAppWaterLevel.h b/include/apps/tools/OswAppWaterLevel.h index 994eec2eb..2fdbdd17e 100644 --- a/include/apps/tools/OswAppWaterLevel.h +++ b/include/apps/tools/OswAppWaterLevel.h @@ -1,4 +1,6 @@ #pragma once +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 #include #include @@ -21,4 +23,5 @@ class OswAppWaterLevel : public OswApp { private: OswUI* ui; int displayMode = 1; -}; \ No newline at end of file +}; +#endif diff --git a/include/apps/tools/OswAppWebserver.h b/include/apps/tools/OswAppWebserver.h index b39053ceb..e900406e7 100644 --- a/include/apps/tools/OswAppWebserver.h +++ b/include/apps/tools/OswAppWebserver.h @@ -1,5 +1,5 @@ -#ifdef OSW_FEATURE_WIFI #pragma once +#ifdef OSW_FEATURE_WIFI #include #include @@ -19,4 +19,4 @@ class OswAppWebserver : public OswApp { OswUI* ui; void drawConnectionInfo(); }; -#endif \ No newline at end of file +#endif diff --git a/include/apps/tools/button_test.h b/include/apps/tools/button_test.h index ce105fda2..1562257ce 100644 --- a/include/apps/tools/button_test.h +++ b/include/apps/tools/button_test.h @@ -19,4 +19,4 @@ class OswButtonTest : public OswApp { const char* longPress = "Long Press"; uint8_t lastButton = 255; -}; \ No newline at end of file +}; diff --git a/include/apps/watchfaces/OswAppWatchfaceBinary.h b/include/apps/watchfaces/OswAppWatchfaceBinary.h index b1a2f45fc..fd26949d4 100644 --- a/include/apps/watchfaces/OswAppWatchfaceBinary.h +++ b/include/apps/watchfaces/OswAppWatchfaceBinary.h @@ -22,4 +22,4 @@ class OswAppWatchfaceBinary : public OswAppV2 { uint16_t primaryColor; void drawWatch(); -}; \ No newline at end of file +}; diff --git a/include/apps/watchfaces/OswAppWatchfaceDigital.h b/include/apps/watchfaces/OswAppWatchfaceDigital.h index cef75dd91..259ddb645 100644 --- a/include/apps/watchfaces/OswAppWatchfaceDigital.h +++ b/include/apps/watchfaces/OswAppWatchfaceDigital.h @@ -28,4 +28,4 @@ class OswAppWatchfaceDigital: public OswAppV2 { private: static uint8_t dateFormatCache; time_t lastTime = 0; -}; \ No newline at end of file +}; diff --git a/include/apps/watchfaces/OswAppWatchfaceDual.h b/include/apps/watchfaces/OswAppWatchfaceDual.h index 0f6a486fc..ba2bed857 100644 --- a/include/apps/watchfaces/OswAppWatchfaceDual.h +++ b/include/apps/watchfaces/OswAppWatchfaceDual.h @@ -23,4 +23,4 @@ class OswAppWatchfaceDual : public OswAppV2 { private: time_t lastTime = 0; -}; \ No newline at end of file +}; diff --git a/include/apps/watchfaces/OswAppWatchfaceFitness.h b/include/apps/watchfaces/OswAppWatchfaceFitness.h index 4cda87f1b..57ab69ed1 100644 --- a/include/apps/watchfaces/OswAppWatchfaceFitness.h +++ b/include/apps/watchfaces/OswAppWatchfaceFitness.h @@ -1,4 +1,6 @@ #pragma once +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 #include #include @@ -25,3 +27,4 @@ class OswAppWatchfaceFitness : public OswAppV2 { void showFitnessTracking(); }; +#endif \ No newline at end of file diff --git a/include/apps/watchfaces/OswAppWatchfaceFitnessAnalog.h b/include/apps/watchfaces/OswAppWatchfaceFitnessAnalog.h new file mode 100644 index 000000000..8209c21b3 --- /dev/null +++ b/include/apps/watchfaces/OswAppWatchfaceFitnessAnalog.h @@ -0,0 +1,48 @@ +#include +#include +#include + +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 + +// if you want a cool background image, enable the following define +//#define GIF_BG + +#ifdef GIF_BG +class OswAppGifPlayer; +#endif +class OswAppWatchfaceFitnessAnalog : public OswAppV2 { + public: + constexpr static const char* APP_ID = "osw.wf.afit"; + + const char* getAppId() override; + const char* getAppName() override; + + void onStart(); + void onLoop() override; + void onDraw() override; + void onButton(Button id, bool up, ButtonStateNames state) override; + void onStop() override; + + static uint32_t calculateDistance(uint32_t steps); + + void timeDisplay(OswHal* hal, uint32_t hour, uint32_t minute, uint32_t second); + void timeDisplay(OswHal* hal, uint32_t hour, uint32_t minute, uint32_t second, bool afterNoon); + void dateDisplay(OswHal* hal, uint32_t hour, uint32_t minute, uint32_t second, bool afterNoon); + + void test(); + + ~OswAppWatchfaceFitnessAnalog() {} + + private: + time_t lastTime = 0; + unsigned screen = 0; + + void showFitnessTracking(OswHal* hal); + void drawWatchFace(OswHal* hal, uint32_t hour, uint32_t minute, uint32_t second, bool afterNoon); + void drawDateFace(OswHal* hal, uint32_t hour, uint32_t minute, uint32_t second, bool afterNoon); + +#ifdef GIF_BG + OswAppGifPlayer* bgGif = nullptr; +#endif +}; +#endif diff --git a/include/assets/.gitignore b/include/assets/.gitignore index c29126468..d54468c2f 100644 --- a/include/assets/.gitignore +++ b/include/assets/.gitignore @@ -1,2 +1,2 @@ www -img \ No newline at end of file +img diff --git a/include/config_defaults.h b/include/config_defaults.h index 7138a05ac..778284075 100644 --- a/include/config_defaults.h +++ b/include/config_defaults.h @@ -21,9 +21,11 @@ #define DISP_H 240 #endif -// !! IMPORTANT: DISP_H must be divisble by DISP_CHUNK_H !! -#ifndef DISP_CHUNK_H -#define DISP_CHUNK_H 8 +// !! IMPORTANT: DISP_H must be divisible by (1< #include +#include +#include namespace OswDevices { class BMA400 : public OswTemperatureProvider, public OswAccelerationProvider { @@ -23,14 +27,26 @@ class BMA400 : public OswTemperatureProvider, public OswAccelerationProvider { return 20; }; // This sensor is not sooo good... - virtual uint32_t getStepCount() override; - virtual void resetStepCount() override; virtual float getAccelerationX() override; virtual float getAccelerationY() override; virtual float getAccelerationZ() override; + virtual uint32_t getStepCount() override; + virtual void resetStepCount() override; + virtual OswAccelerationProvider::ActivityMode getActivityMode() override; virtual inline unsigned char getAccelerationProviderPriority() override { return 100; }; // This is a specialized device! - uint8_t getActivityMode(); + + private: + bma400_dev bma = {}; + float accelT = 0.0f; + float accelX = 0.0f; + float accelY = 0.0f; + float accelZ = 0.0f; + uint32_t step_count = 0; + OswAccelerationProvider::ActivityMode activityMode = OswAccelerationProvider::ActivityMode::UNKNOWN; + + void setupTiltToWake(); +}; }; -}; \ No newline at end of file +#endif diff --git a/include/devices/bme280.h b/include/devices/bme280.h index e89df600e..9bc28bc98 100644 --- a/include/devices/bme280.h +++ b/include/devices/bme280.h @@ -38,4 +38,4 @@ class BME280 : public OswTemperatureProvider, public OswHumidityProvider, public float _hum = -100; float _pres = -100; }; -}; \ No newline at end of file +}; diff --git a/include/devices/bmi270.h b/include/devices/bmi270.h new file mode 100644 index 000000000..a494dfe1a --- /dev/null +++ b/include/devices/bmi270.h @@ -0,0 +1,53 @@ +#pragma once +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_HARDWARE_BMI270 == 1 + +#include +#include +#include +#include + +namespace OswDevices { +class BMI270 : public OswAccelerationProvider, public OswTemperatureProvider { + public: + BMI270() : OswAccelerationProvider(), OswTemperatureProvider() {}; + virtual ~BMI270() {}; + + virtual void setup() override; + virtual void update() override; + virtual void reset() override {}; + virtual void stop() override {}; + + virtual inline const char* getName() override { + return "BMI270"; + }; + virtual float getAccelerationX() override; + virtual float getAccelerationY() override; + virtual float getAccelerationZ() override; + virtual uint32_t getStepCount() override; + virtual void resetStepCount() override; + virtual OswAccelerationProvider::ActivityMode getActivityMode() override; + virtual inline unsigned char getAccelerationProviderPriority() override { + return 100; + }; // This is a specialized device! + + virtual float getTemperature() override; + virtual inline unsigned char getTemperatureProviderPriority() override { + return 20; + }; // This sensor is not sooo good... + private: + bmi2_dev bmi2 = {}; + float accX = 0; + float accY = 0; + float accZ = 0; + uint32_t step_count = 0; + float temperature = 0; + OswAccelerationProvider::ActivityMode activityMode = OswAccelerationProvider::ActivityMode::UNKNOWN; + + void updateAcceleration(); + void updateSteps(); + void updateTemperature(); + void updateActivityMode(); +}; +}; +#endif \ No newline at end of file diff --git a/include/devices/bmp581.h b/include/devices/bmp581.h new file mode 100644 index 000000000..4ac7f02b7 --- /dev/null +++ b/include/devices/bmp581.h @@ -0,0 +1,41 @@ +#pragma once +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_HARDWARE_BMP581 == 1 + +#include +#include +#include +#include + +namespace OswDevices { +class BMP581 : public OswPressureProvider, public OswTemperatureProvider { + public: + BMP581() : OswPressureProvider(), OswTemperatureProvider() {}; + virtual ~BMP581() {}; + + virtual void setup() override; + virtual void update() override; + virtual void reset() override {}; + virtual void stop() override {}; + + virtual inline const char* getName() override { + return "BMP581"; + }; + + virtual float getPressure() override; + virtual unsigned char getPressureProviderPriority() override { + return 100; + }; // This is a specialized device! + + virtual float getTemperature() override; + virtual inline unsigned char getTemperatureProviderPriority() override { + return 20; + }; // This sensor is not sooo good... + private: + bmp5_dev bmp5 = {}; + bmp5_osr_odr_press_config osr_odr_press_cfg = {}; + float pressure = 0; + float temperature = 0; +}; +}; +#endif \ No newline at end of file diff --git a/include/devices/ds3231mz.h b/include/devices/ds3231mz.h index 72fe5f57c..00f2d63d5 100644 --- a/include/devices/ds3231mz.h +++ b/include/devices/ds3231mz.h @@ -1,4 +1,6 @@ #pragma once +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_HARDWARE_DS3231MZ == 1 #include #include @@ -35,4 +37,5 @@ class DS3231MZ : public OswTemperatureProvider, public OswTimeProvider { RtcDS3231 Rtc; uint32_t _utcTime = 0; }; -}; \ No newline at end of file +}; +#endif diff --git a/include/devices/esp32.h b/include/devices/esp32.h index b4aa1976e..f68940892 100644 --- a/include/devices/esp32.h +++ b/include/devices/esp32.h @@ -35,9 +35,9 @@ class NativeESP32 : public OswTemperatureProvider, public OswTimeProvider { }; // This is a specialized (bad) device! virtual time_t getTimezoneOffset(const time_t& timestamp, const String& timezone) override; private: - const time_t successfulNTPTime = 1600000000; // This is the UNIX timestamp for the "Sunday, 13 September 2020 12:26:40" -> if the time of the ESP32 is at least this value, we consider the NTP update to be sucessful + const time_t successfulNTPTime = 1600000000; // This is the UNIX timestamp for the "Sunday, 13 September 2020 12:26:40" -> if the time of the ESP32 is at least this value, we consider the NTP update to be successful bool tempSensorIsBuiltIn = true; bool enableTimeResync = true; bool waitingForNTP = false; }; -}; \ No newline at end of file +}; diff --git a/include/devices/interfaces/OswAccelerationProvider.h b/include/devices/interfaces/OswAccelerationProvider.h index 244d22bec..08e7de2b2 100644 --- a/include/devices/interfaces/OswAccelerationProvider.h +++ b/include/devices/interfaces/OswAccelerationProvider.h @@ -7,12 +7,20 @@ class OswAccelerationProvider : public OswDevice { public: - virtual uint32_t getStepCount() = 0; - virtual void resetStepCount() = 0; + enum class ActivityMode { + UNKNOWN, + STILL, + WALK, + RUN + }; virtual float getAccelerationX() = 0; virtual float getAccelerationY() = 0; virtual float getAccelerationZ() = 0; + virtual uint32_t getStepCount() = 0; + virtual void resetStepCount() = 0; + virtual ActivityMode getActivityMode() = 0; + virtual unsigned char getAccelerationProviderPriority() = 0; static const std::list* getAllAccelerationDevices() { return &allDevices; @@ -26,4 +34,4 @@ class OswAccelerationProvider : public OswDevice { }; private: static std::list allDevices; -}; \ No newline at end of file +}; diff --git a/include/devices/interfaces/OswHumidityProvider.h b/include/devices/interfaces/OswHumidityProvider.h index 94e7494a0..6b47e51f7 100644 --- a/include/devices/interfaces/OswHumidityProvider.h +++ b/include/devices/interfaces/OswHumidityProvider.h @@ -21,4 +21,4 @@ class OswHumidityProvider : public OswDevice { }; private: static std::list allDevices; -}; \ No newline at end of file +}; diff --git a/include/devices/interfaces/OswMagnetometerProvider.h b/include/devices/interfaces/OswMagnetometerProvider.h index c747c724f..b955dc0d5 100644 --- a/include/devices/interfaces/OswMagnetometerProvider.h +++ b/include/devices/interfaces/OswMagnetometerProvider.h @@ -8,6 +8,11 @@ class OswMagnetometerProvider : public OswDevice { public: virtual int getMagnetometerAzimuth() = 0; + // get field strength in microtesla + virtual int getMagnetometerX() = 0; + virtual int getMagnetometerY() = 0; + virtual int getMagnetometerZ() = 0; + virtual unsigned char getMagnetometerProviderPriority() = 0; static const std::list* getAllMagnetometerDevices() { return &allDevices; @@ -21,4 +26,4 @@ class OswMagnetometerProvider : public OswDevice { }; private: static std::list allDevices; -}; \ No newline at end of file +}; diff --git a/include/devices/interfaces/OswPressureProvider.h b/include/devices/interfaces/OswPressureProvider.h index 8a72cc04a..d7c045594 100644 --- a/include/devices/interfaces/OswPressureProvider.h +++ b/include/devices/interfaces/OswPressureProvider.h @@ -21,4 +21,4 @@ class OswPressureProvider : public OswDevice { }; private: static std::list allDevices; -}; \ No newline at end of file +}; diff --git a/include/devices/interfaces/OswTemperatureProvider.h b/include/devices/interfaces/OswTemperatureProvider.h index 2a4b4c816..8d0a7c212 100644 --- a/include/devices/interfaces/OswTemperatureProvider.h +++ b/include/devices/interfaces/OswTemperatureProvider.h @@ -21,4 +21,4 @@ class OswTemperatureProvider : public OswDevice { }; private: static std::list allDevices; -}; \ No newline at end of file +}; diff --git a/include/devices/interfaces/OswTimeProvider.h b/include/devices/interfaces/OswTimeProvider.h index b78121d7b..3268ded23 100644 --- a/include/devices/interfaces/OswTimeProvider.h +++ b/include/devices/interfaces/OswTimeProvider.h @@ -43,4 +43,4 @@ class OswTimeProvider : public OswDevice { }; private: static std::list allDevices; -}; \ No newline at end of file +}; diff --git a/include/devices/qmc5883l.h b/include/devices/qmc5883l.h index d40687b19..b7748c16c 100644 --- a/include/devices/qmc5883l.h +++ b/include/devices/qmc5883l.h @@ -1,4 +1,6 @@ #pragma once +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_HARDWARE_QMC5883L == 1 #include @@ -24,12 +26,13 @@ class QMC5883L : public OswMagnetometerProvider { virtual inline unsigned char getMagnetometerProviderPriority() override { return 100; }; // This is a specialized device! - int getMagnetometerX(); - int getMagnetometerY(); - int getMagnetometerZ(); + virtual int getMagnetometerX() override; + virtual int getMagnetometerY() override; + virtual int getMagnetometerZ() override; byte getMagnetometerBearing(); void setMagnetometerCalibration(int x_min, int x_max, int y_min, int y_max, int z_min, int z_max); private: QMC5883LCompass qmc5883l; }; -}; \ No newline at end of file +}; +#endif diff --git a/include/devices/virtual.h b/include/devices/virtual.h index c94b3b732..1877442d6 100644 --- a/include/devices/virtual.h +++ b/include/devices/virtual.h @@ -19,7 +19,11 @@ class Virtual : public OswTemperatureProvider, public OswAccelerationProvider, p float accelerationX = 0.0f; float accelerationY = 0.0f; float accelerationZ = -9.81f; + OswAccelerationProvider::ActivityMode activityMode = OswAccelerationProvider::ActivityMode::UNKNOWN; int magnetometerAzimuth = 0; + int magnetometerX = 0; + int magnetometerY = 0; + int magnetometerZ = 0; uint32_t steps = 42; } values; @@ -45,12 +49,6 @@ class Virtual : public OswTemperatureProvider, public OswAccelerationProvider, p return this->priority; }; - virtual inline uint32_t getStepCount() override { - return this->values.steps; - }; - virtual void resetStepCount() override { - this->values.steps = 0; - }; virtual inline float getAccelerationX() override { return this->values.accelerationX; }; @@ -60,9 +58,18 @@ class Virtual : public OswTemperatureProvider, public OswAccelerationProvider, p virtual inline float getAccelerationZ() override { return this->values.accelerationZ; }; + virtual inline uint32_t getStepCount() override { + return this->values.steps; + }; + virtual void resetStepCount() override { + this->values.steps = 0; + }; virtual inline unsigned char getAccelerationProviderPriority() override { return this->priority; }; + virtual OswAccelerationProvider::ActivityMode getActivityMode() override { + return this->values.activityMode; + }; virtual inline float getHumidity() override { return this->values.humidity; @@ -81,6 +88,15 @@ class Virtual : public OswTemperatureProvider, public OswAccelerationProvider, p virtual inline int getMagnetometerAzimuth() override { return this->values.magnetometerAzimuth; }; + virtual int getMagnetometerX() override { + return this->values.magnetometerX; + }; + virtual int getMagnetometerY() override { + return this->values.magnetometerY; + }; + virtual int getMagnetometerZ() override { + return this->values.magnetometerZ; + }; virtual inline unsigned char getMagnetometerProviderPriority() override { return this->priority; }; @@ -100,4 +116,4 @@ class Virtual : public OswTemperatureProvider, public OswAccelerationProvider, p private: const unsigned char priority; }; -}; \ No newline at end of file +}; diff --git a/include/fonts/DS_DIGI12pt7b.h b/include/fonts/DS_DIGI12pt7b.h index 81539c4da..57be0f14e 100644 --- a/include/fonts/DS_DIGI12pt7b.h +++ b/include/fonts/DS_DIGI12pt7b.h @@ -215,4 +215,4 @@ const GFXfont DS_DIGI12pt7b PROGMEM = { (uint8_t*)DS_DIGI12pt7bBitmaps, (GFXglyph*)DS_DIGI12pt7bGlyphs, 0x20, 0x7E, 24 -}; \ No newline at end of file +}; diff --git a/include/fonts/DS_DIGI30pt7b.font.url.txt b/include/fonts/DS_DIGI30pt7b.font.url.txt index e1fd7f6d4..e260943a4 100644 --- a/include/fonts/DS_DIGI30pt7b.font.url.txt +++ b/include/fonts/DS_DIGI30pt7b.font.url.txt @@ -1,4 +1,4 @@ "Free for personal use" -https://www.dafont.com/ds-digital.font \ No newline at end of file +https://www.dafont.com/ds-digital.font diff --git a/include/fonts/ows_font_CEI_8859-15.cpp b/include/fonts/ows_font_CEI_8859-15.cpp index 7aac7e412..30604b20c 100644 --- a/include/fonts/ows_font_CEI_8859-15.cpp +++ b/include/fonts/ows_font_CEI_8859-15.cpp @@ -266,4 +266,4 @@ static const unsigned char OSWfont[] PROGMEM = { 0x00, 0x19, 0x1D, 0x17, 0x12, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP -}; \ No newline at end of file +}; diff --git a/include/gfx_2d.h b/include/gfx_2d.h index 1a898a9f0..79a377f68 100644 --- a/include/gfx_2d.h +++ b/include/gfx_2d.h @@ -7,158 +7,82 @@ #include "math_angles.h" enum CIRC_OPT { DRAW_UPPER_RIGHT, DRAW_UPPER_LEFT, DRAW_LOWER_RIGHT, DRAW_LOWER_LEFT, DRAW_ALL }; +enum LINE_END_OPT { STRAIGHT_END, ROUND_END, TRIANGLE_END }; class DrawPixel { public: DrawPixel() {} virtual void drawPixel(int32_t x, int32_t y, uint16_t color) {}; + virtual void drawPixelAA(int32_t x, int32_t y, uint16_t color, uint8_t alpha) {}; }; class Graphics2D { public: - Graphics2D(uint16_t w_, uint16_t h_, uint8_t chunkHeight_, bool isRound_ = false, bool allocatePsram_ = false) - : width(w_), height(h_), chunkHeight(chunkHeight_), isRound(isRound_), allocatePsram(allocatePsram_) { + Graphics2D(uint16_t w_, uint16_t h_, uint8_t chunkHeightLd_, bool isRound_ = false, bool allocatePsram_ = false) + : width(w_), height(h_), chunkHeightLd(chunkHeightLd_), isRound(isRound_), allocatePsram(allocatePsram_) { enableBuffer(); maskEnabled = false; maskColor = rgb565(0, 0, 0); alphaEnabled = false; } - void enableBuffer() { - drawPixelCallback = NULL; - uint16_t numChunks = height / chunkHeight; - buffer = new uint16_t* [numChunks]; - if (isRound) { - missingPixelColor = rgb565(128, 128, 128); - chunkXOffsets = new uint16_t[numChunks]; - chunkWidths = new uint16_t[numChunks]; - for (uint16_t i = 0; i < numChunks; i++) { - uint16_t y = i * chunkHeight; - float y1 = (y + (y < height / 2 ? chunkHeight : 0)) - height / 2.0; - float d = sqrt(120 * 120 - y1 * y1); + void enableBuffer(); - uint16_t xOffset = 120 - d; - uint16_t chunkWidth = ceil(d * 2); - - chunkXOffsets[i] = xOffset; - chunkWidths[i] = chunkWidth; - // Serial.print("Chunk: "); - // Serial.println(i); - // Serial.print(" Width: "); - // Serial.println(chunkWidth); - // Serial.print(" chunkHeight: "); - // Serial.println(chunkHeight); - // Serial.print(" Size: "); - // Serial.println(chunkWidth * chunkHeight); - // buffer[i] = new uint16_t[chunkWidth * chunkHeight]; - if (allocatePsram) { -#if defined(GPS_EDITION) || defined(GPS_EDITION_ROTATED) - buffer[i] = (uint16_t*)ps_malloc(width * chunkHeight * sizeof(uint16_t)); -#else - buffer[i] = new uint16_t[width * chunkHeight](); -#endif - } else { - buffer[i] = new uint16_t[width * chunkHeight](); - } - } - } else { - for (uint16_t i = 0; i < numChunks; i++) { - // buffer[i] = new uint16_t[width * chunkHeight]; - // (uint8_t*) malloc( BufferSize * sizeof(uint8_t) ) - if (allocatePsram) { -#if defined(GPS_EDITION) || defined(GPS_EDITION_ROTATED) - buffer[i] = (uint16_t*)ps_malloc(width * chunkHeight * sizeof(uint16_t)); -#else - buffer[i] = (uint16_t*)malloc(width * chunkHeight * sizeof(uint16_t)); -#endif - } else { - buffer[i] = (uint16_t*)malloc(width * chunkHeight * sizeof(uint16_t)); - } - } - } - } - - bool hasBuffer() { + inline bool hasBuffer() { return drawPixelCallback == NULL; } - void disableBuffer(DrawPixel* callback) { // - delay(1000); - drawPixelCallback = callback; - uint16_t numChunks = height / chunkHeight; - for (uint16_t i = 0; i < numChunks; i++) { - delete[] buffer[i]; - buffer[i] = NULL; - } - delete[] buffer; - buffer = NULL; - - // delete[] chunkXOffsets; - // chunkXOffsets = NULL; - // delete[] chunkWidths; - // chunkWidths = NULL; - } + void disableBuffer(DrawPixel* callback); - ~Graphics2D() { - uint16_t numChunks = height / chunkHeight; - for (uint16_t i = 0; i < numChunks; i++) { - delete[] buffer[i]; - buffer[i] = NULL; - } - delete[] buffer; - buffer = NULL; + void fillBuffer(uint16_t color); - // delete[] chunkXOffsets; - // chunkXOffsets = NULL; + ~Graphics2D(); - // delete[] chunkWidths; - // chunkWidths = NULL; + inline uint16_t getNumChunks() { + return numChunks; } - uint16_t numChunks() { - return height / chunkHeight; - } - uint16_t* getChunk(uint8_t chunkId) { + inline uint16_t* getChunk(uint8_t chunkId) { return buffer[chunkId]; } - uint8_t getChunkHeight() { - return chunkHeight; + inline uint8_t getChunkHeightLd() { + return chunkHeightLd; } - uint16_t getChunkOffset(uint8_t chunkId) { + inline uint16_t getChunkOffset(uint8_t chunkId) { return isRound ? chunkXOffsets[chunkId] : 0; } - uint16_t getChunkWidth(uint8_t chunkId) { + inline uint16_t getChunkWidth(uint8_t chunkId) { return isRound ? chunkWidths[chunkId] : width; } - uint16_t getHeight() { + inline uint16_t getHeight() { return height; } - uint16_t getWidth() { + inline uint16_t getWidth() { return width; } - bool isMaskEnabled() { + inline bool isMaskEnabled() { return maskEnabled; } - void enableMask(uint16_t color) { + inline void enableMask(uint16_t color) { maskEnabled = true; maskColor = color; } - void disableMask() { + inline void disableMask() { maskColor = false; } - void enableAlpha(float a) { + inline void enableAlpha(float a) { alpha = a; alphaEnabled = true; } - void disableAplha() { + inline void disableAlpha() { alphaEnabled = false; } - void setMissingPixelColor(uint16_t color) { + inline void setMissingPixelColor(uint16_t color) { missingPixelColor = color; } - uint16_t getMissingPixelColor(void) { + inline uint16_t getMissingPixelColor(void) { return missingPixelColor; } @@ -175,112 +99,34 @@ class Graphics2D { drawPixelClipped(x, y, color); } - void drawPixelClipped(int32_t x, int32_t y, uint16_t color) { - if (x >= width || y >= height || x < 0 || y < 0) { - return; - } - if (maskEnabled && color == maskColor) { - return; - } - - // if we have a pixel callback, there is now buffer - // draw with the callback and return.. - if (drawPixelCallback != NULL) { - drawPixelCallback->drawPixel(x, y, color); - return; - } - - uint8_t chunkId = y / chunkHeight; - int16_t chunkY = y - chunkId * chunkHeight; - - // - if (alphaEnabled) { - if (isRound && isInsideChunk(x, y)) { - int16_t chunkX = x - chunkXOffsets[chunkId]; - color = blend(buffer[chunkId][chunkX + chunkY * chunkWidths[chunkId]], color, alpha); - } else { - color = blend(buffer[chunkId][x + chunkY * width], color, alpha); - } - } + /** + * @brief Draw a pixel of color 'color' a x-y position and blend it with alpha. + * + * @param x x axis coordinate + * @param y y axis coordinate + * @param color color code of the pixel + * @param alpha alpha value to blend with color + */ + void drawPixelAA(int32_t x, int32_t y, uint16_t color, uint8_t alpha) { + uint16_t old_color = getPixel(x, y); - if (isRound && isInsideChunk(x, y)) { - int16_t chunkX = x - chunkXOffsets[chunkId]; - buffer[chunkId][chunkX + chunkY * chunkWidths[chunkId]] = color; - } else if (!isRound) { // fix for round module - buffer[chunkId][x + chunkY * width] = color; - } + uint16_t new_color = blend(old_color, color, alpha); + drawPixelClipped(x, y, new_color); } - uint16_t getPixel(uint16_t x, uint16_t y) { - if (x >= width || y >= height) { - return 0; - } - uint8_t chunkId = y / chunkHeight; - uint16_t chunkY = y - chunkId * chunkHeight; - // printf("chunkid %d, offetY %d for y=%d and chunkHeight=%d\n", chunkId, chunkY, y, chunkHeight); - if (isRound) { - // TODO: check if inside chunk - if (isInsideChunk(x, y)) { - uint16_t chunkX = x - chunkXOffsets[chunkId]; - return buffer[chunkId][chunkX + chunkY * chunkWidths[chunkId]]; - } else { - return missingPixelColor; - } - } else { - return buffer[chunkId][x + chunkY * width]; - } - } + void drawPixelClipped(int32_t x, int32_t y, uint16_t color); - bool isInsideChunk(uint16_t x, uint16_t y) { - uint8_t chunkId = y / chunkHeight; - // uint16_t chunkY = y - chunkId * chunkHeight; - uint16_t chunkOffset = chunkXOffsets[chunkId]; - uint16_t chunkWidth = chunkWidths[chunkId]; - bool xFit = chunkOffset < x && x < chunkOffset + chunkWidth; - // y always fits, because we chunk in rows - return xFit; - } + uint16_t getPixel(uint16_t x, uint16_t y); - /** - * @brief Draw an horizontal line from the point (x,y) to an other horizontal point at h pixels - * - * @param x x-axis of the start point - * @param y y-axis of the start point - * @param w width of the horizontal line - * @param color color code of the line - */ - void drawHLine(int32_t x, int32_t y, uint16_t w, uint16_t color) { - for (uint16_t i = 0; i < w; i++) { - drawPixel(x + i, y, color); - } - } + bool isInsideChunk(uint16_t x, uint16_t y); - /** - * @brief Draw a vertical line from the bottom point (x,y) to an other vertical point at h pixels - * - * @param x x-axis of the start point - * @param y y-axis of the start point - * @param h height of the vertical line - * @param color color code of the line - */ - void drawVLine(int32_t x, int32_t y, uint16_t h, uint16_t color) { - for (uint16_t i = 0; i < h; i++) { - drawPixel(x, y + i, color); - } - } + void drawHLine(int32_t x, int32_t y, uint16_t w, uint16_t color); - void drawFrame(int32_t x, int32_t y, uint16_t w, uint16_t h, uint16_t color) { - drawHLine(x, y, w, color); - drawHLine(x, y + h, w, color); - drawVLine(x, y, h, color); - drawVLine(x + w, y, h, color); - } + void drawVLine(int32_t x, int32_t y, uint16_t h, uint16_t color); - void fillFrame(int32_t x0, int32_t y0, uint16_t w, uint16_t h, uint16_t color) { - for (uint16_t y = y0; y < y0 + h; y++) { - drawHLine(x0, y, w, color); - } - } + void drawFrame(int32_t x, int32_t y, uint16_t w, uint16_t h, uint16_t color); + + void fillFrame(int32_t x0, int32_t y0, uint16_t w, uint16_t h, uint16_t color); /** * Draw line from (x1,y1) to (x2,y2) point with color @@ -291,69 +137,18 @@ class Graphics2D { * @param y2 * @param color */ - void drawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint16_t color) { // see p3dt_gfx_2d_license.txt - // printf("\ndrawLine(%d, %d, %d, %d)",x1,y1,x2,y2); - // see p3dt_gfx_2d_license.txt - int32_t tmp; - int32_t x, y; - int32_t dx, dy; - int32_t err; - int32_t ystep; - - uint8_t swapxy = 0; - - /* no intersection check at the moment, should be added... */ - - if (x1 > x2) - dx = x1 - x2; - else - dx = x2 - x1; - if (y1 > y2) - dy = y1 - y2; - else - dy = y2 - y1; - - if (dy > dx) { - swapxy = 1; - tmp = dx; - dx = dy; - dy = tmp; - tmp = x1; - x1 = y1; - y1 = tmp; - tmp = x2; - x2 = y2; - y2 = tmp; - } - if (x1 > x2) { - tmp = x1; - x1 = x2; - x2 = tmp; - tmp = y1; - y1 = y2; - y2 = tmp; - } - err = dx >> 1; - if (y2 > y1) - ystep = 1; - else - ystep = -1; - y = y1; - - if (x2 == 0xffff) x2--; + void drawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint16_t color); - for (x = x1; x <= x2; x++) { - if (swapxy == 0) - drawPixel(x, y, color); - else - drawPixel(y, x, color); - err -= abs(dy); - if (err < 0) { - y += ystep; - err += dx; - } - } - } + /** + * Draw an anti-aliased line from (x1,y1) to (x2,y2) point with color + * + * @param x1 + * @param y1 + * @param x2 + * @param y2 + * @param color + */ + void drawLineAA(int32_t x0, int32_t y0, int32_t x1, int32_t y1, const uint16_t color); /** * @brief Draw a line between (x1,y1) and (x2,y2) with a thick of radius and with specific color @@ -368,126 +163,39 @@ class Graphics2D { * @param color color code use to draw the line. * @param highQuality */ - void drawThickLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint8_t radius, uint16_t color, - bool highQuality = false) { // see p3dt_gfx_2d_license.txt - - // see p3dt_gfx_2d_license.txt - int32_t tmp; - int32_t x, y; - int32_t dx, dy; - int32_t err; - int32_t ystep; - - uint8_t swapxy = 0; - - /* no intersection check at the moment, should be added... */ - - if (x1 > x2) - dx = x1 - x2; - else - dx = x2 - x1; - if (y1 > y2) - dy = y1 - y2; - else - dy = y2 - y1; - - if (dy > dx) { - swapxy = 1; - tmp = dx; - dx = dy; - dy = tmp; - tmp = x1; - x1 = y1; - y1 = tmp; - tmp = x2; - x2 = y2; - y2 = tmp; - } - if (x1 > x2) { - tmp = x1; - x1 = x2; - x2 = tmp; - tmp = y1; - y1 = y2; - y2 = tmp; - } - err = dx >> 1; - if (y2 > y1) - ystep = 1; - else - ystep = -1; - y = y1; - - if (x2 == 0xffff) x2--; + void drawThickLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint8_t radius, uint16_t color, bool highQuality = false); - for (x = x1; x <= x2; x++) { - if (swapxy == 0) { - if (highQuality) { - fillCircle(x, y, radius, color); - } else { - drawCircle(x, y, radius, color); - if (radius > 2) { - drawCircle(x, y, radius - 1, color); - } - if (radius > 3) { - drawCircle(x, y, radius - 2, color); - } - } - } else { - if (highQuality) { - fillCircle(y, x, radius, color); - } else { - drawCircle(y, x, radius, color); - if (radius > 2) { - drawCircle(y, x, radius - 1, color); - } - if (radius > 3) { - drawCircle(y, x, radius - 2, color); - } - } - } + /** + * @brief Draw an anti-aliased line between (x1,y1) and (x2,y2) with a thicknes of line_width and with specific color + * + * @param x1 x-axis of the start point + * @param y1 y-axis of the start point + * @param x2 x-axis of the end point + * @param y2 y-axis of the end point + * @param line_width thickness of the line + * @param color color code use to draw the line. + */ + void drawThickLineAA(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t line_width, const uint16_t color, LINE_END_OPT eol = ROUND_END); - err -= (uint8_t)dy; - if (err < 0) { - y += (uint16_t)ystep; - err += (uint16_t)dx; - } - } - } + void drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color); + void drawFilledTriangle(int32_t xa, int32_t ya, int32_t xb, int32_t yb, int32_t xc, int32_t yc, uint16_t color); - void drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) { - drawLine(x0, y0, x1, y1, color); - drawLine(x1, y1, x2, y2, color); - drawLine(x2, y2, x0, y0, color); - } + /** + * @brief Draw a horizontal/vertical box (x1,y1) and (x2,y2) with a specific color + * + * @param x1 x-axis of the start point + * @param y1 y-axis of the start point + * @param x2 x-axis of the end point + * @param y2 y-axis of the end point + * @param color color code use to fill the box. + */ + void fillBoxHV(int32_t x0, int32_t y0, int32_t x1, int32_t y1, const uint16_t color); /* * "Complex" Stuff: */ - void _drawCircleSection(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, uint16_t color, - CIRC_OPT option) { // see p3dt_gfx_2d_license.txt - - if (option == DRAW_UPPER_RIGHT || option == DRAW_ALL) { - drawPixel(x0 + x, y0 - y, color); - drawPixel(x0 + y, y0 - x, color); - } - - if (option == DRAW_UPPER_LEFT || option == DRAW_ALL) { - drawPixel(x0 - x, y0 - y, color); - drawPixel(x0 - y, y0 - x, color); - } - - if (option == DRAW_LOWER_RIGHT || option == DRAW_ALL) { - drawPixel(x0 + x, y0 + y, color); - drawPixel(x0 + y, y0 + x, color); - } - - if (option == DRAW_LOWER_LEFT || option == DRAW_ALL) { - drawPixel(x0 - x, y0 + y, color); - drawPixel(x0 - y, y0 + x, color); - } - } + void _drawCircleSection(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, uint16_t color, CIRC_OPT option); /** * @brief Draw a circle @@ -498,476 +206,79 @@ class Graphics2D { * @param color color code of the circle * @param option */ - void drawCircle(uint16_t x0, uint16_t y0, uint16_t rad, uint16_t color, - CIRC_OPT option = DRAW_ALL) { // see p3dt_gfx_2d_license.txt - - float f; - float ddFx; - float ddFy; - float x; - float y; - - f = 1; - f -= rad; - ddFx = 1; - ddFy = 0; - ddFy -= rad; - ddFy *= 2; - x = 0; - y = rad; - - _drawCircleSection(x, y, x0, y0, color, option); - - while (x < y) { - if (f >= 0) { - y--; - ddFy += 2; - f += ddFy; - } - x++; - ddFx += 2; - f += ddFx; + void drawCircle(int16_t x0, int16_t y0, int16_t rad, uint16_t color, CIRC_OPT option = DRAW_ALL); - _drawCircleSection(x, y, x0, y0, color, option); - } - } - - void _fillCircleSection(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, uint16_t color, - CIRC_OPT option) { // see p3dt_gfx_2d_license.txt - - if (option == DRAW_UPPER_RIGHT || option == DRAW_ALL) { - drawVLine(x0 + x, y0 - y, y + 1, color); - drawVLine(x0 + y, y0 - x, x + 1, color); - } - - if (option == DRAW_UPPER_LEFT || option == DRAW_ALL) { - drawVLine(x0 - x, y0 - y, y + 1, color); - drawVLine(x0 - y, y0 - x, x + 1, color); - } - - if (option == DRAW_LOWER_RIGHT || option == DRAW_ALL) { - drawVLine(x0 + x, y0, y + 1, color); - drawVLine(x0 + y, y0, x + 1, color); - } - - if (option == DRAW_LOWER_LEFT || option == DRAW_ALL) { - drawVLine(x0 - x, y0, y + 1, color); - drawVLine(x0 - y, y0, x + 1, color); - } - } - - void fillCircle(uint16_t x0, uint16_t y0, uint16_t rad, uint16_t color, - CIRC_OPT option = DRAW_ALL) { // see p3dt_gfx_2d_license.txt - - float f; - float ddFx; - float ddFy; - float x; - float y; - - f = 1; - f -= rad; - ddFx = 1; - ddFy = 0; - ddFy -= rad; - ddFy *= 2; - x = 0; - y = rad; - - _fillCircleSection(x, y, x0, y0, color, option); - - while (x < y) { - if (f >= 0) { - y--; - ddFy += 2; - f += ddFy; - } - x++; - ddFx += 2; - f += ddFx; - - _fillCircleSection(x, y, x0, y0, color, option); - } - } - - void _drawEllipseSection(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, uint16_t color, - CIRC_OPT option = DRAW_ALL) { // see p3dt_gfx_2d_license.txt - - /* upper right */ - if (option == DRAW_UPPER_RIGHT || option == DRAW_ALL) { - drawPixel(x0 + x, y0 - y, color); - } - - /* upper left */ - if (option == DRAW_UPPER_LEFT || option == DRAW_ALL) { - drawPixel(x0 - x, y0 - y, color); - } - - /* lower right */ - if (option == DRAW_LOWER_RIGHT || option == DRAW_ALL) { - drawPixel(x0 + x, y0 + y, color); - } + /** + * @brief Draw an anti-aliased circle with thicknes + * + * @param x0 x-axis of the center of the circle + * @param y0 y-axis of the center of the circle + * @param r radius of the circle + * @param bw thickness of th circle + * @param color color code of the circle + */ + void drawCircleAA(int16_t off_x, int16_t off_y, int16_t r, int16_t bw, uint16_t color, + int16_t start_angle = -1, int16_t end_angle = -1); - /* lower left */ - if (option == DRAW_LOWER_LEFT || option == DRAW_ALL) { - drawPixel(x0 - x, y0 + y, color); - } + inline void fillCircleAA(int16_t off_x, int16_t off_y, int16_t r, uint16_t color) { + drawCircleAA(off_x, off_y, r, r-1, color); } - void drawEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, uint16_t color, - CIRC_OPT option = DRAW_ALL) { // see p3dt_gfx_2d_license.txt - - float x; - float y; - float xchg; - float ychg; - float err; - float rxrx2; - float ryry2; - float stopx; - float stopy; + void _fillCircleSection(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, uint16_t color, CIRC_OPT option); + void fillCircle(uint16_t x0, uint16_t y0, uint16_t rad, uint16_t color, CIRC_OPT option = DRAW_ALL); + void _drawEllipseSection(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, uint16_t color, CIRC_OPT option = DRAW_ALL); + void drawEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, uint16_t color, CIRC_OPT option = DRAW_ALL); + void _fillEllipseSection(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, uint16_t color, CIRC_OPT option = DRAW_ALL); - rxrx2 = rx; - rxrx2 *= rx; - rxrx2 *= 2; + void fillEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, uint16_t color, CIRC_OPT option = DRAW_ALL); + void drawRFrame(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, uint16_t color); + void fillRFrame(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, uint16_t color); - ryry2 = ry; - ryry2 *= ry; - ryry2 *= 2; - - x = rx; - y = 0; - - xchg = 1; - xchg -= rx; - xchg -= rx; - xchg *= ry; - xchg *= ry; - - ychg = rx; - ychg *= rx; - - err = 0; - - stopx = ryry2; - stopx *= rx; - stopy = 0; - - while (stopx >= stopy) { - _drawEllipseSection(x, y, x0, y0, color, option); - y++; - stopy += rxrx2; - err += ychg; - ychg += rxrx2; - if (2 * err + xchg > 0) { - x--; - stopx -= ryry2; - err += xchg; - xchg += ryry2; - } - } - - x = 0; - y = ry; - - xchg = ry; - xchg *= ry; - - ychg = 1; - ychg -= ry; - ychg -= ry; - ychg *= rx; - ychg *= rx; - - err = 0; - - stopx = 0; - - stopy = rxrx2; - stopy *= ry; - - while (stopx <= stopy) { - _drawEllipseSection(x, y, x0, y0, color, option); - x++; - stopx += ryry2; - err += xchg; - xchg += ryry2; - if (2 * err + ychg > 0) { - y--; - stopy -= rxrx2; - err += ychg; - ychg += rxrx2; - } - } + inline void drawTick(int16_t cx, int16_t cy, int16_t r1, int16_t r2, float angle, uint16_t color) { + drawLine(rpx(cx, r1, angle), rpy(cy, r1, angle), rpx(cx, r2, angle), rpy(cy, r2, angle), color); } - void _fillEllipseSection(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, uint16_t color, - CIRC_OPT option = DRAW_ALL) { // see p3dt_gfx_2d_license.txt - - /* upper right */ - if (option == DRAW_UPPER_RIGHT || option == DRAW_ALL) { - drawVLine(x0 + x, y0 - y, y + 1, color); - } - - /* upper left */ - if (option == DRAW_UPPER_LEFT || option == DRAW_ALL) { - drawVLine(x0 - x, y0 - y, y + 1, color); - } - - /* lower right */ - if (option == DRAW_LOWER_RIGHT || option == DRAW_ALL) { - drawVLine(x0 + x, y0, y + 1, color); - } - - /* lower left */ - if (option == DRAW_LOWER_LEFT || option == DRAW_ALL) { - drawVLine(x0 - x, y0, y + 1, color); - } + inline void drawTick(int16_t cx, int16_t cy, int16_t r1, int16_t r2, int angle, uint16_t color) { + drawLine(rpx(cx, r1, angle), rpy(cy, r1, angle), rpx(cx, r2, angle), rpy(cy, r2, angle), color); } - void fillEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, uint16_t color, - CIRC_OPT option = DRAW_ALL) { // see p3dt_gfx_2d_license.txt - - float x; - float y; - float xchg; - float ychg; - float err; - float rxrx2; - float ryry2; - float stopx; - float stopy; - - rxrx2 = rx; - rxrx2 *= rx; - rxrx2 *= 2; - - ryry2 = ry; - ryry2 *= ry; - ryry2 *= 2; - - x = rx; - y = 0; - - xchg = 1; - xchg -= rx; - xchg -= rx; - xchg *= ry; - xchg *= ry; - - ychg = rx; - ychg *= rx; - - err = 0; - - stopx = ryry2; - stopx *= rx; - stopy = 0; - - while (stopx >= stopy) { - _fillEllipseSection(x, y, x0, y0, color, option); - y++; - stopy += rxrx2; - err += ychg; - ychg += rxrx2; - if (2 * err + xchg > 0) { - x--; - stopx -= ryry2; - err += xchg; - xchg += ryry2; - } - } - - x = 0; - y = ry; - - xchg = ry; - xchg *= ry; - - ychg = 1; - ychg -= ry; - ychg -= ry; - ychg *= rx; - ychg *= rx; - - err = 0; - - stopx = 0; - - stopy = rxrx2; - stopy *= ry; - - while (stopx <= stopy) { - _fillEllipseSection(x, y, x0, y0, color, option); - x++; - stopx += ryry2; - err += xchg; - xchg += ryry2; - if (2 * err + ychg > 0) { - y--; - stopy -= rxrx2; - err += ychg; - ychg += rxrx2; - } - } + inline void drawTickAA(int16_t cx, int16_t cy, int16_t r1, int16_t r2, float angle, uint16_t color) { + drawLineAA(rpx(cx, r1, angle), rpy(cy, r1, angle), rpx(cx, r2, angle), rpy(cy, r2, angle), color); } - void drawRFrame(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, - uint16_t color) { // see p3dt_gfx_2d_license.txt - - uint16_t xl; - uint16_t yu; - - xl = x; - xl += r; - yu = y; - yu += r; - - { - uint16_t yl; - uint16_t xr; - - xr = x; - xr += w; - xr -= r; - xr -= 1; - - yl = y; - yl += h; - yl -= r; - yl -= 1; - - drawCircle(xl, yu, r, color, DRAW_UPPER_LEFT); - drawCircle(xr, yu, r, color, DRAW_UPPER_RIGHT); - drawCircle(xl, yl, r, color, DRAW_LOWER_LEFT); - drawCircle(xr, yl, r, color, DRAW_LOWER_RIGHT); - } - - { - uint16_t ww; - uint16_t hh; - - ww = w; - ww -= r; - ww -= r; - hh = h; - hh -= r; - hh -= r; - - xl++; - yu++; - - if (ww >= 3) { - ww -= 2; - h--; - drawHLine(xl, y, ww, color); - drawHLine(xl, y + h, ww, color); - } - - if (hh >= 3) { - hh -= 2; - w--; - drawVLine(x, yu, hh, color); - drawVLine(x + w, yu, hh, color); - } - } + inline void drawTickAA(int16_t cx, int16_t cy, int16_t r1, int16_t r2, int32_t angle, uint16_t color) { + drawLineAA(rpx(cx, r1, angle), rpy(cy, r1, angle), rpx(cx, r2, angle), rpy(cy, r2, angle), color); } - void fillRFrame(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, - uint16_t color) { // see p3dt_gfx_2d_license.txt - //Prevent infinite looping - if(h < 2 * r) return; - - uint16_t xl; - uint16_t yu; - uint16_t yl; - uint16_t xr; - - xl = x; - xl += r; - yu = y; - yu += r; - - xr = x; - xr += w; - xr -= r; - xr -= 1; - - yl = y; - yl += h; - yl -= r; - yl -= 1; - fillCircle(xl, yu, r, color, DRAW_UPPER_LEFT); - fillCircle(xr, yu, r, color, DRAW_UPPER_RIGHT); - fillCircle(xl, yl, r, color, DRAW_LOWER_LEFT); - fillCircle(xr, yl, r, color, DRAW_LOWER_RIGHT); - - { - uint16_t ww; - uint16_t hh; - - ww = w; - ww -= r; - ww -= r; - xl++; - yu++; - - if (ww >= 3) { - ww -= 2; - fillFrame(xl, y, ww, r + 1, color); - fillFrame(xl, yl, ww, r + 1, color); - } - - hh = h; - hh -= r; - hh -= r; - // h--; - if (hh >= 3) { - hh -= 2; - fillFrame(x, yu, w, hh, color); - } - } - } - - void drawTick(uint8_t cx, uint8_t cy, uint8_t r1, uint8_t r2, float angle, uint16_t color) { - drawLine(rpx(cx, r1, angle), rpy(cy, r1, angle), rpx(cx, r2, angle), rpy(cy, r2, angle), color); + inline void drawThickTick(int16_t cx, int16_t cy, int16_t r1, int16_t r2, float angle, int16_t radius, uint16_t color, + bool highQuality = false, LINE_END_OPT eol = ROUND_END) { + if (highQuality) + drawThickLineAA(rpx(cx, r1, angle), rpy(cy, r1, angle), rpx(cx, r2, angle), rpy(cy, r2, angle), radius, color, eol); + else + drawThickLine(rpx(cx, r1, angle), rpy(cy, r1, angle), rpx(cx, r2, angle), rpy(cy, r2, angle), radius, color, + highQuality); } - void drawThickTick(uint8_t cx, uint8_t cy, uint8_t r1, uint8_t r2, float angle, uint8_t radius, uint16_t color, - bool highQuality = false) { - drawThickLine(rpx(cx, r1, angle), rpy(cy, r1, angle), rpx(cx, r2, angle), rpy(cy, r2, angle), radius, color, - highQuality); - } + void drawNTicks(int16_t cx, int16_t cy, int16_t r1, int16_t r2, int16_t nTicks, uint16_t color, int16_t skip_every_nth = 361); + void drawNTicksAA(int16_t cx, int16_t cy, int16_t r1, int16_t r2, int16_t nTicks, uint16_t color, int16_t skip_every_nth = 361); /** - * @brief Draw N ticks around the clock to visualize the hours. + * @brief Draw the ticks around the clock to visualize the hours. * - * @param cx center x axis - * @param cy center y axis - * @param r1 radius from the begin of the tick. - * @param r2 radius from the end of the tick. - * @param nTicks number of ticks to draw - * @param color color code - */ - void drawNTicks(uint8_t cx, uint8_t cy, uint8_t r1, uint8_t r2, uint8_t nTicks, uint16_t color) { - const float deltaAngle = 360.0 / nTicks; - for (uint16_t h = 0; h < nTicks; h++) { - drawTick(cx, cy, r1, r2, h * deltaAngle, color); - } - } - - /** - * @brief Draw 12 ticks around the clock to visualize the hours. + * 12 ticks will be drawn around the clock. * * @param cx center x axis * @param cy center y axis - * @param r1 radius from the begin of the tick. - * @param r2 radius from the end of the tick. + * @param r1 rayon + * @param r2 * @param color color code */ - void drawHourTicks(uint8_t cx, uint8_t cy, uint8_t r1, uint8_t r2, uint16_t color) { - drawNTicks(cx, cy, r1, r2, 12, color); + inline void drawHourTicks(int16_t cx, int16_t cy, int16_t r1, int16_t r2, uint16_t color, bool anti_alias = true) { + if (anti_alias) + drawNTicksAA(cx, cy, r1, r2, 12, color); + else + drawNTicks(cx, cy, r1, r2, 12, color); } /** @@ -981,199 +292,50 @@ class Graphics2D { * @param r2 * @param color color code */ - void drawMinuteTicks(uint8_t cx, uint8_t cy, uint8_t r1, uint8_t r2, uint16_t color) { - drawNTicks(cx, cy, r1, r2, 60, color); - } - - void drawArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color) { - this->drawArc(x, y, start, end, 1, r1, r2-r1, color); // This _should_ be the equivalent call... + inline void drawMinuteTicks(int16_t cx, int16_t cy, int16_t r1, int16_t r2, uint16_t color, bool anti_alias = true) { + if (anti_alias) + drawNTicksAA(cx, cy, r1, r2, 60, color, 5); + else + drawNTicks(cx, cy, r1, r2, 60, color, 5); } - /** - * Draw an arc - * - * @param cx Arc X center coordinates - * @param cy Arc Y center coordinates - * @param start Beginning angle of the arc (in deg). O° is equivalent to 12AM - * @param stop End angle of the arc (in deg). - * @param steps Number of lines that will compose the arc. - * @param radius Radius of the arc from the cx/cy center - * @param lineRadius Radius of the line. Example : radius = 1 give a line of 4 px of diameter, radius 2 -> 8px, - * etc.... - * @param color Color code of the arc - * @param highQuality - */ - void drawArc(int32_t cx, int32_t cy, float start, float stop, uint16_t steps, uint16_t radius, uint8_t lineRadius, - uint16_t color, bool highQuality = false) { - int32_t x1 = rpx(cx, radius, start); - int32_t y1 = rpy(cy, radius, start); - // printf("\ndraw from %f,%f in %d steps", start, stop, steps); - - float arcLength = stop - start; - - for (uint16_t i = 1; i <= steps; i++) { - float segmentLength = i * (arcLength / steps); - // printf("\n rpx(%d, %d, %f + %f)", cx, radius, start, segmentLength); - - int32_t x2 = rpx(cx, radius, start + segmentLength); - int32_t y2 = rpy(cy, radius, start + segmentLength); - // printf("\n gfx2d.drawLine(%d, %d, %d, %d, color);", x1, y1, x2, y2); - drawThickLine(x1, y1, x2, y2, lineRadius, color, highQuality); - x1 = x2; - y1 = y2; - } + inline void drawArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color, bool anti_alias = true) { + this->drawArc(x, y, start, end, 1, r1, r2-r1, color, anti_alias); // This _should_ be the equivalent call... } - void drawBWBitmap(uint16_t x0, uint16_t y0, uint16_t cnt, uint16_t h, uint8_t* bitmap, uint16_t color, - uint16_t bgColor = 0, bool drawBackground = false) { - // cnt: Number of bytes of the bitmap in horizontal direction. The width of the bitmap is cnt*8. - // h: Height of the bitmap. + void drawArc(int16_t cx, int16_t cy, float start, float stop, int16_t steps, int16_t radius, int16_t lineRadius, + uint16_t color, bool highQuality = false, bool anti_alias = true); - for (uint16_t x = 0; x < cnt; x++) { - for (uint16_t y = 0; y < h; y++) { - uint8_t bits = bitmap[x + y * cnt]; - for (uint8_t b = 1; b <= 8; b++) { - if (bits & (1 << (8 - b))) { - drawPixel(x * 8 + x0 + b, y + y0, color); - } else if (drawBackground) { - drawPixel(x * 8 + x0 + b, y + y0, bgColor); - } - } - } - } - } + void drawBWBitmap(int16_t x0, int16_t y0, int16_t cnt, int16_t h, uint8_t* bitmap, uint16_t color, + uint16_t bgColor = 0, bool drawBackground = false); - /** - * @brief Fill all the display with a color. - * - * Used for initialisation of the display with a background color. - * - * @param color Color code - */ - void fill(uint16_t color) { - for (uint16_t x = 0; x < width; x++) { - for (uint16_t y = 0; y < height; y++) { - drawPixel(x, y, color); - } - } - } + void fill(uint16_t color); - void dim(uint8_t amount) { - for (uint16_t x = 0; x < width; x++) { - for (uint16_t y = 0; y < height; y++) { - drawPixel(x, y, dimColor(getPixel(x, y), amount)); - } - } - } + void dim(uint8_t amount); + void drawGraphics2D(int16_t offsetX, int16_t offsetY, Graphics2D* source); - void drawGraphics2D(int32_t offsetX, int32_t offsetY, Graphics2D* source) { - for (int32_t y = 0; y < source->getHeight(); y++) { - for (int32_t x = 0; x < source->getWidth(); x++) { - drawPixel(x + offsetX, y + offsetY, source->getPixel(x, y)); - } - } - } - - void drawGraphics2D(int32_t offsetX, int32_t offsetY, Graphics2D* source, int32_t sourceOffsetX, - int32_t sourceOffsetY, uint16_t sourceWidth, uint16_t sourceHeight) { - for (int32_t x = 0; x < sourceWidth; x++) { - for (int32_t y = 0; y < sourceHeight; y++) { - drawPixel(x + offsetX, y + offsetY, source->getPixel(x + sourceOffsetX, y + sourceOffsetY)); - } - } - } + void drawGraphics2D(int16_t offsetX, int16_t offsetY, Graphics2D* source, int16_t sourceOffsetX, + int16_t sourceOffsetY, int16_t sourceWidth, int16_t sourceHeight); // draw scaled by 2x - void drawGraphics2D_2x(int32_t offsetX, int32_t offsetY, Graphics2D* source) { - for (int32_t x = 0; x < source->getWidth() * 2; x++) { - for (int32_t y = 0; y < source->getHeight() * 2; y++) { - drawPixel(x + offsetX, y + offsetY, source->getPixel(x / 2, y / 2)); - } - } - } + void drawGraphics2D_2x(int16_t offsetX, int16_t offsetY, Graphics2D* source); // draw section scaled by 2x - void drawGraphics2D_2x(uint16_t offsetX, uint16_t offsetY, Graphics2D* source, uint16_t sourceOffsetX, - uint16_t sourceOffsetY, uint16_t sourceWidth, uint16_t sourceHeight) { - for (uint16_t x = 0; x < sourceWidth * 2; x++) { - for (uint16_t y = 0; y < sourceHeight * 2; y++) { - drawPixel(x + offsetX, y + offsetY, source->getPixel(sourceOffsetX + x / 2, sourceOffsetY + y / 2)); - } - } - } + void drawGraphics2D_2x(int16_t offsetX, int16_t offsetY, Graphics2D* source, int16_t sourceOffsetX, + int16_t sourceOffsetY, int16_t sourceWidth, int16_t sourceHeight); #ifdef ROTATE_LEGACY // this rotate function is faster, but it has artifacts void drawGraphics2D_rotatedLegacy(uint16_t offsetX, uint16_t offsetY, Graphics2D* source, uint16_t rotationX, - uint16_t rotationY, float angle) { - float cosA = cos(angle); - float sinA = sin(angle); - for (uint16_t x = 0; x < source->getWidth(); x++) { - for (uint16_t y = 0; y < source->getHeight(); y++) { - int32_t newX = (x - rotationX) * cosA + (y - rotationY) * sinA; - int32_t newY = (y - rotationY) * cosA - (x - rotationX) * sinA; - drawPixel(newX + offsetX, newY + offsetY, source->getPixel(x, y)); - } - } - } + uint16_t rotationY, float angle); #endif - void drawGraphics2D_rotated(uint16_t offsetX, uint16_t offsetY, Graphics2D* source, uint16_t rx, uint16_t ry, - float angle) { - float cosA = cos(angle); - float sinA = sin(angle); - // rotateX = (x - rx) * cos(angle) + (y - ry) * sin(angle); - // rotateY = (y - ry) * cos(angle) - (x - rx) * sin(angle); - - // first calculate the bounding box of the new image - // // top left - int32_t tl_x = rotateX(0, 0, rx, ry, cosA, sinA); - int32_t tl_y = rotateY(0, 0, rx, ry, cosA, sinA); - // // top right - int32_t tr_x = rotateX(source->getWidth() - 1, 0, rx, ry, cosA, sinA); - int32_t tr_y = rotateY(source->getWidth() - 1, 0, rx, ry, cosA, sinA); - - // // bottom left - int32_t bl_x = rotateX(0, source->getHeight() - 1, rx, ry, cosA, sinA); - int32_t bl_y = rotateY(0, source->getHeight() - 1, rx, ry, cosA, sinA); - - // // bottom right - int32_t br_x = rotateX(source->getWidth(), source->getHeight(), rx, ry, cosA, sinA); - int32_t br_y = rotateY(source->getWidth(), source->getHeight(), rx, ry, cosA, sinA); - - // debug: draw rotated image - // this->drawLine(offsetX + tl_x, offsetY + tl_y, offsetX + tr_x, offsetY + tr_y, rgb565(255, 0, 0)); - // this->drawLine(offsetX + tr_x, offsetY + tr_y, offsetX + br_x, offsetY + br_y, rgb565(255, 0, 0)); - // this->drawLine(offsetX + bl_x, offsetY + bl_y, offsetX + br_x, offsetY + br_y, rgb565(255, 0, 0)); - // this->drawLine(offsetX + bl_x, offsetY + bl_y, offsetX + tl_x, offsetY + tl_y, rgb565(255, 0, 0)); - - // determine bounding box - int32_t boxX = min(tl_x, min(tr_x, min(bl_x, br_x))); - int32_t boxY = min(tl_y, min(tr_y, min(bl_y, br_y))); - int32_t boxW = max(tl_x, max(tr_x, max(bl_x, br_x))) - boxX; - int32_t boxH = max(tl_y, max(tr_y, max(bl_y, br_y))) - boxY; - - // debug: draw bounding box - // this->drawFrame(boxX + offsetX, boxY + offsetY, boxW, boxH, rgb565(0, 255, 0)); - cosA = cos(-angle); - sinA = sin(-angle); - for (int16_t x = boxX; x < boxX + boxW; x++) { - for (int16_t y = boxY; y < boxY + boxH; y++) { - if (pointInsideTriangle(x, y, tl_x, tl_y, tr_x, tr_y, br_x, br_y)) { - int16_t origX = rotateX(x, y, 0, 0, cosA, sinA); - int16_t origY = rotateY(x, y, 0, 0, cosA, sinA); - drawPixel(x + offsetX, y + offsetY, source->getPixel(origX + rx, origY + ry)); - } else if (pointInsideTriangle(x, y, tl_x, tl_y, bl_x, bl_y, br_x, br_y)) { - int16_t origX = rotateX(x, y, 0, 0, cosA, sinA); - int16_t origY = rotateY(x, y, 0, 0, cosA, sinA); - drawPixel(x + offsetX, y + offsetY, source->getPixel(origX + rx, origY + ry)); - } - } - } - } + void drawGraphics2D_rotated(int16_t offsetX, int16_t offsetY, Graphics2D* source, int16_t rx, int16_t ry, + float angle); protected: uint16_t** buffer; + uint16_t numChunks; DrawPixel* drawPixelCallback; uint16_t* chunkXOffsets; uint16_t* chunkWidths; @@ -1181,21 +343,28 @@ class Graphics2D { /** * @brief Width (in pixels) of the display frame */ - uint16_t width; + int32_t width; /** * @brief Height (in pixels) of the display frame. */ - uint16_t height; + int32_t height; uint16_t maskColor; uint16_t missingPixelColor; bool maskEnabled; - uint8_t chunkHeight; + uint8_t chunkHeightLd; // Height of a chunk is 2^chunkHeightLd bool isRound; bool alphaEnabled; bool allocatePsram; float alpha; + + // for caching of isPixelMasked + void isPixelMaskedByAnglesInit(int32_t off_x, int32_t off_y, int32_t sa, int32_t ea); + bool isPixelMaskedByAngles(int32_t x, int32_t y); + int32_t ox, oy; + int32_t start_angle, end_angle; + float tan_sa, tan_ea; }; #endif diff --git a/include/gfx_2d_license.txt b/include/gfx_2d_license.txt index 3b35bc809..d2dba410e 100644 --- a/include/gfx_2d_license.txt +++ b/include/gfx_2d_license.txt @@ -27,4 +27,4 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/include/gfx_2d_print.h b/include/gfx_2d_print.h index 76badf2ea..df5998426 100644 --- a/include/gfx_2d_print.h +++ b/include/gfx_2d_print.h @@ -493,7 +493,7 @@ class Graphics2DPrint : public Graphics2D, public Print { /** * @brief Set the text cursor position. * - * The cursor define le left-bottom position of the caracter. + * The cursor define le left-bottom position of the character. * * @param x x-axis of the cursor. * @param y y-axis of the cursor. diff --git a/include/gfx_util.h b/include/gfx_util.h index a2227bd54..9776e05f0 100644 --- a/include/gfx_util.h +++ b/include/gfx_util.h @@ -17,6 +17,53 @@ uint8_t rgb888_red(uint32_t rgb888); uint8_t rgb888_green(uint32_t rgb888); uint8_t rgb888_blue(uint32_t rgb888); +inline uint16_t rgb565(uint8_t red, uint8_t green, uint8_t blue) { + return ((red & 0b00011111000) << 8) | ((green & 0b00011111100) << 3) | (blue >> 3); +} + +inline uint32_t rgb888(uint8_t red, uint8_t green, uint8_t blue) { + return ((uint32_t)red << 16) | ((uint32_t)green << 8) | (uint32_t)blue; +} + +inline uint16_t rgb888to565(uint32_t rgb888) { + return rgb565(rgb888_red(rgb888), rgb888_green(rgb888), rgb888_blue(rgb888)); +} + +inline uint32_t rgb565to888(uint16_t rgb565) { + return rgb888(rgb565_red(rgb565), rgb565_green(rgb565), rgb565_blue(rgb565)); +} + +inline uint8_t rgb565_red(uint16_t rgb565) { + // |rrrrrggg|gggbbbbb| + return (rgb565 >> 8) & 0b11111000; +} + +inline uint8_t rgb565_green(uint16_t rgb565) { + // |rrrrrggg|gggbbbbb| + return (rgb565 >> 3) & 0b11111100; +} + +inline uint8_t rgb565_blue(uint16_t rgb565) { + // |rrrrrggg|gggbbbbb| + return (rgb565 << 3); +} + +inline uint8_t rgb888_red(uint32_t rgb888) { + // |rrrrrrrr|gggggggg|bbbbbbbb| + return rgb888 >> 16; +} + +inline uint8_t rgb888_green(uint32_t rgb888) { + // |rrrrrrrr|gggggggg|bbbbbbbb| + return rgb888 >> 8; +} + +inline uint8_t rgb888_blue(uint32_t rgb888) { + // |rrrrrrrr|gggggggg|bbbbbbbb| + return rgb888; +} + +uint16_t blend(uint16_t target, uint16_t source, uint8_t alpha); uint16_t blend(uint16_t target, uint16_t source, float alpha); uint16_t dimColor(uint16_t oc, uint8_t amount); uint16_t changeColor(uint16_t oc, float amount); diff --git a/include/globals.h b/include/globals.h index 6bea393f1..2940b10f1 100644 --- a/include/globals.h +++ b/include/globals.h @@ -10,7 +10,7 @@ namespace OswGlobals { /** * As a rule of thumb: Try to avoid global variables, as they are not reset (e.g. inside the emulator), * because they are not bound to a lifetime of an object. This also applies to applications and their states. - * Furthermore, their names may collide and cause unreleated bugs! + * Furthermore, their names may collide and cause unrelated bugs! * * Yes, they are helpful during early development, but should not be used inside the final code! */ @@ -24,4 +24,9 @@ namespace OswGlobals { RTC_DATA_ATTR extern size_t main_AppIndex; extern OswAppDrawer main_mainDrawer; extern std::unique_ptr main_tutorialApp; -} \ No newline at end of file +extern bool main_delayedAppInit; + +#ifdef OSW_EMULATOR +void resetGlobals(); +#endif +} diff --git a/include/hal/buttons.h b/include/hal/buttons.h index 7f90a373b..ca3691bf7 100644 --- a/include/hal/buttons.h +++ b/include/hal/buttons.h @@ -11,4 +11,4 @@ enum Button { BUTTON_3 = 1 }; -extern const char* ButtonNames[]; \ No newline at end of file +extern const char* ButtonNames[]; diff --git a/include/hal/devices.h b/include/hal/devices.h index 2002f73be..8f5b7ecbb 100644 --- a/include/hal/devices.h +++ b/include/hal/devices.h @@ -5,18 +5,12 @@ #include #include #include -#if OSW_PLATFORM_HARDWARE_BMA400 == 1 #include -#endif -#if OSW_PLATFORM_HARDWARE_QMC5883L == 1 #include -#endif -#if OSW_PLATFORM_HARDWARE_BME280 == 1 #include -#endif -#if OSW_PLATFORM_HARDWARE_DS3231MZ == 1 +#include +#include #include -#endif #include #include @@ -25,6 +19,12 @@ class OswHal::Devices { #if OSW_PLATFORM_HARDWARE_BMA400 == 1 OswDevices::BMA400* bma400; #endif +#if OSW_PLATFORM_HARDWARE_BMI270 == 1 + OswDevices::BMI270* bmi270; +#endif +#if OSW_PLATFORM_HARDWARE_BMP581 == 1 + OswDevices::BMP581* bmp581; +#endif #if OSW_PLATFORM_HARDWARE_QMC5883L == 1 OswDevices::QMC5883L* qmc5883l; #endif @@ -50,4 +50,4 @@ class OswHal::Devices { friend OswHal; friend std::unique_ptr::deleter_type; private: -}; \ No newline at end of file +}; diff --git a/include/hal/environment.h b/include/hal/environment.h index 4bf7e2013..1167ef0a7 100644 --- a/include/hal/environment.h +++ b/include/hal/environment.h @@ -8,6 +8,7 @@ #include #include #include +#include OSW_TARGET_PLATFORM_HEADER #if OSW_PLATFORM_ENVIRONMENT == 1 class OswHal::Environment { @@ -28,6 +29,9 @@ class OswHal::Environment { #endif #if OSW_PLATFORM_ENVIRONMENT_MAGNETOMETER == 1 + int getMagnetometerX(); + int getMagnetometerY(); + int getMagnetometerZ(); int getMagnetometerAzimuth(); #endif @@ -35,6 +39,7 @@ class OswHal::Environment { float getAccelerationX(); float getAccelerationY(); float getAccelerationZ(); + OswAccelerationProvider::ActivityMode getActivityMode(); // Statistics: Steps uint32_t getStepsToday(); void resetStepCount(); @@ -67,4 +72,4 @@ class OswHal::Environment { OswHumidityProvider* humiSensor = nullptr; OswPressureProvider* pressSensor = nullptr; }; -#endif \ No newline at end of file +#endif diff --git a/include/icon/OswIconProgmem.h b/include/icon/OswIconProgmem.h index 45bf87bad..5e9acf033 100644 --- a/include/icon/OswIconProgmem.h +++ b/include/icon/OswIconProgmem.h @@ -12,4 +12,4 @@ class OswIconProgmem: public OswIcon { const unsigned char* data; const unsigned char dimension; -}; \ No newline at end of file +}; diff --git a/include/locales/cs-CZ.h b/include/locales/cs-CZ.h index 9d87738d3..147939385 100644 --- a/include/locales/cs-CZ.h +++ b/include/locales/cs-CZ.h @@ -25,4 +25,4 @@ #define LANG_SUNDAY "Nedele" // At the very last: Include English as a fallback -> any keys not found in the current language, they will be defined in English -#include "en-US.h" \ No newline at end of file +#include "en-US.h" diff --git a/include/locales/de-DE.h b/include/locales/de-DE.h index 7abaa28b7..c94b34db4 100644 --- a/include/locales/de-DE.h +++ b/include/locales/de-DE.h @@ -31,9 +31,9 @@ #define LANG_SETTINGS "Einstellungen" #define LANG_GAMES "Spiele" #define LANG_MIX "Mixtur" -#define LANG_MIX "Zweifach" #define LANG_BINARY "Binaer" #define LANG_MONO "Einfach" +#define LANG_AFIT "Analog+Schritt" // App: Time from web #define LANG_TFW_UPDATE "Abfragen" @@ -134,4 +134,4 @@ #define LANG_EMULATOR_MBTN_HELP "Wenn du eine beliebige Taste gedrückt hältst und dann eine andere Taste drückst, werden alle anderen gedrückten Tasten losgelassen." // At the very last: Include English as a fallback -> any keys not found in the current language, they will be defined in English -#include "en-US.h" \ No newline at end of file +#include "en-US.h" diff --git a/include/locales/en-US.h b/include/locales/en-US.h index 0d9dcf46c..9950139ed 100644 --- a/include/locales/en-US.h +++ b/include/locales/en-US.h @@ -112,6 +112,9 @@ #ifndef LANG_NUMERALS #define LANG_NUMERALS "Numerals" #endif +#ifndef LANG_AFIT +#define LANG_AFIT "Analog+Fit" +#endif // App: Time from web #ifndef LANG_TFW_UPDATE @@ -349,4 +352,4 @@ #endif #ifndef LANG_EMULATOR_MBTN_HELP #define LANG_EMULATOR_MBTN_HELP "Whenever you press-and-hold any butten(s) by activating their checkbox(es) and then click-and-release any button normally, all other held buttons will also be released." -#endif \ No newline at end of file +#endif diff --git a/include/locales/fr-FR.h b/include/locales/fr-FR.h index 607f0ba8f..f8cbf1618 100644 --- a/include/locales/fr-FR.h +++ b/include/locales/fr-FR.h @@ -21,4 +21,4 @@ #define LANG_SUNDAY "Dimanche" // At the very last: Include English as a fallback -> any keys not found in the current language, they will be defined in English -#include "en-US.h" \ No newline at end of file +#include "en-US.h" diff --git a/include/locales/hu-HU.h b/include/locales/hu-HU.h index c7943e64f..56f4d3952 100644 --- a/include/locales/hu-HU.h +++ b/include/locales/hu-HU.h @@ -25,4 +25,4 @@ #define LANG_SUNDAY "Vasárnap" // At the very last: Include English as a fallback -> any keys not found in the current language, they will be defined in English -#include "en-US.h" \ No newline at end of file +#include "en-US.h" diff --git a/include/locales/it-IT.h b/include/locales/it-IT.h index 5f5bf7fcb..41f807e4f 100644 --- a/include/locales/it-IT.h +++ b/include/locales/it-IT.h @@ -25,4 +25,4 @@ #define LANG_SUNDAY "Domenica" // At the very last: Include English as a fallback -> any keys not found in the current language, they will be defined in English -#include "en-US.h" \ No newline at end of file +#include "en-US.h" diff --git a/include/locales/ko-KR.h b/include/locales/ko-KR.h index 50e5850f5..630f6b5d9 100644 --- a/include/locales/ko-KR.h +++ b/include/locales/ko-KR.h @@ -38,4 +38,4 @@ #endif // At the very last: Include English as a fallback -> any keys not found in the current language, they will be defined in English -#include "en-US.h" \ No newline at end of file +#include "en-US.h" diff --git a/include/math_angles.h b/include/math_angles.h index 2675766b4..296404cc1 100644 --- a/include/math_angles.h +++ b/include/math_angles.h @@ -1,40 +1,77 @@ #ifndef GFX_ANGLES_H #define GFX_ANGLES_H +#include #include +extern const float sinDeg[]; + /** * @brief Find the x-axis point which is at a distance r and an angle d of a point C(cx,cy). * - * 0 degrees ist 12 o'clock + * 0 degrees is 12 o'clock * - * This function can be used to find coordonnates of the extremity of the clock hand from the center + * This function can be used to find coordinates of the extremity of the clock hand from the center * * @param cx x value of the initial point * @param r radius - * @param d angle in degrees (0° is 12 o'clock) - * @return float + * @param deg angle in degrees (0° is 12 o'clock) + * @return int32_t */ -float rpx(float cx, float x, float r); +inline int32_t rpx(int32_t cx, int32_t r, float deg) { + return cx + (float) r * cosf((deg - 90) * (float) PI / 180) + 0.5f; +} +// integer version for deg +inline int32_t rpx(int32_t cx, int32_t r, int32_t deg) { + deg -= 90; + deg -= 90; // to use sine + while (deg < 0) + deg += 360; + while (deg > 360) + deg -= 360; + return cx + (float) r * sinDeg[deg] + 0.5f; +} /** * Find the y-axis of a point which is at a distance r and an angle d of a point C(cx,cy). * - * 0 degrees ist 12 o'clock - * This function can be used to find coordonnates of the extremity of the clock hand from the center + * 0 degrees is 12 o'clock + * This function can be used to find coordinates of the extremity of the clock hand from the center * * @param cy y value of the initial point * @param r radius - * @param d angle in degrees (0° is 12 o'clock) + * @param deg angle in degrees (0° is 12 o'clock) * @return float */ -float rpy(float cy, float y, float r); +inline int32_t rpy(int32_t cy, int32_t r, float deg) { + return cy + (float) r * sinf((deg - 90) * (float) PI / 180) + 0.5f; +} + +// integer version for deg +inline int32_t rpy(int32_t cy, int32_t r, int32_t deg) { + deg -= 90; + while (deg < 0) + deg += 360; + while (deg > 360) + deg -= 360; + return cy + (float) r * sinDeg[deg] + 0.5f; +} + +// rotate a point around a point +inline int32_t rotateX(int32_t x, int32_t y, int32_t rx, int32_t ry, float cosA, float sinA) { + return (x - rx) * cosA + (y - ry) * sinA; +} +inline int32_t rotateY(int32_t x, int32_t y, int32_t rx, int32_t ry, float cosA, float sinA) { + return (y - ry) * cosA - (x - rx) * sinA; +} -int32_t rotateX(int32_t x, int32_t y, int32_t rx, int32_t ry, float cosA, float sinA); -int32_t rotateY(int32_t x, int32_t y, int32_t rx, int32_t ry, float cosA, float sinA); -int32_t rotateX(int32_t x, int32_t y, int32_t rx, int32_t ry, float a); -int32_t rotateY(int32_t x, int32_t y, int32_t rx, int32_t ry, float a); +inline int32_t rotateX(int32_t x, int32_t y, int32_t rx, int32_t ry, float a) { + return (x - rx) * cosf(a) + (y - ry) * sinf(a); +} +inline int32_t rotateY(int32_t x, int32_t y, int32_t rx, int32_t ry, float a) { + return (y - ry) * cosf(a) - (x - rx) * sinf(a); +} /** * Convert seconds in degrees. @@ -53,4 +90,4 @@ float m2d(long seconds); float h2d(long seconds); bool pointInsideTriangle(float px, float py, float x1, float y1, float x2, float y2, float x3, float y3); -#endif \ No newline at end of file +#endif diff --git a/include/math_osm.h b/include/math_osm.h index cc07886bc..d1a97f30e 100644 --- a/include/math_osm.h +++ b/include/math_osm.h @@ -20,4 +20,4 @@ float tiley2lat(float y, uint8_t z); float getTileResolution(float lat, uint8_t z); -#endif \ No newline at end of file +#endif diff --git a/include/osw_config_keys.h b/include/osw_config_keys.h index aa93098c3..9a556dec9 100644 --- a/include/osw_config_keys.h +++ b/include/osw_config_keys.h @@ -57,16 +57,17 @@ extern OswConfigKeyShort settingDisplayBrightness; extern OswConfigKeyBool settingDisplayOverlays; extern OswConfigKeyBool settingDisplayOverlaysForced; extern OswConfigKeyBool settingDisplayDualHourTick; +#if OSW_PLATFORM_BLOCK_SLEEP != 1 extern OswConfigKeyBool raiseToWakeEnabled; extern OswConfigKeyShort raiseToWakeSensitivity; extern OswConfigKeyBool tapToWakeEnabled; extern OswConfigKeyBool lightSleepEnabled; extern OswConfigKeyBool buttonToWakeEnabled; +#endif extern OswConfigKeyDropDown dateFormat; extern OswConfigKeyBool timeFormat; extern OswConfigKeyString timezonePrimary; extern OswConfigKeyString timezoneSecondary; -extern OswConfigKeyShort resetDay; #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 extern OswConfigKeyShort configHeight; extern OswConfigKeyShort configWeight; @@ -75,6 +76,7 @@ extern OswConfigKeyInt distPerDay; extern OswConfigKeyInt kcalPerDay; extern OswConfigKeyBool stepsHistoryClear; extern OswConfigKeyBool settingDisplayStepsGoal; +extern OswConfigKeyShort resetDay; #endif extern OswConfigKeyDropDown settingDisplayDefaultWatchface; #ifdef OSW_FEATURE_WEATHER diff --git a/include/osw_hal.h b/include/osw_hal.h index dc467dafb..aa64f569f 100644 --- a/include/osw_hal.h +++ b/include/osw_hal.h @@ -28,6 +28,20 @@ #define ERR_SD_MISSING 1 #define ERR_SD_MOUNT_FAILED 2 +typedef struct { + uint32_t hour; + uint32_t minute; + uint32_t second; + bool afterNoon; +} OswTime; + +typedef struct { + uint32_t year; + uint32_t month; + uint32_t day; + uint32_t weekDay; +} OswDate; + class OswHal { public: static OswHal* getInstance(); @@ -64,7 +78,7 @@ class OswHal { // Setup void setup(bool fromLightSleep); void setupFileSystem(void); - void setupButtons(void); + void setupButtons(); void setupDisplay(); void setupPower(bool fromLightSleep); #if defined(GPS_EDITION) || defined(GPS_EDITION_ROTATED) @@ -181,7 +195,7 @@ class OswHal { // UTC Time void setUTCTime(const time_t& epoch); time_t getUTCTime(); - void getUTCTime(uint32_t* hour, uint32_t* minute, uint32_t* second); + void getUTCTime(OswTime& oswTime); // Offset getters for primary / secondary time (cached!) time_t getTimezoneOffsetPrimary(); @@ -189,43 +203,39 @@ class OswHal { // New time functions with offset time_t getTime(time_t& offset); - void getTime(time_t& offset, uint32_t* hour, uint32_t* minute, uint32_t* second, bool* afterNoon = nullptr); - void getDate(time_t& offset, uint32_t* day, uint32_t* weekDay); - void getDate(time_t& offset, uint32_t* day, uint32_t* month, uint32_t* year); - const char* getWeekday(time_t& offset, uint32_t* setWDay = nullptr); + void getTime(time_t& offset, OswTime& oswTime); + void getDate(time_t& offset, OswDate& oswDate); // For backward compatibility: Local time functions (= primary timezone) - inline void getLocalTime(uint32_t* hour, uint32_t* minute, uint32_t* second, bool* afterNoon = nullptr) { - this->getTime(this->timezoneOffsetPrimary, hour, minute, second, afterNoon); + inline void getLocalTime(OswTime& oswTime) { + this->getTime(this->timezoneOffsetPrimary, oswTime); } inline uint32_t getLocalTime() { return this->getTime(this->timezoneOffsetPrimary); } - inline void getLocalDate(uint32_t* day, uint32_t* weekDay) { - this->getDate(this->timezoneOffsetPrimary, day, weekDay); - }; - inline void getLocalDate(uint32_t* day, uint32_t* month, uint32_t* year) { - this->getDate(this->timezoneOffsetPrimary, day, month, year); - }; - inline const char* getLocalWeekday(uint32_t* sWDay = nullptr) { - return this->getWeekday(this->timezoneOffsetPrimary, sWDay); + inline void getLocalDate(OswDate& oswDate) { + this->getDate(this->timezoneOffsetPrimary, oswDate); }; // For backward compatibility: Dual time functions (= secondary timezone) - inline void getDualTime(uint32_t* hour, uint32_t* minute, uint32_t* second, bool* afterNoon = nullptr) { - this->getTime(this->timezoneOffsetSecondary, hour, minute, second, afterNoon); + inline void getDualTime(OswTime& oswTime) { + this->getTime(this->timezoneOffsetSecondary, oswTime); } inline uint32_t getDualTime() { return this->getTime(this->timezoneOffsetSecondary); } - inline void getDualDate(uint32_t* day, uint32_t* weekDay) { - this->getDate(this->timezoneOffsetSecondary, day, weekDay); + inline void getDualDate(OswDate& oswDate) { + this->getDate(this->timezoneOffsetPrimary, oswDate); }; - inline void getDualDate(uint32_t* day, uint32_t* month, uint32_t* year) { - this->getDate(this->timezoneOffsetSecondary, day, month, year); - }; - inline const char* getDualWeekday(uint32_t* sWDay = nullptr) { - return this->getWeekday(this->timezoneOffsetSecondary, sWDay); + + const std::array getWeekDay = { + LANG_SUNDAY, + LANG_MONDAY, + LANG_TUESDAY, + LANG_WEDNESDAY, + LANG_THURSDAY, + LANG_FRIDAY, + LANG_SATURDAY }; bool _requestDisableBuffer = false; @@ -284,9 +294,12 @@ class OswHal { void persistWakeUpConfig(OswHal::WakeUpConfig* config, bool toLightSleep); std::optional readAndResetWakeUpConfig(bool fromLightSleep); void resetWakeUpConfig(bool useLightSleep); +#if OSW_PLATFORM_IS_FLOW3R_BADGE == 1 + uint8_t readGpioExtender(uint8_t address = 0x6D); +#endif }; #endif #include "hal/devices.h" -#include "hal/environment.h" \ No newline at end of file +#include "hal/environment.h" diff --git a/include/osw_lua.h b/include/osw_lua.h index c0daef23a..a472753e9 100644 --- a/include/osw_lua.h +++ b/include/osw_lua.h @@ -8,4 +8,4 @@ extern "C" { }; void halToLua(lua_State* L); -#endif \ No newline at end of file +#endif diff --git a/include/osw_pins.h b/include/osw_pins.h index c8f80a0ff..afad31f61 100644 --- a/include/osw_pins.h +++ b/include/osw_pins.h @@ -2,25 +2,6 @@ // NOTE This file will slowly be migrated into the platform header files. -// pin mapping -#if defined(GPS_EDITION) || defined(GPS_EDITION_ROTATED) -#define TFT_CS 5 -#define TFT_DC 12 -#define TFT_RST 2 -#define TFT_SCK 18 -#define TFT_MOSI 23 -#define TFT_MISO -1 // no data coming back -#define TFT_LED 9 -#else -#define TFT_CS 5 -#define TFT_DC 12 -#define TFT_RST 33 -#define TFT_SCK 18 -#define TFT_MOSI 23 -#define TFT_MISO -1 // no data coming back -#define TFT_LED 9 -#endif - #define SD_CS 4 // SD_MISO 19 // for SCK, MOSI see TFT @@ -30,19 +11,19 @@ #define GPS_FON 26 #define GPS_3D_FIX 36 #define GPS_GEO_FENCE 39 -#define RX1 27 -#define TX1 14 #if defined(GPS_EDITION) #define BTN_1 0 #define BTN_2 13 #define BTN_3 33 -#define VIBRATE 35 +#define GPS_RX1 27 +#define GPS_TX1 14 #elif defined(GPS_EDITION_ROTATED) #define BTN_1 13 #define BTN_2 33 #define BTN_3 0 -#define VIBRATE 35 +#define GPS_RX1 27 +#define GPS_TX1 14 #else #define BTN_1 0 #define BTN_2 13 @@ -63,4 +44,4 @@ #define BTN_POS_ISTOP_ARRAY {false, true, false} #define BTN_POS_ISLEFT_ARRAY {true, false, false} #define BTN_NAME_ARRAY {"SELECT", "UP", "DOWN"} -#define BTN_PIN_ARRAY {BTN_1, BTN_2, BTN_3} \ No newline at end of file +#define BTN_PIN_ARRAY {BTN_1, BTN_2, BTN_3} diff --git a/include/osw_service.h b/include/osw_service.h index af90c8847..a03fc1801 100644 --- a/include/osw_service.h +++ b/include/osw_service.h @@ -13,4 +13,4 @@ class OswServiceTask : public OswApp { private: bool taskEnabled = false; }; -#endif \ No newline at end of file +#endif diff --git a/include/osw_util.h b/include/osw_util.h index 3d94e3ab0..a53e017b2 100644 --- a/include/osw_util.h +++ b/include/osw_util.h @@ -18,4 +18,4 @@ constexpr size_t size(T (&)[N]) { } -#endif \ No newline at end of file +#endif diff --git a/include/overlays/overlays.h b/include/overlays/overlays.h index c0c574bab..bb87a94fa 100644 --- a/include/overlays/overlays.h +++ b/include/overlays/overlays.h @@ -2,4 +2,4 @@ #include "osw_hal.h" -void drawOverlays(); \ No newline at end of file +void drawOverlays(); diff --git a/include/platform/EMULATOR.h b/include/platform/EMULATOR.h index c604ca51c..8188c9f9b 100644 --- a/include/platform/EMULATOR.h +++ b/include/platform/EMULATOR.h @@ -9,10 +9,24 @@ //#define OSW_PLATFORM_HARDWARE_DS3231MZ 0 //#define OSW_PLATFORM_HARDWARE_BMA400 0 +//#define OSW_PLATFORM_HARDWARE_BMI270 0 +//#define OSW_PLATFORM_HARDWARE_BMP581 0 //#define OSW_PLATFORM_HARDWARE_BME280 0 //#define OSW_PLATFORM_HARDWARE_QMC5883L 0 #define OSW_PLATFORM_HARDWARE_VIRTUAL 1 #define OSW_PLATFORM_HARDWARE_ESP32 0 +//#define OSW_PLATFORM_HARDWARE_ESP32_USE_JTAG_SERIAL 0 +//#define OSW_PLATFORM_HARDWARE_DISPLAY_CS 0 +//#define OSW_PLATFORM_HARDWARE_DISPLAY_DC 0 +//#define OSW_PLATFORM_HARDWARE_DISPLAY_RST 0 +//#define OSW_PLATFORM_HARDWARE_DISPLAY_SCK 0 +//#define OSW_PLATFORM_HARDWARE_DISPLAY_MOSI 0 +//#define OSW_PLATFORM_HARDWARE_DISPLAY_LED 0 +//#define OSW_PLATFORM_HARDWARE_DISPLAY_SPI_NUM 0 +//#define OSW_PLATFORM_HARDWARE_DISPLAY_ROTATION 0 +//#define OSW_PLATFORM_HARDWARE_VIBRATE 0 +//#define OSW_PLATFORM_BLOCK_SLEEP 0 // used during the integration of new platforms to prevent the device from going to sleep +//#define OSW_PLATFORM_IS_FLOW3R_BADGE 0 #define OSW_PLATFORM_DEFAULT_CPUFREQ 0 //#define OSW_DEVICE_ESP32_WIFI_LOWPWR 0 @@ -22,4 +36,5 @@ //#define OSW_DEVICE_I2C_SCL 22 //#define OSW_DEVICE_I2C_SDA 21 #define OSW_DEVICE_TPS2115A_STATPWR 15 -#define OSW_DEVICE_ESP32_BATLVL 25 \ No newline at end of file +#define OSW_DEVICE_ESP32_BATLVL 25 +#define OSW_DEVICE_ESP32_USE_INTTEMP 0 diff --git a/include/platform/FLOW3R_C3CAMP_2023.h b/include/platform/FLOW3R_C3CAMP_2023.h new file mode 100644 index 000000000..bd4b4820a --- /dev/null +++ b/include/platform/FLOW3R_C3CAMP_2023.h @@ -0,0 +1,41 @@ +#pragma once + +#define OSW_PLATFORM_ENVIRONMENT 1 +#define OSW_PLATFORM_ENVIRONMENT_TEMPERATURE 1 +//#define OSW_PLATFORM_ENVIRONMENT_PRESSURE 0 +//#define OSW_PLATFORM_ENVIRONMENT_HUMIDITY 0 +//#define OSW_PLATFORM_ENVIRONMENT_MAGNETOMETER 0 +#define OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER 1 + +//#define OSW_PLATFORM_HARDWARE_DS3231MZ 0 +//#define OSW_PLATFORM_HARDWARE_BMA400 0 +#define OSW_PLATFORM_HARDWARE_BMI270 1 +//#define OSW_PLATFORM_HARDWARE_BMP581 0 +//#define OSW_PLATFORM_HARDWARE_QMC5883L 0 +//#define OSW_PLATFORM_HARDWARE_BME280 0 +//#define OSW_PLATFORM_HARDWARE_VIRTUAL 0 +#define OSW_PLATFORM_HARDWARE_ESP32 1 +#define OSW_PLATFORM_HARDWARE_ESP32_USE_JTAG_SERIAL 1 +#define OSW_PLATFORM_HARDWARE_DISPLAY_CS 40 +#define OSW_PLATFORM_HARDWARE_DISPLAY_DC 38 +// well, the display reset pin is located at MAX7321ATE (U7), pin 5 (P3) +#define OSW_PLATFORM_HARDWARE_DISPLAY_RST -1 +#define OSW_PLATFORM_HARDWARE_DISPLAY_SCK 41 +#define OSW_PLATFORM_HARDWARE_DISPLAY_MOSI 42 +#define OSW_PLATFORM_HARDWARE_DISPLAY_LED 46 +#define OSW_PLATFORM_HARDWARE_DISPLAY_SPI_NUM 0 +#define OSW_PLATFORM_HARDWARE_DISPLAY_ROTATION 2 +//#define OSW_PLATFORM_HARDWARE_VIBRATE 0 +#define OSW_PLATFORM_BLOCK_SLEEP 1 // used during the integration of new platforms to prevent the device from going to sleep +#define OSW_PLATFORM_IS_FLOW3R_BADGE 1 +#define OSW_PLATFORM_DEFAULT_CPUFREQ 240 + +#define OSW_DEVICE_ESP32_WIFI_LOWPWR 0 +//#define OSW_DEVICE_DS3231MZ_RTCINT 32 +//#define OSW_DEVICE_BMA400_INT1 34 +//#define OSW_DEVICE_BMA400_INT2 35 +#define OSW_DEVICE_I2C_SCL 1 +#define OSW_DEVICE_I2C_SDA 2 +//#define OSW_DEVICE_TPS2115A_STATPWR 0 +#define OSW_DEVICE_ESP32_BATLVL 9 +#define OSW_DEVICE_ESP32_USE_INTTEMP 0 diff --git a/include/platform/GPS_EDITION_V3_1.h b/include/platform/GPS_EDITION_V3_1.h index dbf3c240c..52a0ce21a 100644 --- a/include/platform/GPS_EDITION_V3_1.h +++ b/include/platform/GPS_EDITION_V3_1.h @@ -1,5 +1,8 @@ #pragma once +// This flag is used for the rotated variant of the PCB +//#define GPS_EDITION_ROTATED 1 + #define OSW_PLATFORM_ENVIRONMENT 1 #define OSW_PLATFORM_ENVIRONMENT_TEMPERATURE 1 #define OSW_PLATFORM_ENVIRONMENT_PRESSURE 1 @@ -9,10 +12,28 @@ #define OSW_PLATFORM_HARDWARE_DS3231MZ 1 #define OSW_PLATFORM_HARDWARE_BMA400 1 +//#define OSW_PLATFORM_HARDWARE_BMI270 0 +//#define OSW_PLATFORM_HARDWARE_BMP581 0 #define OSW_PLATFORM_HARDWARE_BME280 1 #define OSW_PLATFORM_HARDWARE_QMC5883L 1 //#define OSW_PLATFORM_HARDWARE_VIRTUAL 0 #define OSW_PLATFORM_HARDWARE_ESP32 1 +//#define OSW_PLATFORM_HARDWARE_ESP32_USE_JTAG_SERIAL 0 +#define OSW_PLATFORM_HARDWARE_DISPLAY_CS 5 +#define OSW_PLATFORM_HARDWARE_DISPLAY_DC 12 +#define OSW_PLATFORM_HARDWARE_DISPLAY_RST 2 +#define OSW_PLATFORM_HARDWARE_DISPLAY_SCK 18 +#define OSW_PLATFORM_HARDWARE_DISPLAY_MOSI 23 +#define OSW_PLATFORM_HARDWARE_DISPLAY_LED 9 +#define OSW_PLATFORM_HARDWARE_DISPLAY_SPI_NUM VSPI +#ifdef GPS_EDITION_ROTATED +#define OSW_PLATFORM_HARDWARE_DISPLAY_ROTATION 1 +#else +#define OSW_PLATFORM_HARDWARE_DISPLAY_ROTATION 0 +#endif +#define OSW_PLATFORM_HARDWARE_VIBRATE 35 +//#define OSW_PLATFORM_BLOCK_SLEEP 0 // used during the integration of new platforms to prevent the device from going to sleep +//#define OSW_PLATFORM_IS_FLOW3R_BADGE 0 #define OSW_PLATFORM_DEFAULT_CPUFREQ 240 #define OSW_DEVICE_ESP32_WIFI_LOWPWR 1 @@ -22,4 +43,5 @@ #define OSW_DEVICE_I2C_SCL 22 #define OSW_DEVICE_I2C_SDA 21 #define OSW_DEVICE_TPS2115A_STATPWR 15 -#define OSW_DEVICE_ESP32_BATLVL 25 \ No newline at end of file +#define OSW_DEVICE_ESP32_BATLVL 25 +#define OSW_DEVICE_ESP32_USE_INTTEMP 1 diff --git a/include/platform/LIGHT_EDITION_V3_3.h b/include/platform/LIGHT_EDITION_V3_3.h index 33810e725..5b7b0264c 100644 --- a/include/platform/LIGHT_EDITION_V3_3.h +++ b/include/platform/LIGHT_EDITION_V3_3.h @@ -9,10 +9,24 @@ #define OSW_PLATFORM_HARDWARE_DS3231MZ 1 #define OSW_PLATFORM_HARDWARE_BMA400 1 +//#define OSW_PLATFORM_HARDWARE_BMI270 0 +//#define OSW_PLATFORM_HARDWARE_BMP581 0 //#define OSW_PLATFORM_HARDWARE_QMC5883L 0 //#define OSW_PLATFORM_HARDWARE_BME280 0 //#define OSW_PLATFORM_HARDWARE_VIRTUAL 0 #define OSW_PLATFORM_HARDWARE_ESP32 1 +//#define OSW_PLATFORM_HARDWARE_ESP32_USE_JTAG_SERIAL 0 +#define OSW_PLATFORM_HARDWARE_DISPLAY_CS 5 +#define OSW_PLATFORM_HARDWARE_DISPLAY_DC 12 +#define OSW_PLATFORM_HARDWARE_DISPLAY_RST 33 +#define OSW_PLATFORM_HARDWARE_DISPLAY_SCK 18 +#define OSW_PLATFORM_HARDWARE_DISPLAY_MOSI 23 +#define OSW_PLATFORM_HARDWARE_DISPLAY_LED 9 +#define OSW_PLATFORM_HARDWARE_DISPLAY_SPI_NUM VSPI +#define OSW_PLATFORM_HARDWARE_DISPLAY_ROTATION 0 +//#define OSW_PLATFORM_HARDWARE_VIBRATE 0 +//#define OSW_PLATFORM_BLOCK_SLEEP 0 // used during the integration of new platforms to prevent the device from going to sleep +//#define OSW_PLATFORM_IS_FLOW3R_BADGE 0 #define OSW_PLATFORM_DEFAULT_CPUFREQ 240 #define OSW_DEVICE_ESP32_WIFI_LOWPWR 1 @@ -22,4 +36,5 @@ #define OSW_DEVICE_I2C_SCL 22 #define OSW_DEVICE_I2C_SDA 21 #define OSW_DEVICE_TPS2115A_STATPWR 15 -#define OSW_DEVICE_ESP32_BATLVL 25 \ No newline at end of file +#define OSW_DEVICE_ESP32_BATLVL 25 +#define OSW_DEVICE_ESP32_USE_INTTEMP 1 diff --git a/include/platform/LIGHT_EDITION_V4_0.h b/include/platform/LIGHT_EDITION_V4_0.h index 711fccca8..28366a0e0 100644 --- a/include/platform/LIGHT_EDITION_V4_0.h +++ b/include/platform/LIGHT_EDITION_V4_0.h @@ -9,10 +9,24 @@ #define OSW_PLATFORM_HARDWARE_DS3231MZ 1 #define OSW_PLATFORM_HARDWARE_BMA400 1 +//#define OSW_PLATFORM_HARDWARE_BMI270 0 +//#define OSW_PLATFORM_HARDWARE_BMP581 0 //#define OSW_PLATFORM_HARDWARE_BME280 0 //#define OSW_PLATFORM_HARDWARE_QMC5883L 0 //#define OSW_PLATFORM_HARDWARE_VIRTUAL 0 #define OSW_PLATFORM_HARDWARE_ESP32 1 +//#define OSW_PLATFORM_HARDWARE_ESP32_USE_JTAG_SERIAL 0 +#define OSW_PLATFORM_HARDWARE_DISPLAY_CS 5 +#define OSW_PLATFORM_HARDWARE_DISPLAY_DC 12 +#define OSW_PLATFORM_HARDWARE_DISPLAY_RST 33 +#define OSW_PLATFORM_HARDWARE_DISPLAY_SCK 18 +#define OSW_PLATFORM_HARDWARE_DISPLAY_MOSI 23 +#define OSW_PLATFORM_HARDWARE_DISPLAY_LED 9 +#define OSW_PLATFORM_HARDWARE_DISPLAY_SPI_NUM VSPI +#define OSW_PLATFORM_HARDWARE_DISPLAY_ROTATION 0 +//#define OSW_PLATFORM_HARDWARE_VIBRATE 0 +//#define OSW_PLATFORM_BLOCK_SLEEP 0 // used during the integration of new platforms to prevent the device from going to sleep +//#define OSW_PLATFORM_IS_FLOW3R_BADGE 0 #define OSW_PLATFORM_DEFAULT_CPUFREQ 240 //#define OSW_DEVICE_ESP32_WIFI_LOWPWR 0 @@ -22,4 +36,5 @@ #define OSW_DEVICE_I2C_SCL 22 #define OSW_DEVICE_I2C_SDA 21 #define OSW_DEVICE_TPS2115A_STATPWR 15 -#define OSW_DEVICE_ESP32_BATLVL 25 \ No newline at end of file +#define OSW_DEVICE_ESP32_BATLVL 25 +#define OSW_DEVICE_ESP32_USE_INTTEMP 1 diff --git a/include/platform/MINIMAL.h b/include/platform/MINIMAL.h new file mode 100644 index 000000000..153aab22e --- /dev/null +++ b/include/platform/MINIMAL.h @@ -0,0 +1,40 @@ +#pragma once + +//#define OSW_PLATFORM_ENVIRONMENT 0 +//#define OSW_PLATFORM_ENVIRONMENT_TEMPERATURE 0 +//#define OSW_PLATFORM_ENVIRONMENT_PRESSURE 0 +//#define OSW_PLATFORM_ENVIRONMENT_HUMIDITY 0 +//#define OSW_PLATFORM_ENVIRONMENT_MAGNETOMETER 0 +//#define OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER 0 + +//#define OSW_PLATFORM_HARDWARE_DS3231MZ 0 +//#define OSW_PLATFORM_HARDWARE_BMA400 0 +//#define OSW_PLATFORM_HARDWARE_BMI270 0 +//#define OSW_PLATFORM_HARDWARE_BMP581 0 +//#define OSW_PLATFORM_HARDWARE_BME280 0 +//#define OSW_PLATFORM_HARDWARE_QMC5883L 0 +//#define OSW_PLATFORM_HARDWARE_VIRTUAL 0 +//#define OSW_PLATFORM_HARDWARE_ESP32 0 +//#define OSW_PLATFORM_HARDWARE_ESP32_USE_JTAG_SERIAL 0 +#define OSW_PLATFORM_HARDWARE_DISPLAY_CS 0 +#define OSW_PLATFORM_HARDWARE_DISPLAY_DC 0 +//#define OSW_PLATFORM_HARDWARE_DISPLAY_RST 0 +#define OSW_PLATFORM_HARDWARE_DISPLAY_SCK 0 +#define OSW_PLATFORM_HARDWARE_DISPLAY_MOSI 0 +//#define OSW_PLATFORM_HARDWARE_DISPLAY_LED 0 +#define OSW_PLATFORM_HARDWARE_DISPLAY_SPI_NUM 0 +//#define OSW_PLATFORM_HARDWARE_DISPLAY_ROTATION 0 +//#define OSW_PLATFORM_HARDWARE_VIBRATE 0 +//#define OSW_PLATFORM_BLOCK_SLEEP 0 // used during the integration of new platforms to prevent the device from going to sleep +//#define OSW_PLATFORM_IS_FLOW3R_BADGE 0 +//#define OSW_PLATFORM_DEFAULT_CPUFREQ 0 + +//#define OSW_DEVICE_ESP32_WIFI_LOWPWR 0 +//#define OSW_DEVICE_DS3231MZ_RTCINT 0 +//#define OSW_DEVICE_BMA400_INT1 0 +//#define OSW_DEVICE_BMA400_INT2 0 +//#define OSW_DEVICE_I2C_SCL 0 +//#define OSW_DEVICE_I2C_SDA 0 +//#define OSW_DEVICE_TPS2115A_STATPWR 0 +//#define OSW_DEVICE_ESP32_BATLVL 0 +//#define OSW_DEVICE_ESP32_USE_INTTEMP 0 diff --git a/include/services/NotifierClient.h b/include/services/NotifierClient.h index ab4b37c01..de2966695 100644 --- a/include/services/NotifierClient.h +++ b/include/services/NotifierClient.h @@ -24,4 +24,4 @@ class NotifierClient { const std::string publisher{}; }; -#endif \ No newline at end of file +#endif diff --git a/include/services/OswServiceManager.h b/include/services/OswServiceManager.h index 9574c73f9..8b3d4359f 100644 --- a/include/services/OswServiceManager.h +++ b/include/services/OswServiceManager.h @@ -25,7 +25,7 @@ class OswServiceManager { #else #define _SERVICE_WIFI 0 #endif - const unsigned workerStackSize = 1024 + (7168 * _SERVICE_WIFI); // If wifi is active, set to same size as core 0 + const unsigned workerStackSize = 2048 + (8192 * _SERVICE_WIFI); // If wifi is active, set to same size as core 0 const unsigned workerStartupDelay = 2000; const unsigned workerLoopDelay = 10; diff --git a/include/services/OswServiceTaskBLECompanion.h b/include/services/OswServiceTaskBLECompanion.h index bb68d05ad..0fc5e8228 100644 --- a/include/services/OswServiceTaskBLECompanion.h +++ b/include/services/OswServiceTaskBLECompanion.h @@ -2,6 +2,7 @@ #define OSW_SERVICE_COMPANION_H #ifndef OSW_EMULATOR +#if SERVICE_BLE_COMPANION == 1 #include #include #include @@ -43,4 +44,5 @@ class OswServiceTaskBLECompanion : public OswServiceTask { }; #endif -#endif \ No newline at end of file +#endif +#endif diff --git a/include/services/OswServiceTaskConsole.h b/include/services/OswServiceTaskConsole.h index dfb23eb19..9b5d7078d 100644 --- a/include/services/OswServiceTaskConsole.h +++ b/include/services/OswServiceTaskConsole.h @@ -19,4 +19,4 @@ class OswServiceTaskConsole : public OswServiceTask { bool m_locked = false; unsigned char m_lockCounter = 0; bool m_configuring = false; -}; \ No newline at end of file +}; diff --git a/include/services/OswServiceTaskGPS.h b/include/services/OswServiceTaskGPS.h index da3cc85c5..fba71a3c1 100644 --- a/include/services/OswServiceTaskGPS.h +++ b/include/services/OswServiceTaskGPS.h @@ -12,4 +12,4 @@ class OswServiceTaskGPS : public OswServiceTask { ~OswServiceTaskGPS() {}; }; -#endif \ No newline at end of file +#endif diff --git a/include/services/OswServiceTaskMemMonitor.h b/include/services/OswServiceTaskMemMonitor.h index 48a29b55e..2df9f763c 100644 --- a/include/services/OswServiceTaskMemMonitor.h +++ b/include/services/OswServiceTaskMemMonitor.h @@ -7,7 +7,7 @@ class OswServiceTaskMemMonitor : public OswServiceTask { OswServiceTaskMemMonitor() {}; virtual void setup() override; virtual void loop() override; - void updateLoopTaskStats(); // Call this from the main loop regulary! + void updateLoopTaskStats(); // Call this from the main loop regularly! void printStats(); bool hasLowMemoryCondition(); ~OswServiceTaskMemMonitor() {}; @@ -17,4 +17,4 @@ class OswServiceTaskMemMonitor : public OswServiceTask { unsigned core1high; unsigned heapHigh; bool lowMemoryCondition = false; -}; \ No newline at end of file +}; diff --git a/include/services/OswServiceTaskNotifier.h b/include/services/OswServiceTaskNotifier.h index 2ebc55097..2db09f124 100644 --- a/include/services/OswServiceTaskNotifier.h +++ b/include/services/OswServiceTaskNotifier.h @@ -76,4 +76,4 @@ class OswServiceTaskNotifier : public OswServiceTask { friend class TestOswServiceTaskNotifier; }; -#endif \ No newline at end of file +#endif diff --git a/include/services/OswServiceTaskWebserver.h b/include/services/OswServiceTaskWebserver.h index 33e4323ce..bb0f25d90 100644 --- a/include/services/OswServiceTaskWebserver.h +++ b/include/services/OswServiceTaskWebserver.h @@ -75,4 +75,4 @@ class OswServiceTaskWebserver : public OswServiceTask { }; #endif -#endif \ No newline at end of file +#endif diff --git a/include/services/OswServiceTaskWiFi.h b/include/services/OswServiceTaskWiFi.h index 0e9015b07..1aa11dc7a 100644 --- a/include/services/OswServiceTaskWiFi.h +++ b/include/services/OswServiceTaskWiFi.h @@ -56,13 +56,6 @@ class OswServiceTaskWiFi : public OswServiceTask { ~OswServiceTaskWiFi() {}; private: - //The ESP32 has some problems broadcasting its SSID while using client & station -#ifdef OSW_FEATURE_WIFI_APST - const bool onlyOneModeSimultaneously = false; -#else - const bool onlyOneModeSimultaneously = true; -#endif - bool m_bootDone = false; // This triggers the async setup inside the loop bool m_enableWiFi = false; bool m_enableClient = false; diff --git a/include/services/OswServiceTasks.h b/include/services/OswServiceTasks.h index d880bfaa2..154298e71 100644 --- a/include/services/OswServiceTasks.h +++ b/include/services/OswServiceTasks.h @@ -1,6 +1,5 @@ #include "osw_service.h" -class OswServiceTaskBLECompanion; class OswServiceTaskExample; class OswServiceTaskMemMonitor; class OswServiceTaskNotifier; @@ -10,6 +9,7 @@ class OswServiceTaskWebserver; #endif namespace OswServiceAllTasks { #if SERVICE_BLE_COMPANION == 1 +class OswServiceTaskBLECompanion; extern OswServiceTaskBLECompanion bleCompanion; #endif // extern OswServiceTaskExample example; diff --git a/lib/BMI270-API b/lib/BMI270-API new file mode 160000 index 000000000..d211d93e2 --- /dev/null +++ b/lib/BMI270-API @@ -0,0 +1 @@ +Subproject commit d211d93e223c57ceff7f488c5dd8381ed04ff271 diff --git a/lib/BMP581-API b/lib/BMP581-API new file mode 160000 index 000000000..c779b44bf --- /dev/null +++ b/lib/BMP581-API @@ -0,0 +1 @@ +Subproject commit c779b44bf3c682d1fc06b5771378361650028223 diff --git a/lib/ESP32-BLE-Keyboard b/lib/ESP32-BLE-Keyboard index f8dd48521..b7aaf9bb7 160000 --- a/lib/ESP32-BLE-Keyboard +++ b/lib/ESP32-BLE-Keyboard @@ -1 +1 @@ -Subproject commit f8dd4852113a722a6b8dc8af987e94cf84d73ad5 +Subproject commit b7aaf9bb711a04216e4417f1e2a6b0ee0eaeaf66 diff --git a/lib/open-smartwatch-web b/lib/open-smartwatch-web index 7e5954151..ac693e2e2 160000 --- a/lib/open-smartwatch-web +++ b/lib/open-smartwatch-web @@ -1 +1 @@ -Subproject commit 7e59541511c93f664d9ded8db499cb8a7a09df39 +Subproject commit ac693e2e29c70d64e0b70d57b5f43ef2cbad3074 diff --git a/platformio.ini b/platformio.ini index 02960c9fe..a153b84d0 100755 --- a/platformio.ini +++ b/platformio.ini @@ -11,8 +11,14 @@ [platformio] default_envs = LIGHT_EDITION_V3_3 +# =========================================== +# A note regarding the platform/library versions here: +# Due to potential upstream bugs, we pinned all versions to the latest known working version. +# While this will prevent the use of latest features, it will also prevent randomly breaking builds... +# =========================================== + [env] -platform = espressif32@^6.3.2 +platform = espressif32@6.8.1 ; for USE_ULP: use a special branch and git submodule add https://github.com/boarchuz/HULP.git ; platform_packages = ; framework-arduinoespressif32 @ https://github.com/marcovannoord/arduino-esp32.git#idf-release/v4.2 @@ -22,12 +28,12 @@ framework = arduino board_build.partitions = min_spiffs.csv ; OTA updates (two app slots), but no space for the SPIFFS (as it is currently not used) monitor_filters = esp32_exception_decoder ; Well, it works?! lib_deps = - adafruit/Adafruit Unified Sensor@^1.1.9 - adafruit/Adafruit BusIO@^1.14.1 - makuna/RTC@^2.4.0 - bblanchon/ArduinoJson@^6.21.2 - finitespace/BME280@^3.0.0 ; TODO Use the more popular Adafruit BME280 Library instead (also true for others?)? - mprograms/QMC5883LCompass@^1.1.1 + adafruit/Adafruit Unified Sensor@1.1.14 + adafruit/Adafruit BusIO@1.16.1 + makuna/RTC@2.4.3 + bblanchon/ArduinoJson@6.21.5 + finitespace/BME280@3.0.0 ; TODO Use the more popular Adafruit BME280 Library instead (also true for others?)? + mprograms/QMC5883LCompass@1.2.3 upload_speed = 460800 monitor_speed = 115200 ; Define additional build stage scripts - used to "compile" the html or define additional information @@ -38,6 +44,17 @@ extra_scripts = pre:scripts/build/prebuild_lua.py ; Needed to generate the .cxx file(s), enabled via "OSW_FEATURE_LUA" build flag build_unflags = -std=gnu++11 # The correct flag will be set by the cppflags python script... +# =========================================== +# A note regarding the environments here... +# If you add new ones, checkout `docs/support.md` and update the list there. +# If you wonder what flags are available, check the `docs/flags.md` file. +# =========================================== + +[env:MINIMAL] ; For development only, the absolute minimal operating system +build_flags = + -D OSW_TARGET_PLATFORM_HEADER='"platform/MINIMAL.h"' +build_type = debug + ; Light edition by hardware revisions ; This revision did not change anything on hardware or software level, it just resized the pcb from V3_2 [env:LIGHT_EDITION_V3_3] @@ -48,7 +65,7 @@ build_flags = -D OSW_FEATURE_WIFI build_type = debug -[env:LIGHT_EDITION_V4_0] +[env:EXPERIMENTAL_LIGHT_EDITION_V4_0] build_flags = -D OSW_TARGET_PLATFORM_HEADER='"platform/LIGHT_EDITION_V4_0.h"' -D OSW_FEATURE_STATS_STEPS @@ -58,13 +75,14 @@ build_flags = build_type = debug ; Light edition other stuff -[env:LIGHT_EDITION_DEV_LUA] +[env:EXPERIMENTAL_LIGHT_EDITION_V3_3_LUA] build_flags = -D OSW_TARGET_PLATFORM_HEADER='"platform/LIGHT_EDITION_V3_3.h"' -D OSW_FEATURE_LUA -D OSW_SERVICE_CONSOLE -D OSW_FEATURE_WIFI -D LUA_C89_NUMBERS ; Required by OSW_FEATURE_LUA + -Wdouble-promotion extra_scripts = pre:scripts/build/prebuild_info.py pre:scripts/build/prebuild_assets.py @@ -73,7 +91,7 @@ extra_scripts = build_type = debug ; GPS edition by hardware revisions -[env:GPS_EDITION_V3_1] +[env:EXPERIMENTAL_GPS_EDITION_V3_1] build_flags = -D OSW_TARGET_PLATFORM_HEADER='"platform/GPS_EDITION_V3_1.h"' -D GPS_EDITION @@ -83,12 +101,11 @@ build_flags = -D OSW_FEATURE_STATS_STEPS -D OSW_SERVICE_CONSOLE -D OSW_FEATURE_WIFI - -D OSW_FEATURE_WIFI_APST -D OSW_FEATURE_WIFI_ONBOOT build_type = debug ; GPS edition other stuff -[env:GPS_EDITION_DEV_ROTATED] +[env:EXPERIMENTAL_GPS_EDITION_DEV_ROTATED] build_flags = -D OSW_TARGET_PLATFORM_HEADER='"platform/GPS_EDITION_V3_1.h"' -D PROGMEM_TILES @@ -98,6 +115,15 @@ build_flags = -D OSW_FEATURE_STATS_STEPS -D OSW_SERVICE_CONSOLE -D OSW_FEATURE_WIFI - -D OSW_FEATURE_WIFI_APST + -D OSW_FEATURE_WIFI_ONBOOT +build_type = debug + +[env:3RD_PARTY_FLOW3R_C3CAMP_2023] +board = esp32-s3-devkitc-1 +upload_speed = 921600 ; the usb-c is more stable, allowing faster speeds +build_flags = + -D OSW_TARGET_PLATFORM_HEADER='"platform/FLOW3R_C3CAMP_2023.h"' + -D OSW_SERVICE_CONSOLE + -D OSW_FEATURE_WIFI -D OSW_FEATURE_WIFI_ONBOOT build_type = debug diff --git a/scripts/build/prebuild_assets.py b/scripts/build/prebuild_assets.py index ad3cc6180..149ff7cc0 100755 --- a/scripts/build/prebuild_assets.py +++ b/scripts/build/prebuild_assets.py @@ -31,9 +31,9 @@ def createAssets(srcPath, assPath, convertAssetToSourceCode, force): # fileStripped = file.removesuffix('.h').removesuffix('.gz') # the above line is only available in python 3.9, so we use the following instead: fileStripped = file - if (split := os.path.splitext(file))[1] == '.h': + if (split := os.path.splitext(fileStripped))[1] == '.h': fileStripped = split[0] - if (split := os.path.splitext(file))[1] == '.gz': + if (split := os.path.splitext(fileStripped))[1] == '.gz': fileStripped = split[0] assFile = os.path.join(subPath, fileStripped) path = os.path.relpath(assFile, assPath) @@ -93,7 +93,11 @@ def makeIconImgStr(srcPath, subPath): if not subPath.endswith('.png'): return None - img = Image.open(srcPath, 'r') + try: + img = Image.open(srcPath, 'r') + except: + print(f'!!! The build process noticed that the image {srcPath} is not a valid image. Please make sure it is in an valid image format - this is commonly caused by cloning this repository without Git LFS enabled.') + raise assert img.size[0] == img.size[1], 'Image must be square' assert img.size[0] % 8 == 0, 'Image dimension must be a multiple of 8' imgData = list(img.getdata()) @@ -157,4 +161,4 @@ def makePngImgStr(srcPath, subPath): useForce = "--force" in sys.argv createAssets(os.path.join('lib', 'open-smartwatch-web', 'dist', 'open-smartwatch-web'), os.path.join(args.output_asset_path, 'www'), makeGzStr, useForce) createAssets(os.path.join('img', 'icons'), os.path.join(args.output_asset_path, 'img', 'icons'), makeIconImgStr, useForce) -createAssets(os.path.join('img', 'static'), os.path.join(args.output_asset_path, 'img', 'static'), makePngImgStr, useForce) \ No newline at end of file +createAssets(os.path.join('img', 'static'), os.path.join(args.output_asset_path, 'img', 'static'), makePngImgStr, useForce) diff --git a/scripts/build/prebuild_info.py b/scripts/build/prebuild_info.py index a9b0e62e7..a4ed2fff8 100755 --- a/scripts/build/prebuild_info.py +++ b/scripts/build/prebuild_info.py @@ -1,7 +1,7 @@ Import("env") import subprocess -# Try to execute Git, if it failes we will just display the defaults below +# Try to execute Git, if it fails we will just display the defaults below gitAvailable = False gitCommitHash = "???" gitCommitTime = "???" @@ -22,7 +22,7 @@ ['git', 'rev-parse', '--abbrev-ref', 'HEAD'], stdout=subprocess.PIPE).communicate()[0].decode('utf-8').strip() env.Append(CPPDEFINES=[ - # This will be expanded into a command line argument like '-DGIT_COMMIT_HASH="\"str\""', and thats the reason for the "strange" backslashing... + # This will be expanded into a command line argument like '-DGIT_COMMIT_HASH="\"str\""', and that's the reason for the "strange" backslashing... ("GIT_COMMIT_HASH", "\\\"" + gitCommitHash + "\\\""), ("GIT_COMMIT_TIME", "\\\"" + gitCommitTime + "\\\""), ("GIT_BRANCH_NAME", "\\\"" + gitBranchName + "\\\""), diff --git a/scripts/update.sh b/scripts/update.sh deleted file mode 100755 index 0d4a444b0..000000000 --- a/scripts/update.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -echo "This script will help you to update all the submodules and the main repository to the latest master-version." -sleep 2 - -set -xe - -git fetch -git stash # stash any local changes -git switch master -git reset origin/master # using reset instead of pull to avoid merge commits -git checkout -- . -git submodule update --init --recursive -git stash pop # restore any local changes \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..483bc0cfc --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,6 @@ +# This file was automatically generated for projects +# without default 'CMakeLists.txt' file. + +FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*) + +idf_component_register(SRCS ${app_sources}) diff --git a/src/OswAppV2.cpp b/src/OswAppV2.cpp index 35f7173aa..096135cf8 100644 --- a/src/OswAppV2.cpp +++ b/src/OswAppV2.cpp @@ -5,7 +5,7 @@ #include #include "assets/img/icons/app.png.h" -OswIconProgmem OswAppV2::defaultAppIcon = app_png; // Copy, so color can be set upon retreival +OswIconProgmem OswAppV2::defaultAppIcon = app_png; // Copy, so color can be set upon retrieval OswAppV2::OswAppV2() { @@ -34,7 +34,7 @@ void OswAppV2::resetNeedsRedraw() { void OswAppV2::onStart() { #ifndef NDEBUG - // Can't run this during startup, as this method should be overriden by the app + // Can't run this during startup, as this method should be overridden by the app if(String(this->getAppId()).length() > 15) OSW_LOG_W("The app id ", this->getAppId(), " is longer than 15 characters. This may cause problems with some api calls (e.g. Preferences)."); #endif @@ -55,7 +55,7 @@ void OswAppV2::onLoop() { const unsigned short longPressTime = OswConfigAllKeys::oswAppV2ButtonLongPress.get(); const unsigned short veryLongPressTime = OswConfigAllKeys::oswAppV2ButtonVeryLongPress.get(); - const unsigned long indicatorMinTime = minPressTime + (longPressTime * 0.2); + const unsigned long indicatorMinTime = minPressTime + (longPressTime * 0.2f); for(char i = 0; i < BTN_NUMBER; i++) { if(hal->btnIsDownSince((Button) i) > 0) { if(buttonDownSince[i] == 0) { @@ -110,11 +110,11 @@ void OswAppV2::onLoop() { // Now update the indicator-levels for the buttons if(hal->btnIsDownFor((Button) i) > indicatorMinTime) { float progress = (hal->btnIsDownFor((Button) i) - indicatorMinTime) / (float) longPressTime; - if(progress > 1.0) { + if(progress > 1.0f) { // Oh! The button is down for a very long time! - progress = 1.0 + (hal->btnIsDownFor((Button) i) - indicatorMinTime - longPressTime) / (float) (veryLongPressTime - longPressTime); - if(progress > 2.0) - progress = 2.0; + progress = 1.0f + (hal->btnIsDownFor((Button) i) - indicatorMinTime - longPressTime) / (float) (veryLongPressTime - longPressTime); + if(progress > 2.0f) + progress = 2.0f; } if(this->buttonIndicatorProgress[i] != progress) { this->buttonIndicatorProgress[i] = progress; @@ -124,8 +124,8 @@ void OswAppV2::onLoop() { this->needsRedraw = true; } } - } else if(this->buttonIndicatorProgress[i] != 0.0) { - this->buttonIndicatorProgress[i] = 0.0; + } else if(this->buttonIndicatorProgress[i] != 0.0f) { + this->buttonIndicatorProgress[i] = 0.0f; this->needsRedraw = true; } } @@ -142,7 +142,7 @@ void OswAppV2::onDrawOverlay() { if(this->knownButtonStates[i] == 0) continue; // If the button is not down, skip it - if(this->buttonIndicatorProgress[i] == 0.0) + if(this->buttonIndicatorProgress[i] == 0.0f) continue; int16_t btnX = 0; @@ -160,11 +160,11 @@ void OswAppV2::onDrawOverlay() { const int16_t longRad = 24; const int16_t veryLongRad = 14; - if(this->knownButtonStates[i] & ButtonStateNames::VERY_LONG_PRESS and this->buttonIndicatorProgress[i] > 1.0) { + if(this->knownButtonStates[i] & ButtonStateNames::VERY_LONG_PRESS and this->buttonIndicatorProgress[i] > 1.0f) { // Very long-press circle - const float overcut = 0.2; - const float secondRad = (1.0 + overcut) * veryLongRad; - hal->gfx()->fillCircle(btnX, btnY, (1.0 - overcut) * longRad + (this->buttonIndicatorProgress[i] - 1.0) * secondRad, OswUI::getInstance()->getWarningColor()); + const float overcut = 0.2f; + const float secondRad = (1.0f + overcut) * veryLongRad; + hal->gfx()->fillCircle(btnX, btnY, (1.0f - overcut) * longRad + (this->buttonIndicatorProgress[i] - 1.0f) * secondRad, OswUI::getInstance()->getWarningColor()); } if(this->knownButtonStates[i] & ButtonStateNames::LONG_PRESS) { // Long-press circle @@ -185,4 +185,4 @@ void OswAppV2::onButton(Button id, bool up, OswAppV2::ButtonStateNames state) { void OswAppV2::onLoopDebug() { // By default no debug loop (GUI) is implemented } -#endif \ No newline at end of file +#endif diff --git a/src/OswImage.cpp b/src/OswImage.cpp index cfb19d6fc..e2f29a777 100644 --- a/src/OswImage.cpp +++ b/src/OswImage.cpp @@ -67,4 +67,4 @@ void OswImage::drawCallback(pngle_t* pngle, unsigned int x, unsigned int y, unsi // We pretty much ignore alpha - and just draw the pixel if it's not transparent if (a > 0) OswImage::cbGfx->drawPixel(OswImage::cbOffX + x * scale, OswImage::cbOffY + y * scale, rgb565(r, g, b)); -} \ No newline at end of file +} diff --git a/src/OswLogger.cpp b/src/OswLogger.cpp index 639f6b064..8b00e2c7a 100644 --- a/src/OswLogger.cpp +++ b/src/OswLogger.cpp @@ -1,3 +1,3 @@ #include -std::unique_ptr OswLogger::instance = nullptr; \ No newline at end of file +std::unique_ptr OswLogger::instance = nullptr; diff --git a/src/OswSerial.cpp b/src/OswSerial.cpp new file mode 100644 index 000000000..5ec8f4169 --- /dev/null +++ b/src/OswSerial.cpp @@ -0,0 +1,80 @@ +#include + +OswSerial* OswSerial::instance = nullptr; + +void OswSerial::begin(unsigned long baud) { +#if OSW_PLATFORM_HARDWARE_ESP32_USE_JTAG_SERIAL == 1 + // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG would do its magic - but is was not set in ESP-IDF during compile time, so... + // the function bootloader_console_init() would normally set this up, but the compiled one configures another UART + { + // the following line is just a forward to the rom-function + // ld will be instructed to just use a hard-coded addresses + // ...but the ESP-IDF version is too old and does not have this function yet + // esp_rom_output_switch_buffer(ESP_ROM_USB_SERIAL_DEVICE_NUM); + + // this replaces the above function, at least in ESP-IDF v4.3 + { + UartDevice* uart = GetUartDevice(); + uart->buff_uart_no = ESP_ROM_USB_SERIAL_DEVICE_NUM; + } + + // same as before, but not needed for older chips + // esp_rom_output_set_as_console(ESP_ROM_USB_SERIAL_DEVICE_NUM); + + // esp_rom_output_switch_buffer or uart_buff_switch // -> does NOT exist in my old ESP-IDF version + // -> use older variant, which directly accesses the rom-code + } +#else + Serial.begin(115200); +#endif +} + +void OswSerial::putc(uint8_t c) { +#if OSW_PLATFORM_HARDWARE_ESP32_USE_JTAG_SERIAL == 1 + esp_rom_uart_putc(c); +#else + Serial.print((char) c); +#endif +} + +void OswSerial::flush() { +#if OSW_PLATFORM_HARDWARE_ESP32_USE_JTAG_SERIAL == 1 + esp_rom_uart_flush_tx(ESP_ROM_USB_SERIAL_DEVICE_NUM); +#else + Serial.flush(); +#endif +} + +bool OswSerial::getc(uint8_t& c) { +#if OSW_PLATFORM_HARDWARE_ESP32_USE_JTAG_SERIAL == 1 + return esp_rom_uart_rx_one_char(&c) == 0; +#else + if(::Serial.available()) { + c = ::Serial.read(); + return true; + } else { + return false; + } +#endif +} + +void OswSerial::println() { +#if OSW_PLATFORM_HARDWARE_ESP32_USE_JTAG_SERIAL == 1 + this->putc('\n'); + this->flush(); +#else + Serial.println(); +#endif +} + +OswSerial* OswSerial::getInstance() { + if(OswSerial::instance == nullptr) { + OswSerial::instance = new OswSerial(); + } + return OswSerial::instance; +}; + +void OswSerial::resetInstance() { + delete OswSerial::instance; + OswSerial::instance = nullptr; +} diff --git a/src/animations/anim_doom_fire.cpp b/src/animations/anim_doom_fire.cpp index 245413e24..813f890ea 100644 --- a/src/animations/anim_doom_fire.cpp +++ b/src/animations/anim_doom_fire.cpp @@ -46,4 +46,4 @@ void AnimDoomFire::mapFire(uint8_t** firePixels, uint16_t fireW, uint16_t fireH, void AnimDoomFire::loop(Graphics2DPrint* gfx,float* X, float* Y) { calcFire(firePixels, 240, 240,X,Y); mapFire(firePixels, 240, 240, gfx, 0, 0); -} \ No newline at end of file +} diff --git a/src/animations/anim_firework.cpp b/src/animations/anim_firework.cpp index 19cde56c3..93d02d819 100644 --- a/src/animations/anim_firework.cpp +++ b/src/animations/anim_firework.cpp @@ -6,19 +6,19 @@ void Particle::tick(long ms, float friction, float gravity) { // update position - locationX += speedX * (ms / 1000.0); - locationY += speedY * (ms / 1000.0); + locationX += speedX * (ms / 1000.0f); + locationY += speedY * (ms / 1000.0f); // update velocity - speedX = speedX - friction * (ms / 1000.0); - speedY = speedY + gravity * (ms / 1000.0); + speedX = speedX - friction * (ms / 1000.0f); + speedY = speedY + gravity * (ms / 1000.0f); // printf("particle at %d/%d\n", locationX, locationY); } void Firework::init(uint16_t color_, uint8_t radius, uint8_t rings, // uint16_t screenWidth, uint16_t screenHeight) { height = 0; - explHeight = random((float)screenHeight * 0.2, (float)screenHeight * 0.8); + explHeight = random((float)screenHeight * 0.2f, (float)screenHeight * 0.8f); age = 0; color = color_; @@ -26,7 +26,7 @@ void Firework::init(uint16_t color_, uint8_t radius, uint8_t rings, // // precalculate particle starting points float pointsOnRing = ((float)numParticles / (float)rings); uint8_t ring = (i / pointsOnRing) + 1; - float angle = (360.0 / pointsOnRing) * i; + float angle = (360.0f / pointsOnRing) * i; particles[i].locationX = rpx(0, ring * radius, angle); particles[i].locationY = rpy(0, ring * radius, angle); @@ -39,10 +39,10 @@ void Firework::init(uint16_t color_, uint8_t radius, uint8_t rings, // void Firework::tick(long ms, uint8_t launchSpeed) { if (height < explHeight) { - height += launchSpeed * (ms / 100.0); + height += launchSpeed * (ms / 100.0f); } else { for (uint8_t i = 0; i < numParticles; i++) { - particles[i].tick(ms, .1, 9.8); + particles[i].tick(ms, 0.1f, 9.8f); } color = dimColor(color, age / 1000); @@ -58,4 +58,4 @@ void Firework::draw(Graphics2D* gfx, int16_t offsetX, int16_t offsetY) { gfx->drawPixel(offsetX + (int)particles[i].locationX, offsetY - height + (int)particles[i].locationY, color); } } -} \ No newline at end of file +} diff --git a/src/animations/demos/README.md b/src/animations/demos/README.md index bad304507..bd1aa76a1 100644 --- a/src/animations/demos/README.md +++ b/src/animations/demos/README.md @@ -1,4 +1,4 @@ This folder holds now inactive (by changed extensions) and broken code to demonstrate these animations. -These snippets were kept, as not every animation is just simply useable (...). +These snippets were kept, as not every animation is just simply usable (...). -Feel free to explore them and maybe even polish them up, so they work with the emulator again... \ No newline at end of file +Feel free to explore them and maybe even polish them up, so they work with the emulator again... diff --git a/src/animations/demos/mix-face.cpp.inactive b/src/animations/demos/mix-face.cpp.inactive index ed2e832e4..2d903f265 100644 --- a/src/animations/demos/mix-face.cpp.inactive +++ b/src/animations/demos/mix-face.cpp.inactive @@ -112,11 +112,11 @@ class MixFace : public SDLWindowRGB565 { gfx2d_print.setTextLeftAligned(); gfx2d_print.setTextCursor(120 + alp, 90); - gfx2d_print.printDecimal((int)(x*0.2)%31+1, 2); + gfx2d_print.printDecimal((int)(x*0.2f)%31+1, 2); gfx2d_print.print("."); - gfx2d_print.printDecimal((int)(x*0.6)% 12+1, 2); + gfx2d_print.printDecimal((int)(x*0.6f)% 12+1, 2); gfx2d_print.print("."); - gfx2d_print.printDecimal((int)(x*0.9)%100,2); // Full year-name is overflowing + gfx2d_print.printDecimal((int)(x*0.9f)%100,2); // Full year-name is overflowing ////time gfx2d_print.setTextSize(3); @@ -124,9 +124,9 @@ class MixFace : public SDLWindowRGB565 { gfx2d_print.setTextLeftAligned(); gfx2d_print.setTextCursor(120 + alp, 120); - gfx2d_print.printDecimal((int)(x * 0.4) % 12, 2); + gfx2d_print.printDecimal((int)(x * 0.4f) % 12, 2); gfx2d_print.print(":"); - gfx2d_print.printDecimal((int)(x * 0.8) % 60, 2); + gfx2d_print.printDecimal((int)(x * 0.8f) % 60, 2); gfx2d_print.setTextSize(1); gfx2d_print.setTextMiddleAligned(); @@ -146,9 +146,9 @@ class MixFace : public SDLWindowRGB565 { boxHeight = boxHeight < 2 ? 0 : boxHeight; // step bars - gfx2d_print.fillFrame(((240 / 2) - 8 * 3.5) + i * 8, 180 + (32 - boxHeight), 8, boxHeight, rgb888to565(rgb888(32, 156, 238))); + gfx2d_print.fillFrame(((240 / 2) - 8 * 3.5f) + i * 8, 180 + (32 - boxHeight), 8, boxHeight, rgb888to565(rgb888(32, 156, 238))); - gfx2d_print.drawRFrame(((240 / 2) - 8 * 3.5) + i * 8, 180, 8, 32, 2, rgb888to565(rgb888(122, 122, 122))); + gfx2d_print.drawRFrame(((240 / 2) - 8 * 3.5f) + i * 8, 180, 8, 32, 2, rgb888to565(rgb888(122, 122, 122))); } // labels @@ -156,7 +156,7 @@ class MixFace : public SDLWindowRGB565 { gfx2d_print.setTextBottomAligned(); gfx2d_print.setTextSize(1); gfx2d_print.setTextCursor(240 / 2, 180 - 1); - gfx2d_print.print((int)(x * 0.04)); // today step counter + gfx2d_print.print((int)(x * 0.04f)); // today step counter gfx2d_print.setTextCursor(240 / 2, 180 + 1 + 8 + 8 * 4); gfx2d_print.print(x); // total step counter } diff --git a/src/animations/demos/perlin/SimplexNoise.cpp.inactive b/src/animations/demos/perlin/SimplexNoise.cpp.inactive index 9a6df68ca..b08236d21 100644 --- a/src/animations/demos/perlin/SimplexNoise.cpp.inactive +++ b/src/animations/demos/perlin/SimplexNoise.cpp.inactive @@ -472,4 +472,4 @@ float SimplexNoise::fractal(size_t octaves, float x, float y, float z) const { } return (output / denom); -} \ No newline at end of file +} diff --git a/src/animations/demos/perlin/SimplexNoise.h.inactive b/src/animations/demos/perlin/SimplexNoise.h.inactive index de6394a1c..4cecaedc2 100644 --- a/src/animations/demos/perlin/SimplexNoise.h.inactive +++ b/src/animations/demos/perlin/SimplexNoise.h.inactive @@ -52,4 +52,4 @@ private: float mAmplitude; ///< Amplitude ("height") of the first octave of noise (default to 1.0) float mLacunarity; ///< Lacunarity specifies the frequency multiplier between successive octaves (default to 2.0). float mPersistence; ///< Persistence is the loss of amplitude between successive octaves (usually 1/lacunarity) -}; \ No newline at end of file +}; diff --git a/src/animations/demos/perlin/SimplexNosie.License.txt b/src/animations/demos/perlin/SimplexNosie.License.txt index f69ae4096..0d4956728 100644 --- a/src/animations/demos/perlin/SimplexNosie.License.txt +++ b/src/animations/demos/perlin/SimplexNosie.License.txt @@ -17,4 +17,4 @@ 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 +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/animations/demos/rotation/main.cpp.inactive b/src/animations/demos/rotation/main.cpp.inactive index 3e94c9c72..cc76ac979 100644 --- a/src/animations/demos/rotation/main.cpp.inactive +++ b/src/animations/demos/rotation/main.cpp.inactive @@ -94,7 +94,7 @@ class RotationExampleWindow : public SDLWindowRGB565 { waterBackground.drawGraphics2D_rotated(lx2, ly2, &leaf1, 16, 16, -counter / 50.0); waterBackground.drawGraphics2D_rotated(lx3, ly3, &leaf2, 16, 16, counter / 50.0); waterBackground.drawGraphics2D_rotated(lx4, ly4, &leaf3, 16, 16, -counter / 50.0); - // gfx2d.disableAplha(); + // gfx2d.disableAlpha(); calcWater(wbuf1, wbuf2, WATER_W, WATER_H, .9); mapWater(wbuf1, WATER_W, WATER_H, &waterBackground, &waterScreenBuffer, 0, 0); diff --git a/src/apps/OswAppDrawer.cpp b/src/apps/OswAppDrawer.cpp index 49aa25590..fa007a87a 100644 --- a/src/apps/OswAppDrawer.cpp +++ b/src/apps/OswAppDrawer.cpp @@ -227,6 +227,21 @@ void OswAppDrawer::onButton(Button id, bool up, ButtonStateNames state) { } #ifdef OSW_EMULATOR +/** + * @brief allow re-use of the drawer instance in the emulator + * + */ +void OswAppDrawer::reset() { + for (auto& category : this->apps) { + for (auto& app : category.second) { + app.cleanup(); + } + } + this->apps.clear(); + this->current = nullptr; + this->highlightApp = nullptr; +} + void OswAppDrawer::onLoopDebug() { if(this->current) this->current->get()->onLoopDebug(); // forward to the current app @@ -256,7 +271,7 @@ void OswAppDrawer::resetNeedsRedraw() { } /** - * @brief This destorys all cached app instances, leaving only the current app running. + * @brief This destroys all cached app instances, leaving only the current app running. * */ void OswAppDrawer::cleanup() { @@ -317,4 +332,4 @@ void OswAppDrawer::open(LazyInit& app) { } assert(found && "Could not find the current app in the app drawer?!"); // this should never happen } -} \ No newline at end of file +} diff --git a/src/apps/OswAppV2Compat.cpp b/src/apps/OswAppV2Compat.cpp index 7b614ff92..04cf920b4 100644 --- a/src/apps/OswAppV2Compat.cpp +++ b/src/apps/OswAppV2Compat.cpp @@ -44,4 +44,4 @@ void OswAppV2Compat::onStop() { void OswAppV2Compat::onLoopDebug() { this->app.loopDebug(); } -#endif \ No newline at end of file +#endif diff --git a/src/apps/_experiments/OswAppWeather.cpp b/src/apps/_experiments/OswAppWeather.cpp index 639a30344..f5123d1dd 100644 --- a/src/apps/_experiments/OswAppWeather.cpp +++ b/src/apps/_experiments/OswAppWeather.cpp @@ -78,9 +78,9 @@ int OswAppWeather::WeatherDecoder::_str2hum(const String& humidity) { } int OswAppWeather::WeatherDecoder::_str2pres(const String& pressure) { - int pres = pressure.toInt(); - pres = pres + 850; - return pres; + int press = pressure.toInt(); + press = press + 850; + return press; } int OswAppWeather::WeatherDecoder::_str2wthr(const String& weather) { diff --git a/src/apps/_experiments/OswAppWeatherIconPrinter.cpp b/src/apps/_experiments/OswAppWeatherIconPrinter.cpp index 12584ea61..b4d5d3fe8 100644 --- a/src/apps/_experiments/OswAppWeatherIconPrinter.cpp +++ b/src/apps/_experiments/OswAppWeatherIconPrinter.cpp @@ -175,4 +175,4 @@ void OswAppWeatherIconPrinter::drawIcon(int code, int x, int y, float k) { break; } } -#endif \ No newline at end of file +#endif diff --git a/src/apps/_experiments/autumn.cpp b/src/apps/_experiments/autumn.cpp index 4d5d6f305..97cbedddf 100644 --- a/src/apps/_experiments/autumn.cpp +++ b/src/apps/_experiments/autumn.cpp @@ -122,7 +122,7 @@ void OswAppAutumn::loop() { waterBackground->drawGraphics2D_rotated(lx2, ly2, leaf1, 16, 16, -counter / 50.0); waterBackground->drawGraphics2D_rotated(lx3, ly3, leaf2, 16, 16, counter / 50.0); waterBackground->drawGraphics2D_rotated(lx4, ly4, leaf3, 16, 16, -counter / 50.0); - // gfx2d.disableAplha(); + // gfx2d.disableAlpha(); calcWater(wbuf1, wbuf2, WATER_W, WATER_H, .9); mapWater(wbuf1, WATER_W, WATER_H, waterBackground, waterScreenBuffer, 0, 0); diff --git a/src/apps/_experiments/dnatilt.cpp b/src/apps/_experiments/dnatilt.cpp index 0934dc6d1..585b141c0 100644 --- a/src/apps/_experiments/dnatilt.cpp +++ b/src/apps/_experiments/dnatilt.cpp @@ -1,4 +1,5 @@ #ifdef OSW_FEATURE_WIFI +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 #include "./apps/_experiments/dnatilt.h" #include @@ -42,7 +43,7 @@ void OswAppDNATilt::loop() { /* THIS IS NOW MANAGED BY THE WIFI SERVICE. - The get() method is still a NON-STATIC method of MiniWiFi and therfore currently unusable. + The get() method is still a NON-STATIC method of MiniWiFi and therefore currently unusable. Then you need this code working, please contact the author of the MiniWiFi lib or extend it yourself. if (hal->getAccelerationX() > 250) { @@ -52,4 +53,5 @@ void OswAppDNATilt::loop() { } */ } -#endif \ No newline at end of file +#endif +#endif diff --git a/src/apps/_experiments/gif_player.cpp b/src/apps/_experiments/gif_player.cpp index 87c3df6a2..cbb222ec1 100644 --- a/src/apps/_experiments/gif_player.cpp +++ b/src/apps/_experiments/gif_player.cpp @@ -87,7 +87,7 @@ void OswAppGifPlayer::setup() { gfx = OswHal::getInstance()->gfx(); // update static gfx handle for the GIFDraw callback gif.begin(LITTLE_ENDIAN_PIXELS); if (gif.open((uint8_t*)GIF_NAME, sizeof(GIF_NAME), GIFDraw)) { - Serial.printf("Successfully opened GIF; Canvas size = %d x %d\n", gif.getCanvasWidth(), gif.getCanvasHeight()); + OSW_LOG_D("Successfully opened GIF; Canvas size = ", gif.getCanvasWidth(), " x ", gif.getCanvasHeight()); gifOpen = true; } OswHal::getInstance()->gfx()->fill(rgb565(0, 0, 0)); @@ -127,4 +127,4 @@ void OswAppGifPlayer::stop() { } -#endif \ No newline at end of file +#endif diff --git a/src/apps/_experiments/magnetometer_calibrate.cpp b/src/apps/_experiments/magnetometer_calibrate.cpp index 8c1b623b6..123d460d1 100644 --- a/src/apps/_experiments/magnetometer_calibrate.cpp +++ b/src/apps/_experiments/magnetometer_calibrate.cpp @@ -111,4 +111,4 @@ void OswAppMagnetometerCalibrate::loop() { void OswAppMagnetometerCalibrate::stop() { } -#endif \ No newline at end of file +#endif diff --git a/src/apps/_experiments/show_display_size.cpp b/src/apps/_experiments/show_display_size.cpp index 3e81c7932..79162bbc5 100644 --- a/src/apps/_experiments/show_display_size.cpp +++ b/src/apps/_experiments/show_display_size.cpp @@ -23,8 +23,8 @@ void OswAppShowDisplaySize::loop() { uint16_t height = gfx->getHeight(); for (uint16_t y = 0; y < height; y += chunkHeight) { - float y1 = (y + (y < height / 2 ? chunkHeight : 0)) - height / 2.0; - float d = sqrt(120 * 120 - y1 * y1); + float y1 = (y + (y < height / 2 ? chunkHeight : 0)) - height / 2.0f; + float d = sqrtf(120 * 120 - y1 * y1); uint16_t xOffset = 120 - d; uint16_t chunkWidth = ceil(d * 2); gfx->fillFrame(xOffset, y, chunkWidth, chunkHeight, rgb565(0, 0, 0)); diff --git a/src/apps/clock/OswAppAlarm.cpp b/src/apps/clock/OswAppAlarm.cpp index 0a8b00a5c..5271655ba 100644 --- a/src/apps/clock/OswAppAlarm.cpp +++ b/src/apps/clock/OswAppAlarm.cpp @@ -200,7 +200,7 @@ void OswAppAlarm::listAlarms() { hal->gfx()->setTextLeftAligned(); for (size_t i{}; i < notifications.size(); ++i) { hal->gfx()->setTextSize(2); - hal->gfx()->setTextCursor(hal->gfx()->getTextOfsetColumns(1.5), DISP_H * (i + 3) / 8); + hal->gfx()->setTextCursor(hal->gfx()->getTextOfsetColumns(1.5f), DISP_H * (i + 3) / 8); hal->gfx()->setTextColor(state == AlarmState::LIST && step == i ? colorActive : colorForeground, colorBackground); auto timeToFire = notifications[i].first; date::hh_mm_ss time{floor(timeToFire - floor(timeToFire))}; @@ -212,7 +212,7 @@ void OswAppAlarm::listAlarms() { hal->gfx()->print(minutes / 10); hal->gfx()->print(minutes % 10); hal->gfx()->setTextSize(1); - hal->gfx()->setTextCursor(DISP_W / 3 + hal->gfx()->getTextOfsetColumns(1.5), DISP_H * (i + 3) / 8); + hal->gfx()->setTextCursor(DISP_W / 3 + hal->gfx()->getTextOfsetColumns(1.5f), DISP_H * (i + 3) / 8); auto myDaysOfWeek = notifications[i].second.getDaysOfWeek(); if (std::all_of(myDaysOfWeek.begin(), myDaysOfWeek.end(), [](bool x) { return x; @@ -331,12 +331,12 @@ void OswAppAlarm::loop() { hal->gfx()->print("+"); hal->gfx()->setTextRightAligned(); - hal->gfx()->setTextCursor((DISP_W / 2) - hal->gfx()->getTextOfsetColumns(0.5), DISP_H * 5 / 8); + hal->gfx()->setTextCursor((DISP_W / 2) - hal->gfx()->getTextOfsetColumns(0.5f), DISP_H * 5 / 8); hal->gfx()->setTextColor(step == 4 ? colorActive : colorForeground, colorBackground); hal->gfx()->print(LANG_CANCEL); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor((DISP_W / 2) + hal->gfx()->getTextOfsetColumns(0.5), DISP_H * 5 / 8); + hal->gfx()->setTextCursor((DISP_W / 2) + hal->gfx()->getTextOfsetColumns(0.5f), DISP_H * 5 / 8); hal->gfx()->setTextColor(step == 5 ? colorActive : colorForeground, colorBackground); hal->gfx()->print(LANG_NEXT); @@ -400,12 +400,12 @@ void OswAppAlarm::loop() { } hal->gfx()->setTextRightAligned(); - hal->gfx()->setTextCursor((DISP_W / 2) - hal->gfx()->getTextOfsetColumns(0.5), DISP_H * 10 / 12); + hal->gfx()->setTextCursor((DISP_W / 2) - hal->gfx()->getTextOfsetColumns(0.5f), DISP_H * 10 / 12); hal->gfx()->setTextColor(step == 7 ? colorActive : colorForeground, colorBackground); hal->gfx()->print(LANG_CANCEL); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor((DISP_W / 2) + hal->gfx()->getTextOfsetColumns(0.5), DISP_H * 10 / 12); + hal->gfx()->setTextCursor((DISP_W / 2) + hal->gfx()->getTextOfsetColumns(0.5f), DISP_H * 10 / 12); hal->gfx()->setTextColor(step == 8 ? colorActive : colorForeground, colorBackground); hal->gfx()->print(LANG_SAVE); } diff --git a/src/apps/clock/OswAppTimer.cpp b/src/apps/clock/OswAppTimer.cpp index 139f2c047..670a19ad7 100644 --- a/src/apps/clock/OswAppTimer.cpp +++ b/src/apps/clock/OswAppTimer.cpp @@ -166,12 +166,12 @@ void drawSetTimerScreen(unsigned char step, uint16_t colorActive, uint16_t color hal->gfx()->setTextSize(2); hal->gfx()->setTextRightAligned(); - hal->gfx()->setTextCursor((DISP_W / 2) - hal->gfx()->getTextOfsetColumns(0.5), DISP_H * 5 / 8); + hal->gfx()->setTextCursor((DISP_W / 2) - hal->gfx()->getTextOfsetColumns(0.5f), DISP_H * 5 / 8); hal->gfx()->setTextColor(step == 6 ? colorActive : colorForeground, colorBackground); hal->gfx()->print(LANG_CANCEL); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor((DISP_W / 2) + hal->gfx()->getTextOfsetColumns(0.5), DISP_H * 5 / 8); + hal->gfx()->setTextCursor((DISP_W / 2) + hal->gfx()->getTextOfsetColumns(0.5f), DISP_H * 5 / 8); hal->gfx()->setTextColor(step == 7 ? colorActive : colorForeground, colorBackground); hal->gfx()->print(LANG_START); } @@ -321,4 +321,4 @@ void OswAppTimer::loop() { drawPausedTimerScreen(btnDown); break; } -} \ No newline at end of file +} diff --git a/src/apps/clock/stopwatch.cpp b/src/apps/clock/stopwatch.cpp index ee2804d38..31bd69644 100644 --- a/src/apps/clock/stopwatch.cpp +++ b/src/apps/clock/stopwatch.cpp @@ -237,8 +237,8 @@ void OswAppStopWatch::drawPageIndicator() { uint16_t alpha0 = 147 + (spacing / 2 * (lapPages-1)); // Angle of the first Element (147deg = Button 1) for(uint8_t i = 0; i < lapPages ; i++) { uint16_t alpha = alpha0 - (i * spacing); - uint16_t x = (DISP_W / 2) + (cos(alpha * PI / 180) * r); - uint16_t y = (DISP_H / 2) + (sin(alpha * PI / 180) * r); + uint16_t x = (DISP_W / 2) + (cosf(alpha * PI / 180) * r); + uint16_t y = (DISP_H / 2) + (sinf(alpha * PI / 180) * r); if(i == lapPage) { OswHal::getInstance()->gfx()->fillCircle(x, y, rDot, ui->getPrimaryColor()); } else { @@ -246,4 +246,4 @@ void OswAppStopWatch::drawPageIndicator() { } } } -} \ No newline at end of file +} diff --git a/src/apps/examples/README.md b/src/apps/examples/README.md index 965ef4d39..f641af26d 100644 --- a/src/apps/examples/README.md +++ b/src/apps/examples/README.md @@ -12,4 +12,4 @@ While this interface is more complex than the v1 interface, it is still very eas The example apps (v1/v2) are also a small showcase of what you can do with this OS, but they are maybe not the smallest possible examples (I mean, why do these apps use images?!)... 😎 If you want to fiddle around with them - either on the real hardware or in the emulator - you should define the feature flag for them inside the `platformio.ini` file, so that they are compiled and linked into the firmware. -Happy Hacking! \ No newline at end of file +Happy Hacking! diff --git a/src/apps/games/brick_breaker.cpp b/src/apps/games/brick_breaker.cpp index 01853dd80..4494ace5b 100644 --- a/src/apps/games/brick_breaker.cpp +++ b/src/apps/games/brick_breaker.cpp @@ -1,3 +1,5 @@ +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 #include "./apps/games/brick_breaker.h" @@ -38,7 +40,7 @@ void OswAppBrickBreaker::drawGrid() { void OswAppBrickBreaker::drawBall() { OswHal::getInstance()->gfx()->fillCircle(ballPosx, ballPosy, 4, ui->getForegroundColor()); - // hal->gfx()->drawArc(120,120, 0, 360, 60, 80, 0.75,ui->getForegroundColor(),false); + // hal->gfx()->drawArc(120,120, 0, 360, 60, 80, 0.75f,ui->getForegroundColor(),false); // hal->gfx()->drawFrame(18,18,203,250,ui->getForegroundColor()); } @@ -90,7 +92,7 @@ void OswAppBrickBreaker::BrickBreaker() { const int currentTime = millis(); - deltaSeconds += (currentTime - previousTime) / (1000.0); + deltaSeconds += (currentTime - previousTime) / 1000.0f; previousTime = currentTime; @@ -151,28 +153,28 @@ void OswAppBrickBreaker::initGrid() { void OswAppBrickBreaker::hitPlayer() { pHitPosition = ballPosx - playerPos; - absspd = sqrt((ballSpdx * ballSpdx) + (ballSpdy * ballSpdy)); - pHitAngle = atan(-ballSpdy / ballSpdx); - posAngle = asin(pHitPosition / 24); + absspd = sqrtf((ballSpdx * ballSpdx) + (ballSpdy * ballSpdy)); + pHitAngle = atanf(-ballSpdy / ballSpdx); + posAngle = asinf(pHitPosition / 24); angleVar = pHitAngle + posAngle; angleVar = (PI + angleVar * 2); angleout = pHitAngle - angleVar; angleout2 = PI + angleout; if (pHitPosition >= 0) { if (ballSpdx >= 0) { - ballSpdx = cos(angleout2) * absspd; - ballSpdy = -sin(angleout2) * absspd; + ballSpdx = cosf(angleout2) * absspd; + ballSpdy = -sinf(angleout2) * absspd; } else { - ballSpdx = -cos(angleout2) * absspd; - ballSpdy = sin(angleout2) * absspd; + ballSpdx = -cosf(angleout2) * absspd; + ballSpdy = sinf(angleout2) * absspd; } } else { if (ballSpdx >= 0) { - ballSpdx = cos(angleout2) * absspd; - ballSpdy = -sin(angleout2) * absspd; + ballSpdx = cosf(angleout2) * absspd; + ballSpdy = -sinf(angleout2) * absspd; } else { - ballSpdx = -cos(angleout2) * absspd; - ballSpdy = sin(angleout2) * absspd; + ballSpdx = -cosf(angleout2) * absspd; + ballSpdy = sinf(angleout2) * absspd; } } } @@ -180,10 +182,10 @@ void OswAppBrickBreaker::hitPlayer() { void OswAppBrickBreaker::hitWall() { wallPosx = ballPosx - 120; wallPosy = -(ballPosy - 120); - absspd = sqrt((ballSpdx * ballSpdx) + (ballSpdy * ballSpdy)); + absspd = sqrtf((ballSpdx * ballSpdx) + (ballSpdy * ballSpdy)); - pHitAngle = atan(-ballSpdy / ballSpdx); - posAngle = asin(wallPosy / 116); + pHitAngle = atanf(-ballSpdy / ballSpdx); + posAngle = asinf(wallPosy / 116); angleVar = pHitAngle + posAngle; if (wallPosx <= 0) { @@ -198,64 +200,64 @@ void OswAppBrickBreaker::hitWall() { // quadrant 2 (top left) / if (ballSpdx >= 0 && ballSpdy <= 0) { // quadrant 2 x+ y- / - ballSpdx = -cos(angleout) * absspd; - ballSpdy = sin(angleout) * absspd; + ballSpdx = -cosf(angleout) * absspd; + ballSpdy = sinf(angleout) * absspd; } else if (ballSpdx <= 0 && ballSpdy <= 0) { // quadrant 2 x- y- / - ballSpdx = cos(angleout) * absspd; - ballSpdy = -sin(angleout) * absspd; + ballSpdx = cosf(angleout) * absspd; + ballSpdy = -sinf(angleout) * absspd; } else { // quadrant 2 x- y+ / - ballSpdx = -cos(angleout) * absspd; - ballSpdy = -sin(angleout) * absspd; + ballSpdx = -cosf(angleout) * absspd; + ballSpdy = -sinf(angleout) * absspd; } } else if (wallPosx <= 0 && wallPosy <= 0) { // quadrant 3 (bottom left) / if (ballSpdx <= 0 && ballSpdy >= 0) { // quadrant 3 x- y+ / - ballSpdx = cos(angleout) * absspd; - ballSpdy = -sin(angleout) * absspd; + ballSpdx = cosf(angleout) * absspd; + ballSpdy = -sinf(angleout) * absspd; } else if (ballSpdx >= 0 && ballSpdy >= 0) { // quadrant 3 x+ y+ / - ballSpdx = -cos(angleout) * absspd; - ballSpdy = sin(angleout) * absspd; + ballSpdx = -cosf(angleout) * absspd; + ballSpdy = sinf(angleout) * absspd; } else if (ballSpdx <= 0 && ballSpdy <= 0) { // quadrant 3 x- y- / - ballSpdx = -sin(angleout) * absspd; - ballSpdy = cos(angleout) * absspd; + ballSpdx = -sinf(angleout) * absspd; + ballSpdy = cosf(angleout) * absspd; } } else if (wallPosx >= 0 && wallPosy >= 0) { // quadrant 1 (top right) / if (ballSpdx >= 0 && ballSpdy <= 0) { // quadrant 1 x+ y- / - ballSpdx = -cos(angleout) * absspd; - ballSpdy = -sin(angleout) * absspd; + ballSpdx = -cosf(angleout) * absspd; + ballSpdy = -sinf(angleout) * absspd; } else if (ballSpdx >= 0 && ballSpdy >= 0) { ////quadrant 1 x+ y+ - ballSpdx = -cos(angleout) * absspd; - ballSpdy = sin(angleout) * absspd; + ballSpdx = -cosf(angleout) * absspd; + ballSpdy = sinf(angleout) * absspd; } else if (ballSpdx <= 0 && ballSpdy <= 0) { // quadrant 1 x- y- / angleVar = pHitAngle - posAngle; angleVar = (angleVar * 2); angleout = (pHitAngle - angleVar); - ballSpdx = cos(angleout) * absspd; - ballSpdy = -sin(angleout) * absspd; + ballSpdx = cosf(angleout) * absspd; + ballSpdy = -sinf(angleout) * absspd; } } else { // quadrant 4 (bottom right) / if (ballSpdx <= 0 && ballSpdy >= 0) { // quadrant 4 x- y+ / - ballSpdx = cos(angleout) * absspd; - ballSpdy = -sin(angleout) * absspd; + ballSpdx = cosf(angleout) * absspd; + ballSpdy = -sinf(angleout) * absspd; } else if (ballSpdx >= 0 && ballSpdy <= 0) { // quadrant 4 x+ y- / - ballSpdx = -cos(angleout) * absspd; - ballSpdy = sin(angleout) * absspd; + ballSpdx = -cosf(angleout) * absspd; + ballSpdy = sinf(angleout) * absspd; } else if (ballSpdx >= 0 && ballSpdy >= 0) { // quadrant 4 x+ y+ / - ballSpdx = -cos(angleout) * absspd; - ballSpdy = sin(angleout) * absspd; + ballSpdx = -cosf(angleout) * absspd; + ballSpdy = sinf(angleout) * absspd; } } } @@ -306,7 +308,7 @@ void OswAppBrickBreaker::accelerometerController() { void OswAppBrickBreaker::gravityController() { float xAcceleration = OswHal::getInstance()->environment()->getAccelerationX(); - float realAcceleration = -xAcceleration * 59.3346774; + float realAcceleration = -xAcceleration * 59.3346774f; playerSpd = playerSpd + (realAcceleration * (millis() - lastpos)); playerPos = playerPos + (playerSpd * (millis() - lastpos)); if (playerPos <= 30) { @@ -385,3 +387,4 @@ void OswAppBrickBreaker::moveBall() { //} } } +#endif \ No newline at end of file diff --git a/src/apps/games/snake_game.cpp b/src/apps/games/snake_game.cpp index 12f3bb648..13706d581 100644 --- a/src/apps/games/snake_game.cpp +++ b/src/apps/games/snake_game.cpp @@ -1,3 +1,5 @@ +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 #include "./apps/games/snake_game.h" // #define GIF_BG @@ -197,7 +199,7 @@ void OswAppSnakeGame::snakeGame() { const int currentTime = millis(); - deltaSeconds += (currentTime - previousTime) / (1000.0); + deltaSeconds += (currentTime - previousTime) / 1000.0f; proceedSnakeCoords(fastGame); @@ -416,3 +418,4 @@ bool OswAppSnakeGame::touchItself() { } return false; } +#endif \ No newline at end of file diff --git a/src/apps/main/luaapp.cpp b/src/apps/main/luaapp.cpp index 31a0c3f51..21d9dfc57 100644 --- a/src/apps/main/luaapp.cpp +++ b/src/apps/main/luaapp.cpp @@ -62,4 +62,4 @@ void OswLuaApp::cleanupState() { void OswLuaApp::printLuaError() { OSW_LOG_E(lua_tostring(luaState, -1)); } -#endif \ No newline at end of file +#endif diff --git a/src/apps/main/map.cpp b/src/apps/main/map.cpp index aaca7138a..8c8f9d95e 100644 --- a/src/apps/main/map.cpp +++ b/src/apps/main/map.cpp @@ -223,4 +223,4 @@ void OswAppMap::stop() { #endif -#endif \ No newline at end of file +#endif diff --git a/src/apps/tools/OswAppBLEMediaCtrl.cpp b/src/apps/tools/OswAppBLEMediaCtrl.cpp index c0ef95174..6f0271e7b 100644 --- a/src/apps/tools/OswAppBLEMediaCtrl.cpp +++ b/src/apps/tools/OswAppBLEMediaCtrl.cpp @@ -2,12 +2,16 @@ #ifdef OSW_FEATURE_BLE_MEDIA_CTRL #include "./apps/tools/OswAppBLEMediaCtrl.h" -#include #include #include #include #include +// workaround for compile issues via https://github.com/espressif/arduino-esp32/issues/6388 +#define BLE_42_FEATURE_SUPPORT TRUE +#define BLE_50_FEATURE_SUPPORT TRUE +#include + BleKeyboard* bleKeyboard; void OswAppBLEMediaCtrl::setup() { @@ -65,4 +69,4 @@ void OswAppBLEMediaCtrl::stop() { OswHal::getInstance()->enableDisplayBuffer(); } #endif -#endif \ No newline at end of file +#endif diff --git a/src/apps/tools/OswAppCalculator.cpp b/src/apps/tools/OswAppCalculator.cpp index d02d85a87..cc9e190d2 100644 --- a/src/apps/tools/OswAppCalculator.cpp +++ b/src/apps/tools/OswAppCalculator.cpp @@ -1,6 +1,6 @@ /* a calculator for addition, subtraction, multiplication, division, square roots, powers, num1 * 10 ^ num2 - with postitive and negativ numbers + generating random numbers + with positive and negative numbers + generating random numbers press btn2 + btn3 to move the cursor a position back */ @@ -33,7 +33,7 @@ void OswAppCalculator::loop() { position--; } - //calls the functions and controlls the cursor (position) + //calls the functions and controls the cursor (position) if(iNum == 0) { //sets sign of num1 signOfNum1 = setSign(position, iNum, signOfNum1, signOfNum2); position = (position > 1) ? 0 : position; @@ -47,7 +47,7 @@ void OswAppCalculator::loop() { position = (position < 0) ? 7 : position; position = (position > 8) ? 0 : position; } else if(iNum == 8) { //sets sign of num2 - iNum = ((mathOperation == "square root") || (mathOperation == "random")) ? 15 : 8; //skips to the end because no further input is requierd + iNum = ((mathOperation == "square root") || (mathOperation == "random")) ? 15 : 8; //skips to the end because no further input is required signOfNum2 = setSign(position, iNum, signOfNum1, signOfNum2); position = (position > 1) ? 0 : position; position = (position < 0) ? 1 : position; @@ -181,11 +181,11 @@ String OswAppCalculator::calculate(int iNum, char signOfNum1, String mathOperati } else if (mathOperation == "/") { result = Num1 / Num2; } else if (mathOperation == "square root") { - result = sqrt(Num1); + result = sqrtf(Num1); } else if (mathOperation == "^") { - result = pow(Num1, Num2); + result = powf(Num1, Num2); } else if (mathOperation == "x10^") { - result = pow(10, Num2) * Num1; + result = powf(10, Num2) * Num1; } else if (mathOperation == "random") { result = random(-100000, 100001); result = result / 100; @@ -366,4 +366,4 @@ void OswAppCalculator::draw(int iNum, char signOfNum1, String mathOperation, cha hal->gfx()->print(">"); } -void OswAppCalculator::stop() {} \ No newline at end of file +void OswAppCalculator::stop() {} diff --git a/src/apps/tools/OswAppDistStats.cpp b/src/apps/tools/OswAppDistStats.cpp index 88d4cea7e..fede1dd1b 100644 --- a/src/apps/tools/OswAppDistStats.cpp +++ b/src/apps/tools/OswAppDistStats.cpp @@ -15,10 +15,6 @@ void OswAppDistStats::drawChart() { uint8_t interval = 20; uint16_t goalValue = OswConfigAllKeys::distPerDay.get(); - uint32_t weekDay = 0; - uint32_t dayOfMonth = 0; - hal->getLocalDate(&dayOfMonth, &weekDay); - for (uint8_t index = 0; index < 7; index++) { uint32_t weekDayDist = OswAppWatchfaceFitness::calculateDistance(hal->environment()->getStepsOnDay(index)); uint16_t chartStickValue = ((float)(weekDayDist > goalValue ? goalValue : weekDayDist) / goalValue) * chartStickHeight; @@ -46,15 +42,14 @@ void OswAppDistStats::showStickChart() { hal->gfx()->print(LANG_DISTSTATS_TITLE); OswAppDistStats::drawChart(); - OswAppStepStats::drawInfoPanel(ui, (uint32_t)cursorPos, OswAppWatchfaceFitness::calculateDistance(hal->environment()->getStepsOnDay((uint32_t)cursorPos, true)), OswAppWatchfaceFitness::calculateDistance(hal->environment()->getStepsOnDay((uint32_t)cursorPos)), OswAppWatchfaceFitness::calculateDistance(hal->environment()->getStepsAverage()), OswAppWatchfaceFitness::calculateDistance(hal->environment()->getStepsTotalWeek()), " m"); + OswAppStepStats::drawInfoPanel(ui, cursorPos, OswAppWatchfaceFitness::calculateDistance(hal->environment()->getStepsOnDay((uint32_t)cursorPos, true)), OswAppWatchfaceFitness::calculateDistance(hal->environment()->getStepsOnDay((uint32_t)cursorPos)), OswAppWatchfaceFitness::calculateDistance(hal->environment()->getStepsAverage()), OswAppWatchfaceFitness::calculateDistance(hal->environment()->getStepsTotalWeek()), " m"); } void OswAppDistStats::setup() { OswHal* hal = OswHal::getInstance(); - uint32_t weekDay = 0; - uint32_t dayOfMonth = 0; - hal->getLocalDate(&dayOfMonth, &weekDay); - cursorPos = weekDay; + OswDate oswDate = { }; + hal->getLocalDate(oswDate); + cursorPos = oswDate.weekDay; } void OswAppDistStats::loop() { OswHal* hal = OswHal::getInstance(); @@ -79,4 +74,4 @@ void OswAppDistStats::loopDebug() { #endif void OswAppDistStats::stop() {} -#endif \ No newline at end of file +#endif diff --git a/src/apps/tools/OswAppFitnessStats.cpp b/src/apps/tools/OswAppFitnessStats.cpp index fbd59549e..d44bb58e3 100644 --- a/src/apps/tools/OswAppFitnessStats.cpp +++ b/src/apps/tools/OswAppFitnessStats.cpp @@ -1,3 +1,6 @@ +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 + #include "./apps/tools/OswAppFitnessStats.h" #include "./apps/watchfaces/OswAppWatchfaceDual.h" #include "./apps/watchfaces/OswAppWatchfaceFitness.h" @@ -56,3 +59,4 @@ void OswAppFitnessStats::loop() { } void OswAppFitnessStats::stop() {} +#endif diff --git a/src/apps/tools/OswAppFlashLight.cpp b/src/apps/tools/OswAppFlashLight.cpp index 11c6caaad..8b08d0781 100644 --- a/src/apps/tools/OswAppFlashLight.cpp +++ b/src/apps/tools/OswAppFlashLight.cpp @@ -43,7 +43,7 @@ void OswAppFlashLight::onDraw() { this->hal->gfx()->print(int(hal->screenBrightness())); //displays the current brightness } else { this->hal->gfx()->fillCircle(120, 120, 115, blackColor); - this->hal->gfx()->setTextSize(3.5); + this->hal->gfx()->setTextSize(3); this->hal->gfx()->setTextCenterAligned(); this->hal->gfx()->setTextCursor(120, 125); this->hal->gfx()->setTextColor(whiteColor); @@ -78,4 +78,4 @@ void OswAppFlashLight::onButton(Button id, bool up, OswAppV2::ButtonStateNames s void OswAppFlashLight::onStop() { OswAppV2::onStop(); this->hal->setBrightness(OswConfigAllKeys::settingDisplayBrightness.get(), false); // reset the brightness to the initial value -} \ No newline at end of file +} diff --git a/src/apps/tools/OswAppKcalStats.cpp b/src/apps/tools/OswAppKcalStats.cpp index 1114c3b49..f4fb02ab0 100644 --- a/src/apps/tools/OswAppKcalStats.cpp +++ b/src/apps/tools/OswAppKcalStats.cpp @@ -14,9 +14,9 @@ uint32_t findCursorWeekDay(uint8_t Index) { // Show the day of the week that cursor (Dynamic weekDay--info) OswHal* hal = OswHal::getInstance(); - uint32_t d, wD = 0; - hal->getLocalDate(&d, &wD); - int cursorWeekDay = wD - (6 - Index); + OswDate oswDate = { }; + hal->getLocalDate(oswDate); + int cursorWeekDay = oswDate.weekDay - (6 - Index); int findWeekDay = (cursorWeekDay >= 0) ? cursorWeekDay : (cursorWeekDay + 7); uint32_t fWD = findWeekDay; return fWD; @@ -47,12 +47,12 @@ void OswAppKcalStats::drawCurvedChart() { hal->gfx()->drawThickTick(this->cursorPos == 6 && Index == 5 ? x2 : x1, 140, 0, 60, 0, 3, ui->getForegroundColor()); } - hal->gfx()->drawLine(x1, y1, x2, y2, changeColor(ui->getSuccessColor(),2.25)); // first-second Coord - hal->gfx()->fillCircle(x1, y1, 2.5,ui->getSuccessColor() ); // draw circle on the first coord + hal->gfx()->drawLine(x1, y1, x2, y2, changeColor(ui->getSuccessColor(),2.25f)); // first-second Coord + hal->gfx()->fillCircle(x1, y1, 2.5f,ui->getSuccessColor() ); // draw circle on the first coord // last coord if (Index == 5) { - hal->gfx()->fillCircle(x2, y2, 2.5,ui->getSuccessColor() ); + hal->gfx()->fillCircle(x2, y2, 2.5f,ui->getSuccessColor() ); } } } @@ -99,4 +99,4 @@ void OswAppKcalStats::loopDebug() { #endif void OswAppKcalStats::stop() {} -#endif \ No newline at end of file +#endif diff --git a/src/apps/tools/OswAppPrintDebug.cpp b/src/apps/tools/OswAppPrintDebug.cpp index 5f864f746..b8df89962 100644 --- a/src/apps/tools/OswAppPrintDebug.cpp +++ b/src/apps/tools/OswAppPrintDebug.cpp @@ -67,6 +67,17 @@ void OswAppPrintDebug::loop() { printStatus((String(" ") + d->getName()).c_str(), String(d->getMagnetometerAzimuth() + String(" deg")).c_str()); // Idea: Also print azimuth, bearing or calibration #endif +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 + printStatus("Accelerometer", String(String(hal->environment()->getAccelerationX()) + ";" + String(hal->environment()->getAccelerationY()) + ";" + String(hal->environment()->getAccelerationZ()) + " m/s^2").c_str()); + for(auto& d : *OswAccelerationProvider::getAllAccelerationDevices()) + printStatus((String(" ") + d->getName()).c_str(), String(String(hal->environment()->getAccelerationX()) + ";" + String(hal->environment()->getAccelerationY()) + ";" + String(hal->environment()->getAccelerationZ()) + " m/s^2").c_str()); + printStatus("Steps", String(hal->environment()->getStepsToday()).c_str()); + for(auto& d : *OswAccelerationProvider::getAllAccelerationDevices()) + printStatus((String(" ") + d->getName()).c_str(), String(hal->environment()->getStepsToday()).c_str()); + printStatus("Activity", String((int) hal->environment()->getActivityMode()).c_str()); + for(auto& d : *OswAccelerationProvider::getAllAccelerationDevices()) + printStatus((String(" ") + d->getName()).c_str(), String((int) hal->environment()->getActivityMode()).c_str()); +#endif #endif printStatus("UTC Time", String(String(hal->getUTCTime()) + " sec").c_str()); for(auto& d : *OswTimeProvider::getAllTimeDevices()) @@ -151,4 +162,4 @@ void OswAppPrintDebug::stop() { OswHal::getInstance()->gpsBackupMode(); #endif } -#endif \ No newline at end of file +#endif diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index 1fc5ab495..967ba053d 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -14,10 +14,6 @@ void OswAppStepStats::drawChart() { uint8_t interval = 20; uint16_t goalValue = OswConfigAllKeys::stepsPerDay.get(); - uint32_t weekDay = 0; - uint32_t dayOfMonth = 0; - hal->getLocalDate(&dayOfMonth, &weekDay); - for (uint8_t index = 0; index < 7; index++) { unsigned int weekDayStep = hal->environment()->getStepsOnDay(index); unsigned short chartStickValue = ((float)(weekDayStep > goalValue ? goalValue : weekDayStep) / goalValue) * chartStickHeight; @@ -43,7 +39,12 @@ void OswAppStepStats::drawInfoPanel(OswUI* ui, uint32_t pos, uint32_t lastWeekDa hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextBottomAligned(); hal->gfx()->setTextCursor(DISP_W / 2, 170); - hal->gfx()->print(hal->getLocalWeekday(&pos)); + try { + const char* weekday = hal->getWeekDay.at(pos); + hal->gfx()->print(weekday); + } catch (const std::out_of_range& ignore) { + OSW_LOG_E("getWeekDay is out of range: ", ignore.what()); + } hal->gfx()->setTextCursor(DISP_W / 2, 190); hal->gfx()->print(String(lastWeekData)); // lastweek(before 7 day) hal->gfx()->setTextCursor(DISP_W / 2, 215); @@ -69,10 +70,9 @@ void OswAppStepStats::showStickChart() { void OswAppStepStats::setup() { OswHal* hal = OswHal::getInstance(); - uint32_t weekDay = 0; - uint32_t dayOfMonth = 0; - hal->getLocalDate(&dayOfMonth, &weekDay); - cursorPos = weekDay; + OswDate oswDate = { }; + hal->getLocalDate(oswDate); + cursorPos = oswDate.weekDay; } void OswAppStepStats::loop() { OswHal* hal = OswHal::getInstance(); @@ -96,4 +96,4 @@ void OswAppStepStats::loopDebug() { #endif void OswAppStepStats::stop() {} -#endif \ No newline at end of file +#endif diff --git a/src/apps/tools/OswAppTimeConfig.cpp b/src/apps/tools/OswAppTimeConfig.cpp index 8f3a6a3d5..eccda97fd 100644 --- a/src/apps/tools/OswAppTimeConfig.cpp +++ b/src/apps/tools/OswAppTimeConfig.cpp @@ -15,25 +15,21 @@ void OswAppTimeConfig::setup() {} void OswAppTimeConfig::enterManualMode() { - uint32_t second = 0; - uint32_t minute = 0; - uint32_t hour = 0; - uint32_t day = 0; - uint32_t month = 0; - uint32_t year = 0; - OswHal::getInstance()->getLocalTime(&hour, &minute, &second); - OswHal::getInstance()->getLocalDate(&day, &month, &year); - manualSettingTimestamp[0] = year % 10; - manualSettingTimestamp[1] = month / 10; - manualSettingTimestamp[2] = month % 10; - manualSettingTimestamp[3] = day / 10; - manualSettingTimestamp[4] = day % 10; - manualSettingTimestamp[5] = hour / 10; - manualSettingTimestamp[6] = hour % 10; - manualSettingTimestamp[7] = minute / 10; - manualSettingTimestamp[8] = minute % 10; - manualSettingTimestamp[9] = second / 10; - manualSettingTimestamp[10] = second % 10; + OswTime oswTime = { }; + OswDate oswDate = { }; + OswHal::getInstance()->getLocalTime(oswTime); + OswHal::getInstance()->getLocalDate(oswDate); + manualSettingTimestamp[0] = oswDate.year % 10; + manualSettingTimestamp[1] = oswDate.month / 10; + manualSettingTimestamp[2] = oswDate.month % 10; + manualSettingTimestamp[3] = oswDate.day / 10; + manualSettingTimestamp[4] = oswDate.day % 10; + manualSettingTimestamp[5] = oswTime.hour / 10; + manualSettingTimestamp[6] = oswTime.hour % 10; + manualSettingTimestamp[7] = oswTime.minute / 10; + manualSettingTimestamp[8] = oswTime.minute % 10; + manualSettingTimestamp[9] = oswTime.second / 10; + manualSettingTimestamp[10] = oswTime.second % 10; manualSettingScreen = true; } @@ -196,16 +192,13 @@ void OswAppTimeConfig::loop() { hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextCursor(120 - hal->gfx()->getTextOfsetColumns(4), 120); - - uint32_t second = 0; - uint32_t minute = 0; - uint32_t hour = 0; - hal->getLocalTime(&hour, &minute, &second); - hal->gfx()->printDecimal(hour, 2); + OswTime oswTime = { }; + hal->getLocalTime(oswTime); + hal->gfx()->printDecimal(oswTime.hour, 2); hal->gfx()->print(":"); - hal->gfx()->printDecimal(minute, 2); + hal->gfx()->printDecimal(oswTime.minute, 2); hal->gfx()->print(":"); - hal->gfx()->printDecimal(second, 2); + hal->gfx()->printDecimal(oswTime.second, 2); } else { handleIncrementButton(); @@ -244,13 +237,13 @@ void OswAppTimeConfig::loop() { // Cancel-Field hal->gfx()->setTextRightAligned(); - hal->gfx()->setTextCursor((DISP_W / 2) - hal->gfx()->getTextOfsetColumns(0.5), DISP_H * 5 / 8); + hal->gfx()->setTextCursor((DISP_W / 2) - hal->gfx()->getTextOfsetColumns(0.5f), DISP_H * 5 / 8); hal->gfx()->setTextColor(11 == manualSettingStep ? colorActive : colorForeground, colorBackground); hal->gfx()->print(LANG_CANCEL); // Done-Field hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor((DISP_W / 2) + hal->gfx()->getTextOfsetColumns(0.5), DISP_H * 5 / 8); + hal->gfx()->setTextCursor((DISP_W / 2) + hal->gfx()->getTextOfsetColumns(0.5f), DISP_H * 5 / 8); hal->gfx()->setTextColor(12 == manualSettingStep ? colorActive : colorForeground, colorBackground); hal->gfx()->print(LANG_SAVE); } diff --git a/src/apps/tools/OswAppTutorial.cpp b/src/apps/tools/OswAppTutorial.cpp index 48dbd0aec..b1d97c9c4 100644 --- a/src/apps/tools/OswAppTutorial.cpp +++ b/src/apps/tools/OswAppTutorial.cpp @@ -247,4 +247,4 @@ bool OswAppTutorial::changeRootAppIfNecessary() { return true; } return false; -} \ No newline at end of file +} diff --git a/src/apps/tools/OswAppWaterLevel.cpp b/src/apps/tools/OswAppWaterLevel.cpp index 7164143f2..508251c85 100644 --- a/src/apps/tools/OswAppWaterLevel.cpp +++ b/src/apps/tools/OswAppWaterLevel.cpp @@ -1,3 +1,5 @@ +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 #include "./apps/tools/OswAppWaterLevel.h" @@ -43,7 +45,7 @@ void OswAppWaterLevel::circlesDisplay() { const float xValue = hal->environment()->getAccelerationX(); const float yValue = hal->environment()->getAccelerationY(); - const bool isXYAccelerationInMiddle = abs(yValue) < 0.25 && abs(xValue) < 0.25; + const bool isXYAccelerationInMiddle = abs(yValue) < 0.25f && abs(xValue) < 0.25f; uint16_t color = isXYAccelerationInMiddle ? ui->getSuccessColor() : ui->getInfoColor(); @@ -79,7 +81,7 @@ void OswAppWaterLevel::drawBar(const float value, char text, const int x) { gfx->fillRFrame(x, 120 - 5 - yOffset, width, height + barHeight, 5, rgb565(redComponent, greenComponent, 0)); - bool isMiddleValue = value > -0.25 && value < 0.25; + bool isMiddleValue = value > -0.25f && value < 0.25f; const int backgroundColor = isMiddleValue ? ui->getSuccessColor() : ui->getBackgroundColor(); const int foregroundColor = isMiddleValue ? ui->getBackgroundColor() : ui->getForegroundColor(); @@ -131,3 +133,4 @@ void OswAppWaterLevel::loop() { } void OswAppWaterLevel::stop() {} +#endif diff --git a/src/apps/tools/OswAppWebserver.cpp b/src/apps/tools/OswAppWebserver.cpp index 1ce4fd032..cc4d39ca9 100644 --- a/src/apps/tools/OswAppWebserver.cpp +++ b/src/apps/tools/OswAppWebserver.cpp @@ -1,7 +1,7 @@ #ifdef OSW_FEATURE_WIFI #include "./apps/tools/OswAppWebserver.h" -#include +#include #include #include #include @@ -96,4 +96,4 @@ void OswAppWebserver::drawConnectionInfo() { } void OswAppWebserver::stop() {} -#endif \ No newline at end of file +#endif diff --git a/src/apps/watchfaces/OswAppWatchface.cpp b/src/apps/watchfaces/OswAppWatchface.cpp index a77c8cb3e..ba8ae4a7f 100644 --- a/src/apps/watchfaces/OswAppWatchface.cpp +++ b/src/apps/watchfaces/OswAppWatchface.cpp @@ -13,6 +13,9 @@ #include "./apps/watchfaces/OswAppWatchface.h" +#define CENTER_X (DISP_W / 2) +#define CENTER_Y (DISP_H / 2) + const char* OswAppWatchface::getAppId() { return OswAppWatchface::APP_ID; } @@ -25,9 +28,10 @@ const char* OswAppWatchface::getAppName() { void OswAppWatchface::drawStepHistory(OswUI* ui, uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint32_t max) { OswHal* hal = OswHal::getInstance(); OswUI::getInstance()->resetTextColors(); - uint32_t weekDay = 0; - uint32_t dayOfMonth = 0; - hal->getLocalDate(&dayOfMonth, &weekDay); + + OswDate oswDate = { }; + hal->getLocalDate(oswDate); + for (uint8_t i = 0; i < 7; i++) { uint32_t s = hal->environment()->getStepsOnDay(i); uint16_t boxHeight = ((float)(s > max ? max : s) / max) * h; @@ -37,18 +41,18 @@ void OswAppWatchface::drawStepHistory(OswUI* ui, uint8_t x, uint8_t y, uint8_t w uint16_t c = (unsigned int) OswConfigAllKeys::stepsPerDay.get() <= s ? ui->getSuccessColor() : ui->getPrimaryColor(); hal->gfx()->fillFrame(x + i * w, y + (h - boxHeight), w, boxHeight, c); // bar frames - uint16_t f = weekDay == i ? ui->getForegroundColor() : ui->getForegroundDimmedColor(); + uint16_t f = oswDate.weekDay == i ? ui->getForegroundColor() : ui->getForegroundDimmedColor(); hal->gfx()->drawRFrame(x + i * w, y, w, h, 2, f); // labels hal->gfx()->setTextCenterAligned(); // horiz. hal->gfx()->setTextBottomAligned(); hal->gfx()->setTextSize(1); - hal->gfx()->setTextCursor(DISP_W * 0.5, y - 1); + hal->gfx()->setTextCursor(CENTER_X, y - 1); hal->gfx()->print(hal->environment()->getStepsToday() + (OswConfigAllKeys::settingDisplayStepsGoal.get() ? String("/") + max:"")); - hal->gfx()->setTextCursor(DISP_W * 0.5, y + 1 + 8 + w * 4); + hal->gfx()->setTextCursor(CENTER_X, y + 1 + 8 + w * 4); hal->gfx()->setTextColor(ui->getForegroundColor()); // Let's make the background transparent. // See : https://github.com/Open-Smartwatch/open-smartwatch-os/issues/194 // font : WHITE / bg : None @@ -61,68 +65,60 @@ void OswAppWatchface::drawStepHistory(OswUI* ui, uint8_t x, uint8_t y, uint8_t w void OswAppWatchface::drawWatch() { OswHal* hal = OswHal::getInstance(); - hal->gfx()->drawMinuteTicks(DISP_W * 0.5, DISP_H * 0.5, 116, 112, ui->getForegroundDimmedColor()); - hal->gfx()->drawHourTicks(DISP_W * 0.5, DISP_H * 0.5, 117, 107, ui->getForegroundColor()); + + hal->gfx()->drawMinuteTicks(CENTER_Y, CENTER_Y, 116, 112, ui->getForegroundDimmedColor(), true); + hal->gfx()->drawHourTicks(CENTER_X, CENTER_Y, 117, 107, ui->getForegroundColor(), true); #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 uint32_t steps = hal->environment()->getStepsToday(); uint32_t stepsTarget = OswConfigAllKeys::stepsPerDay.get(); - hal->gfx()->drawArc(DISP_W * 0.5, DISP_H * 0.5, 0, 360.0 * (float)(steps % stepsTarget) / (float)stepsTarget, 90, 93, 6, + hal->gfx()->drawArc(CENTER_X, CENTER_Y, 0, 360.0f * (float)(steps % stepsTarget) / (float)stepsTarget, 90, 93, 6, steps > stepsTarget ? ui->getSuccessColor() : ui->getInfoColor(), true); #endif #ifdef OSW_FEATURE_STATS_STEPS uint8_t w = 8; - OswAppWatchface::drawStepHistory(ui, (DISP_W / 2) - w * 3.5, 180, w, w * 4, OswConfigAllKeys::stepsPerDay.get()); + OswAppWatchface::drawStepHistory(ui, (CENTER_X) - w * 3.5f, 180, w, w * 4, OswConfigAllKeys::stepsPerDay.get()); #endif // below two arcs take too long to draw - // hal->gfx()->drawArc(120, 120, 0, 360, 180, 75, 7, changeColor(COLOR_GREEN, 0.25)); + // hal->gfx()->drawArc(120, 120, 0, 360, 180, 75, 7, changeColor(COLOR_GREEN, 0.25f)); // hal->gfx()->drawArc(120, 120, 0, (steps / 360) % 360, 180, 75, 7, dimColor(COLOR_GREEN, 25)); // hal->gfx()->drawArc(120, 120, 0, (steps / 360) % 360, 180, 75, 6, COLOR_GREEN); - // float bat = hal->getBatteryPercent() * 3.6; + // float bat = hal->getBatteryPercent() * 3.6f; - // hal->gfx()->drawArc(120, 120, 0, 360, 180, 57, 7, changeColor(COLOR_BLUE, 0.25)); + // hal->gfx()->drawArc(120, 120, 0, 360, 180, 57, 7, changeColor(COLOR_BLUE, 0.25f)); // hal->gfx()->drawArc(120, 120, 0, bat, 180, 57, 7, dimColor(COLOR_BLUE, 25)); // hal->gfx()->drawArc(120, 120, 0, bat, 180, 57, 6, COLOR_BLUE); - uint32_t second = 0; - uint32_t minute = 0; - uint32_t hour = 0; - hal->getLocalTime(&hour, &minute, &second); + OswTime oswTime = { }; + hal->getLocalTime(oswTime); if(OswConfigAllKeys::settingDisplayDualHourTick.get()) { - uint32_t dualSecond = 0; - uint32_t dualMinute = 0; - uint32_t dualHour = 0; - hal->getDualTime(&dualHour, &dualMinute, &dualSecond); + OswTime oswDualTime = { }; + hal->getDualTime(oswDualTime); // dual-hours - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 0, 16, 360.0 / 12.0 * (1.0 * dualHour + dualMinute / 60.0), 2, ui->getBackgroundDimmedColor()); - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 16, 60, 360.0 / 12.0 * (1.0 * dualHour + dualMinute / 60.0), 5, ui->getBackgroundDimmedColor()); + hal->gfx()->drawThickTick(CENTER_X, CENTER_Y, 0, 16, (int)(360.0f / 12.0f * (oswDualTime.hour + oswDualTime.minute / 60.0f)), 2, ui->getBackgroundDimmedColor(), true, STRAIGHT_END); + hal->gfx()->drawThickTick(CENTER_X, CENTER_Y, 16, 60, (int)(360.0f / 12.0f * (oswDualTime.hour + oswDualTime.minute / 60.0f)), 5, ui->getBackgroundDimmedColor(), true); } // hours - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 0, 16, 360.0 / 12.0 * (1.0 * hour + minute / 60.0), 1, ui->getForegroundColor()); - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 16, 60, 360.0 / 12.0 * (1.0 * hour + minute / 60.0), 4, ui->getForegroundColor()); + hal->gfx()->drawThickTick(CENTER_X, CENTER_Y, 0, (int)16, (int)(360.0f / 12.0f * (oswTime.hour + oswTime.minute / 60.0f)), 1, ui->getForegroundColor(), true, STRAIGHT_END); + hal->gfx()->drawThickTick(CENTER_X, CENTER_Y, 16, 60, (int)(360.0f / 12.0f * (oswTime.hour + oswTime.minute / 60.0f)), 4, ui->getForegroundColor(), true); // minutes - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 0, 16, 360.0 / 60.0 * (1.0 * minute + second / 60.0), 1, ui->getForegroundColor()); - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 16, 105, 360.0 / 60.0 * (1.0 * minute + second / 60.0), 4, ui->getForegroundColor()); + hal->gfx()->drawThickTick(CENTER_X, CENTER_Y, 0, 16, (int)(360.0f / 60.0f * (oswTime.minute + oswTime.second / 60.0f)), 1, ui->getForegroundColor(), true, STRAIGHT_END); + hal->gfx()->drawThickTick(CENTER_X, CENTER_Y, 16, 105, (int)(360.0f / 60.0f * (oswTime.minute + oswTime.second / 60.0f)), 4, ui->getForegroundColor(), true); #ifndef GIF_BG // seconds - hal->gfx()->fillCircle(DISP_W * 0.5, DISP_H * 0.5, 3, ui->getDangerColor()); - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 0, 16, 180 + ( 360.0 / 60.0 * second ), 1, ui->getDangerColor()); - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 0, 110, 360.0 / 60.0 * second, 1, ui->getDangerColor()); + hal->gfx()->fillCircleAA(CENTER_X, CENTER_Y, 3, ui->getDangerColor()); + hal->gfx()->drawThickTick(CENTER_X, CENTER_Y, -16, 110, 180 + 360 / 60 * oswTime.second, 1, ui->getDangerColor(), true); #endif } -#ifdef GIF_BG -OswAppGifPlayer* bgGif = new OswAppGifPlayer(); -#endif - void OswAppWatchface::onStart() { OswAppV2::onStart(); this->viewFlags = OswAppV2::ViewFlags::NO_OVERLAYS; // no overlay for this watchface diff --git a/src/apps/watchfaces/OswAppWatchfaceBinary.cpp b/src/apps/watchfaces/OswAppWatchfaceBinary.cpp index c8e1cae0c..b6ca72f84 100644 --- a/src/apps/watchfaces/OswAppWatchfaceBinary.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceBinary.cpp @@ -5,6 +5,7 @@ #include "apps/watchfaces/OswAppWatchface.h" #include "apps/watchfaces/OswAppWatchfaceBinary.h" +#include OSW_TARGET_PLATFORM_HEADER #define COLOR_SECxOND rgb565(231, 111, 81) #define COLOR_MIxNUTE rgb565(244, 162, 97) @@ -13,12 +14,10 @@ #define COLOR_WHxITE rgb565(255, 255, 255) void OswAppWatchfaceBinary::drawWatch() { - uint32_t second = 0; - uint32_t minute = 0; - uint32_t hour = 0; - bool afterNoon = false; OswHal* hal = OswHal::getInstance(); - hal->getLocalTime(&hour, &minute, &second, &afterNoon); + + OswTime oswTime = { }; + hal->getLocalTime(oswTime); uint16_t width = hal->gfx()->getWidth(); uint16_t height = hal->gfx()->getHeight(); @@ -26,7 +25,7 @@ void OswAppWatchfaceBinary::drawWatch() { //hours for(uint8_t i = 0; i < 5 ; i++ ) { uint32_t b = pow(2, i); - if((hour & b) == 0) { + if((oswTime.hour & b) == 0) { hal->gfx()->drawFrame(width - (((width - 32) / 8) * i + 64) - 32, height / 2 - 16, 8, 8, ui->getWarningColor()); } else { hal->gfx()->fillFrame(width - (((width - 32) / 8) * i + 64) - 32, height / 2 - 16, 8, 8, ui->getWarningColor()); @@ -35,7 +34,7 @@ void OswAppWatchfaceBinary::drawWatch() { //minutes for(uint8_t i = 0; i < 6 ; i++ ) { uint32_t b = pow(2, i); - if((minute & b) == 0) { + if((oswTime.minute & b) == 0) { hal->gfx()->drawFrame(width - (((width - 32) / 8) * i + 64) - 32, height / 2, 8, 8, ui->getDangerColor()); } else { hal->gfx()->fillFrame(width - (((width - 32) / 8) * i + 64) - 32, height / 2, 8, 8, ui->getDangerColor()); @@ -44,7 +43,7 @@ void OswAppWatchfaceBinary::drawWatch() { //seconds for(uint8_t i = 0; i < 6 ; i++ ) { uint32_t b = pow(2, i); - if((second & b) == 0) { + if((oswTime.second & b) == 0) { hal->gfx()->drawFrame(width - (((width - 32) / 8) * i + 64) - 32, height / 2 + 16, 8, 8, ui->getInfoColor()); } else { hal->gfx()->fillFrame(width - (((width - 32) / 8) * i + 64) - 32, height / 2 + 16, 8, 8, ui->getInfoColor()); @@ -54,6 +53,7 @@ void OswAppWatchfaceBinary::drawWatch() { //cosmetic hal->gfx()->drawLine(width /2 + 40, height / 8 * 1, width /2 + 40, height / 8 * 7, ui->getForegroundColor()); +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 //steps uint32_t steps = hal->environment()->getStepsToday(); hal->gfx()->setTextSize(1); @@ -65,6 +65,7 @@ void OswAppWatchfaceBinary::drawWatch() { hal->gfx()->setTextCursor(width /2 + 48, height / 2 + 32); hal->gfx()->print("0x"); hal->gfx()->print(steps, HEX); +#endif } const char* OswAppWatchfaceBinary::getAppId() { diff --git a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp index 2cd9afc9b..ec1e09138 100644 --- a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp @@ -5,6 +5,7 @@ #include "./apps/watchfaces/OswAppWatchface.h" #include "./apps/watchfaces/OswAppWatchfaceDigital.h" +#include OSW_TARGET_PLATFORM_HEADER uint8_t OswAppWatchfaceDigital::dateFormatCache = 42; @@ -20,7 +21,7 @@ void OswAppWatchfaceDigital::refreshDateFormatCache() { OswAppWatchfaceDigital::dateFormatCache = (format == "mm/dd/yyyy" ? 1 : (format == "dd.mm.yyyy" ? 2 : 3)); } -// display Weekday to 3 charater +// display Weekday to 3 character void OswAppWatchfaceDigital::displayWeekDay3(const char* weekday) { OswHal* hal = OswHal::getInstance(); @@ -60,22 +61,24 @@ void OswAppWatchfaceDigital::dateOutput(uint32_t yearInt, uint32_t monthInt, uin } static void drawDate(time_t timeZone, uint8_t fontSize, uint8_t CoordY) { - uint32_t dayInt = 0; - uint32_t monthInt = 0; - uint32_t yearInt = 0; + OswDate oswDate = { }; OswHal* hal = OswHal::getInstance(); - const char* weekday = hal->getWeekday(timeZone); - hal->getDate(timeZone,&dayInt, &monthInt, &yearInt); + hal->getDate(timeZone, oswDate); // we want to output a value like "Wed, 05/02/2021" hal->gfx()->setTextSize(fontSize); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(120 - hal->gfx()->getTextOfsetColumns(6.9), CoordY); + hal->gfx()->setTextCursor(120 - hal->gfx()->getTextOfsetColumns(6.9f), CoordY); - OswAppWatchfaceDigital::displayWeekDay3(weekday); + try { + const char* weekday = hal->getWeekDay.at(oswDate.weekDay); + OswAppWatchfaceDigital::displayWeekDay3(weekday); + } catch (const std::out_of_range& ignore) { + OSW_LOG_E("getWeekDay is out of range: ", ignore.what()); + } // The GFX library has an alignment bug, causing single letters to "float", therefore the workaround above is used to still utilize the correct string printing. //hal->gfx()->print(weekday[0]); @@ -85,7 +88,7 @@ static void drawDate(time_t timeZone, uint8_t fontSize, uint8_t CoordY) { // i really would want the date to be dynamic based on what's in the config, but the most efficient thing to do right // now is simply three if statements covering the 3 common conditions. - OswAppWatchfaceDigital::dateOutput(yearInt, monthInt, dayInt); + OswAppWatchfaceDigital::dateOutput(oswDate.year, oswDate.month, oswDate.day); } void OswAppWatchfaceDigital::timeOutput(uint32_t hour, uint32_t minute, uint32_t second,bool showSecond) { @@ -100,10 +103,7 @@ void OswAppWatchfaceDigital::timeOutput(uint32_t hour, uint32_t minute, uint32_t } static void drawTime(time_t timeZone,uint8_t CoordY) { - uint32_t second = 0; - uint32_t minute = 0; - uint32_t hour = 0; - bool afterNoon = false; + OswTime oswTime = { }; char am[] = "AM"; char pm[] = "PM"; OswHal* hal = OswHal::getInstance(); @@ -113,11 +113,11 @@ static void drawTime(time_t timeZone,uint8_t CoordY) { hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextCursor(120 - hal->gfx()->getTextOfsetColumns(OswConfigAllKeys::timeFormat.get() ? 4 : 5.5),CoordY ); - hal->getTime(timeZone,&hour, &minute, &second, &afterNoon); - OswAppWatchfaceDigital::timeOutput(hour, minute, second); + hal->getTime(timeZone, oswTime); + OswAppWatchfaceDigital::timeOutput(oswTime.hour, oswTime.minute, oswTime.second); if (!OswConfigAllKeys::timeFormat.get()) { hal->gfx()->print(" "); - if (afterNoon) { + if (oswTime.afterNoon) { hal->gfx()->print(pm); } else { hal->gfx()->print(am); @@ -133,10 +133,11 @@ const char* OswAppWatchfaceDigital::getAppName() { return LANG_DIGITAL; } +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 void OswAppWatchfaceDigital::drawSteps() { #ifdef OSW_FEATURE_STATS_STEPS uint8_t w = 8; - OswAppWatchface::drawStepHistory(OswUI::getInstance(), (DISP_W / 2) - w * 3.5, 180, w, w * 4, OswConfigAllKeys::stepsPerDay.get()); + OswAppWatchface::drawStepHistory(OswUI::getInstance(), (DISP_W / 2) - w * 3.5f, 180, w, w * 4, OswConfigAllKeys::stepsPerDay.get()); #else OswHal* hal = OswHal::getInstance(); uint32_t steps = hal->environment()->getStepsToday(); @@ -147,6 +148,7 @@ void OswAppWatchfaceDigital::drawSteps() { hal->gfx()->print(steps); #endif } +#endif void OswAppWatchfaceDigital::digitalWatch(short timeZone,uint8_t fontSize, uint8_t dateCoordY, uint8_t timeCoordY) { @@ -181,4 +183,4 @@ void OswAppWatchfaceDigital::onButton(Button id, bool up, OswAppV2::ButtonStateN OswAppV2::onButton(id, up, state); if(OswAppWatchface::onButtonDefaults(*this, id, up, state)) return; // if the button was handled by the defaults, we are done here -} \ No newline at end of file +} diff --git a/src/apps/watchfaces/OswAppWatchfaceDual.cpp b/src/apps/watchfaces/OswAppWatchfaceDual.cpp index ab59eb97a..d665c73bf 100644 --- a/src/apps/watchfaces/OswAppWatchfaceDual.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceDual.cpp @@ -25,21 +25,21 @@ */ void OswAppWatchfaceDual::drawProgressBar(OswUI* ui,uint8_t cx, uint8_t cy, uint8_t jump, uint8_t length, uint8_t value,float angle, uint8_t radius, uint16_t color, uint8_t* goal) { OswHal* hal = OswHal::getInstance(); - hal->gfx()->drawThickTick(cx, cy, jump, length, angle, radius, changeColor(color, 0.25)); + hal->gfx()->drawThickTick(cx, cy, jump, length, angle, radius, changeColor(color, 0.25f)); hal->gfx()->drawThickTick(cx, cy, jump, value, angle, radius, goal == nullptr ? color :*goalgetSuccessColor():color, true); } void OswAppWatchfaceDual::drawAnimSec() { OswHal* hal = OswHal::getInstance(); uint8_t barWidth = 140; - uint32_t Hs, Ms, Ss = 0; - hal->getLocalTime(&Hs,&Ms,&Ss); - uint32_t onlySecond = Ss; + OswTime oswTime = { }; + hal->getLocalTime(oswTime); + uint32_t onlySecond = oswTime.second; uint16_t barValue = ((float)onlySecond / 60) * barWidth; barValue = barValue < 2 ? 0 : barValue; uint8_t coordX = (DISP_W - barWidth) / 2; uint8_t levelY = DISP_H / 2; - uint8_t radius = 1.5; + uint8_t radius = 1; drawProgressBar(ui, coordX, levelY - 1, 0, barWidth, barValue, 90, radius, ui->getPrimaryColor()); } @@ -67,7 +67,7 @@ void OswAppWatchfaceDual::onDraw() { // Set Dual Size hal->gfx()->setTextSize(2); - uint8_t mid_little = hal->gfx()->getTextOfsetRows(0.5); + uint8_t mid_little = hal->gfx()->getTextOfsetRows(0.5f); uint8_t mid = hal->gfx()->getTextOfsetRows(2); OswAppWatchfaceDigital::digitalWatch(hal->getTimezoneOffsetPrimary(),1, 120 - mid_little, 120 - mid); @@ -86,4 +86,4 @@ void OswAppWatchfaceDual::onButton(Button id, bool up, OswAppV2::ButtonStateName OswAppV2::onButton(id, up, state); if(OswAppWatchface::onButtonDefaults(*this, id, up, state)) return; // if the button was handled by the defaults, we are done here -} \ No newline at end of file +} diff --git a/src/apps/watchfaces/OswAppWatchfaceFitness.cpp b/src/apps/watchfaces/OswAppWatchfaceFitness.cpp index 1f1b47879..91d6ef753 100644 --- a/src/apps/watchfaces/OswAppWatchfaceFitness.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceFitness.cpp @@ -1,3 +1,6 @@ +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 + #include "apps/watchfaces/OswAppWatchfaceFitness.h" #include "apps/watchfaces/OswAppWatchfaceDigital.h" #include "apps/watchfaces/OswAppWatchface.h" @@ -11,8 +14,8 @@ float OswAppWatchfaceFitness::calculateDistance(uint32_t steps) { uint8_t userHeight = OswConfigAllKeys::configHeight.get(); - uint16_t avgDist = ((userHeight * 0.37) + (userHeight * 0.45) + (userHeight - 100)) / 3; - return steps * avgDist * 0.01 ; // cm -> m + uint16_t avgDist = ((userHeight * 0.37f) + (userHeight * 0.45f) + (userHeight - 100)) / 3; + return steps * avgDist * 0.01f ; // cm -> m } uint32_t OswAppWatchfaceFitness::calculateKcalorie(uint32_t steps) { @@ -22,27 +25,28 @@ uint32_t OswAppWatchfaceFitness::calculateKcalorie(uint32_t steps) { } void dateDisplay() { - uint32_t dayInt = 0; - uint32_t monthInt = 0; - uint32_t yearInt = 0; OswHal* hal = OswHal::getInstance(); - const char* weekday = hal->getLocalWeekday(); - hal->getLocalDate(&dayInt, &monthInt, &yearInt); + OswDate oswDate = { }; + hal->getLocalDate(oswDate); hal->gfx()->setTextSize(2); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextRightAligned(); hal->gfx()->setTextCursor(205, 90); - - OswAppWatchfaceDigital::displayWeekDay3(weekday); + try { + const char* weekday = hal->getWeekDay.at(oswDate.weekDay); + OswAppWatchfaceDigital::displayWeekDay3(weekday); + } catch (const std::out_of_range& ignore) { + OSW_LOG_E("getWeekDay is out of range: ", ignore.what()); + } // Date hal->gfx()->setTextSize(2); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(DISP_W * 0.5 - 30 + hal->gfx()->getTextOfsetColumns(1), 150); - OswAppWatchfaceDigital::dateOutput(yearInt, monthInt, dayInt); + hal->gfx()->setTextCursor(DISP_W / 2 - 30 + hal->gfx()->getTextOfsetColumns(1), 150); + OswAppWatchfaceDigital::dateOutput(oswDate.year, oswDate.month, oswDate.day); } void timeDisplay(uint32_t hour, uint32_t minute, uint32_t second) { @@ -54,15 +58,11 @@ void timeDisplay(uint32_t hour, uint32_t minute, uint32_t second) { hal->gfx()->setTextSize(1); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(215, DISP_W * 0.5); + hal->gfx()->setTextCursor(215, DISP_H / 2); hal->gfx()->printDecimal(second,2); } void digitalWatchDisplay() { - uint32_t second = 0; - uint32_t minute = 0; - uint32_t hour = 0; - bool afterNoon = false; char am[] = "AM"; char pm[] = "PM"; OswHal* hal = OswHal::getInstance(); @@ -70,14 +70,14 @@ void digitalWatchDisplay() { hal->gfx()->setTextSize(4); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(DISP_W * 0.5 - 30, DISP_W * 0.5); + hal->gfx()->setTextCursor(DISP_W / 2 - 30, DISP_W / 2); + OswTime oswTime = { }; + hal->getLocalTime(oswTime); - hal->getLocalTime(&hour, &minute, &second, &afterNoon); - - timeDisplay(hour, minute, second); + timeDisplay(oswTime.hour, oswTime.minute, oswTime.second); if (!OswConfigAllKeys::timeFormat.get()) { hal->gfx()->setTextCursor(215, 130); - if (afterNoon) { + if (oswTime.afterNoon) { hal->gfx()->print(pm); } else { hal->gfx()->print(am); @@ -95,44 +95,44 @@ void OswAppWatchfaceFitness::showFitnessTracking() { uint32_t distTarget = OswConfigAllKeys::distPerDay.get(); uint32_t kcalTarget = OswConfigAllKeys::kcalPerDay.get(); - hal->gfx()->drawArc(DISP_W * 0.5, DISP_H * 0.5, 180, 360, 90, 93, 7, changeColor(ui->getDangerColor(), 0.25)); - // hal->gfx()->drawArc(DISP_W * 0.5, DISP_H * 0.5, 180, 280, 90, 93, 7, dimColor(rgb565(210, 50, 66), 25)); - hal->gfx()->drawArc(DISP_W * 0.5, DISP_H * 0.5, 180, 180 + (180.0 * (float)(steps % stepsTarget) / (float)stepsTarget), 90, 93, 6, steps > stepsTarget ? changeColor(ui->getSuccessColor(),6.25 ): ui->getDangerColor(), true); + hal->gfx()->drawArc(DISP_W / 2, DISP_H / 2, 180, 360, 90, 93, 7, changeColor(ui->getDangerColor(), 0.25f)); + // hal->gfx()->drawArc(DISP_W / 2, DISP_H / 2, 180, 280, 90, 93, 7, dimColor(rgb565(210, 50, 66), 25)); + hal->gfx()->drawArc(DISP_W / 2, DISP_H / 2, 180, 180 + (180.0f * (float)(steps % stepsTarget) / (float)stepsTarget), 90, 93, 6, steps > stepsTarget ? changeColor(ui->getSuccessColor(),6.25f ): ui->getDangerColor(), true); - hal->gfx()->drawArc(DISP_W * 0.5, DISP_H * 0.5, 180, 360, 90, 75, 7, changeColor(ui->getWarningColor(), 0.25)); - // hal->gfx()->drawArc(DISP_W * 0.5, DISP_H * 0.5, 180, 180+128, 90, 75, 7, dimColor(rgb565(117, 235, 10), 25)); - hal->gfx()->drawArc(DISP_W * 0.5, DISP_H * 0.5, 180, 180 + (180.0 * (float)(kcals % kcalTarget) / (float)kcalTarget), 90, 75, 6, kcals > kcalTarget ? changeColor(ui->getSuccessColor(),1.25): ui->getWarningColor(), true); + hal->gfx()->drawArc(DISP_W / 2, DISP_H / 2, 180, 360, 90, 75, 7, changeColor(ui->getWarningColor(), 0.25f)); + // hal->gfx()->drawArc(DISP_W / 2, DISP_H / 2, 180, 180+128, 90, 75, 7, dimColor(rgb565(117, 235, 10), 25)); + hal->gfx()->drawArc(DISP_W / 2, DISP_H / 2, 180, 180 + (180.0f * (float)(kcals % kcalTarget) / (float)kcalTarget), 90, 75, 6, kcals > kcalTarget ? changeColor(ui->getSuccessColor(),1.25f): ui->getWarningColor(), true); - hal->gfx()->drawArc(DISP_W * 0.5, DISP_H * 0.5, 180, 360, 90, 57, 7, changeColor(ui->getInfoColor(), 0.25)); - // hal->gfx()->drawArc(DISP_W * 0.5, DISP_H * 0.5, 180, 180+32, 90, 57, 7, dimColor(rgb565(25, 193, 202), 25)); - hal->gfx()->drawArc(DISP_W * 0.5, DISP_H * 0.5, 180, 180 + (180.0 * (float)(uint32_t(dists) % distTarget) / (float)distTarget), 90, 57, 6, dists > distTarget ? changeColor(ui->getSuccessColor(),2.25) : ui->getInfoColor(), true); + hal->gfx()->drawArc(DISP_W / 2, DISP_H / 2, 180, 360, 90, 57, 7, changeColor(ui->getInfoColor(), 0.25f)); + // hal->gfx()->drawArc(DISP_W / 2, DISP_H / 2, 180, 180+32, 90, 57, 7, dimColor(rgb565(25, 193, 202), 25)); + hal->gfx()->drawArc(DISP_W / 2, DISP_H / 2, 180, 180 + (180.0f * (float)(uint32_t(dists) % distTarget) / (float)distTarget), 90, 57, 6, dists > distTarget ? changeColor(ui->getSuccessColor(),2.25f) : ui->getInfoColor(), true); hal->gfx()->setTextSize(1); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextColor(dimColor(ui->getDangerColor(), 25)); - hal->gfx()->setTextCursor(DISP_W * 0.5 + 10, 25); + hal->gfx()->setTextCursor(DISP_W / 2 + 10, 25); hal->gfx()->print(steps); hal->gfx()->setTextColor(dimColor(ui->getWarningColor(), 25)); - hal->gfx()->setTextCursor(DISP_W * 0.5 + 10, 45); + hal->gfx()->setTextCursor(DISP_W / 2 + 10, 45); hal->gfx()->print(kcals); hal->gfx()->setTextColor(dimColor(ui->getInfoColor(), 25)); - hal->gfx()->setTextCursor(DISP_W * 0.5 + 10, 65); + hal->gfx()->setTextCursor(DISP_W / 2 + 10, 65); hal->gfx()->print(dists); hal->gfx()->setTextColor(dimColor(ui->getInfoColor(), 25)); - hal->gfx()->setTextCursor(DISP_W * 0.5 + 10, DISP_H-65); + hal->gfx()->setTextCursor(DISP_W / 2 + 10, DISP_H-65); hal->gfx()->print(LANG_WATCHFACE_FITNESS_DISTANCE); hal->gfx()->setTextColor(dimColor(ui->getWarningColor(), 25)); - hal->gfx()->setTextCursor(DISP_W * 0.5 + 10, DISP_H-45); + hal->gfx()->setTextCursor(DISP_W / 2 + 10, DISP_H-45); hal->gfx()->print("kcal"); hal->gfx()->setTextColor(dimColor(ui->getDangerColor(), 25)); - hal->gfx()->setTextCursor(DISP_W * 0.5 + 10, DISP_H-25); + hal->gfx()->setTextCursor(DISP_W / 2 + 10, DISP_H-25); hal->gfx()->print(LANG_WATCHFACE_FITNESS_STEP); } @@ -172,4 +172,5 @@ void OswAppWatchfaceFitness::onButton(Button id, bool up, OswAppV2::ButtonStateN OswAppV2::onButton(id, up, state); if(OswAppWatchface::onButtonDefaults(*this, id, up, state)) return; // if the button was handled by the defaults, we are done here -} \ No newline at end of file +} +#endif diff --git a/src/apps/watchfaces/OswAppWatchfaceFitnessAnalog.cpp b/src/apps/watchfaces/OswAppWatchfaceFitnessAnalog.cpp new file mode 100644 index 000000000..828af1862 --- /dev/null +++ b/src/apps/watchfaces/OswAppWatchfaceFitnessAnalog.cpp @@ -0,0 +1,261 @@ +#include "apps/watchfaces/OswAppWatchfaceFitnessAnalog.h" +#include "apps/watchfaces/OswAppWatchfaceDigital.h" +#include "apps/watchfaces/OswAppWatchface.h" + +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 + +#ifdef GIF_BG +#include "./apps/_experiments/gif_player.h" +#endif + +#include +#include +#include +#include +#include +#include + +#define CENTER_X (DISP_W / 2) +#define CENTER_Y (DISP_H / 2) + +inline uint32_t OswAppWatchfaceFitnessAnalog::calculateDistance(uint32_t steps) { + float userHeight = OswConfigAllKeys::configHeight.get(); + float avgDist; + if (userHeight < 180) + avgDist = userHeight * 0.40f; + else + avgDist = userHeight * 0.48f; + + return steps * avgDist * 0.01f; // cm -> m +} + +void OswAppWatchfaceFitnessAnalog::showFitnessTracking(OswHal* hal) { + uint32_t steps = hal->environment()->getStepsToday(); + uint32_t dists = OswAppWatchfaceFitnessAnalog::calculateDistance(steps); + + uint32_t stepsTarget = OswConfigAllKeys::stepsPerDay.get(); + uint32_t distTarget = OswConfigAllKeys::distPerDay.get(); + + uint8_t arcRadius = 6; + uint16_t yellow = rgb565(255, 255,0); + +#ifdef OSW_EMULATOR + steps = 4000; + dists = 3000; +#endif + + { + // draw step arc + int32_t angle_val = 180.0f * (float)min(steps, stepsTarget) / (float)stepsTarget; + uint16_t color = yellow; + uint16_t dimmed_color = changeColor(color, 0.25f); + hal->gfx()->drawCircleAA(CENTER_X, CENTER_Y, 92 +arcRadius, arcRadius*2, dimmed_color, 90, 270-angle_val); + hal->gfx()->drawCircleAA(CENTER_X, CENTER_Y -92, arcRadius, 0, dimmed_color); + + hal->gfx()->drawCircleAA(CENTER_X, CENTER_Y, 92 +arcRadius, arcRadius*2, steps > stepsTarget ? dimmed_color : color, 270-angle_val, 270); + hal->gfx()->drawCircleAA(CENTER_X, CENTER_Y +92, arcRadius, 0, steps > stepsTarget ? dimmed_color : color); + int x = CENTER_X + cosf((270-angle_val)*PI/180) * 92.0f; + int y = CENTER_Y - sinf((270-angle_val)*PI/180) * 92.0f; + hal->gfx()->drawCircleAA(x, y, arcRadius, 0, color); + } + + { + // draw distance arc + int32_t angle_val = 180.0f * (float)min(dists, distTarget) / (float)distTarget; + uint16_t color = ui->getInfoColor(); + uint16_t dimmed_color = changeColor(color, 0.25f); + hal->gfx()->drawCircleAA(CENTER_X, CENTER_Y, 75 +arcRadius, arcRadius*2, dimmed_color, 90, 270-angle_val); + hal->gfx()->drawCircleAA(CENTER_X, CENTER_Y -75, arcRadius, 0, dimmed_color, 0.25f); + + hal->gfx()->drawCircleAA(CENTER_X, CENTER_Y, 75 +arcRadius, arcRadius*2, steps > stepsTarget ? dimmed_color: color, 270-angle_val, 270); + hal->gfx()->drawCircleAA(CENTER_X, CENTER_Y +75, arcRadius, 0, steps > stepsTarget ? dimmed_color: color); + int x = CENTER_X + cosf((270-angle_val)*PI/180) * 75.0f; + int y = CENTER_Y - sinf((270-angle_val)*PI/180) * 75.0f; + hal->gfx()->drawCircleAA(x, y, arcRadius, 0, color); + } + + hal->gfx()->setTextSize(1); + hal->gfx()->setTextLeftAligned(); + + hal->gfx()->setTextColor(dimColor(yellow, 25)); + hal->gfx()->setTextCursor(CENTER_X + 12, 8+23); + hal->gfx()->print(steps); + hal->gfx()->setTextCursor(CENTER_X + 12, DISP_H-23); + hal->gfx()->print(LANG_WATCHFACE_FITNESS_STEP); + + hal->gfx()->setTextColor(dimColor(ui->getInfoColor(), 24)); + hal->gfx()->setTextCursor(CENTER_X + 12, 8+40); + hal->gfx()->print(dists); + hal->gfx()->setTextCursor(CENTER_X + 12, DISP_H-40); + hal->gfx()->print(LANG_WATCHFACE_FITNESS_DISTANCE); +} + +void OswAppWatchfaceFitnessAnalog::drawWatchFace(OswHal* hal, uint32_t hour, uint32_t minute, uint32_t second, bool afterNoon) { + // Indices + hal->gfx()->drawMinuteTicks(CENTER_X, CENTER_Y, 116, 112, ui->getForegroundDimmedColor(), true); + hal->gfx()->drawHourTicks(CENTER_X, CENTER_Y, 117, 107, ui->getForegroundColor(), true); + + // Hours + hal->gfx()->drawThickTick(CENTER_X, CENTER_Y, 0, 16, (int)(360.0f / 12.0f * (hour + minute / 60.0f)), 3, ui->getForegroundColor(), true, STRAIGHT_END); + hal->gfx()->drawThickTick(CENTER_X, CENTER_Y, 16, 60, (int)(360.0f / 12.0f * (hour + minute / 60.0f)), 7, ui->getForegroundColor(), true); + + // Minutes + hal->gfx()->drawThickTick(CENTER_X, CENTER_Y, 0, 16, (int)(360.0f / 60.0f * (minute + second / 60.0f)), 3, ui->getForegroundColor(), true, STRAIGHT_END); + hal->gfx()->drawThickTick(CENTER_X, CENTER_Y, 16, 105, (int)(360.0f / 60.0f * (minute + second / 60.0f)), 7, ui->getForegroundColor(), true); + +#ifndef GIF_BG + // Seconds + hal->gfx()->fillCircleAA(CENTER_X, CENTER_Y, 6, ui->getDangerColor()); + hal->gfx()->drawThickTick(CENTER_X, CENTER_Y, -16, 110, 360 / 60 * second, 3, ui->getDangerColor(), true); +#endif +} + +void OswAppWatchfaceFitnessAnalog::drawDateFace(OswHal* hal, uint32_t hour, uint32_t minute, uint32_t second, bool afterNoon) { + OswDate oswDate = { }; + hal->getLocalDate(oswDate); + + hal->gfx()->setTextSize(2); + hal->gfx()->setTextRightAligned(); + hal->gfx()->setTextCursor(205, 75); + try { + const char* weekday = hal->getWeekDay.at(oswDate.weekDay); + OswAppWatchfaceDigital::displayWeekDay3(weekday); + } catch (const std::out_of_range& ignore) { + OSW_LOG_E("getWeekDay is out of range: ", ignore.what()); + } + + hal->gfx()->setTextSize(3); + hal->gfx()->setTextLeftAligned(); + hal->gfx()->setTextCursor(CENTER_X - 70, 170); + OswAppWatchfaceDigital::dateOutput(oswDate.year, oswDate.month, oswDate.day); + + hal->gfx()->setTextSize(4); + hal->gfx()->setTextLeftAligned(); + hal->gfx()->setTextCursor(CENTER_X - 35, CENTER_Y); + + hal->gfx()->printDecimal(hour, 2); + hal->gfx()->print(":"); + hal->gfx()->printDecimal(minute, 2); + + hal->gfx()->setTextSize(2); + hal->gfx()->setTextLeftAligned(); + hal->gfx()->setTextCursor(215, CENTER_Y); + hal->gfx()->printDecimal(second,2); + + if (!OswConfigAllKeys::timeFormat.get()) { + const char am[] = "AM"; + const char pm[] = "PM"; + hal->gfx()->setTextCursor(215, 130); + if (afterNoon) { + hal->gfx()->print(pm); + } else { + hal->gfx()->print(am); + } + } + +#if OSW_PLATFORM_ENVIRONMENT_TEMPERATURE == 1 + /* + printStatus("Temperature", String(hal->environment()->getTemperature() + String("C")).c_str()); + for(auto& d : *OswTemperatureProvider::getAllTemperatureDevices()) + printStatus((String(" ") + d->getName()).c_str(), String(d->getTemperature() + String("C")).c_str()); + */ + hal->gfx()->setTextSize(2); + hal->gfx()->setTextLeftAligned(); + hal->gfx()->setTextCursor(DISP_W * 0.2f, DISP_H * 0.2f); + hal->gfx()->print(hal->environment()->getTemperature(), 1); + hal->gfx()->print("C"); +#endif +} + +const char* OswAppWatchfaceFitnessAnalog::getAppId() { + return OswAppWatchfaceFitnessAnalog::APP_ID; +} + +const char* OswAppWatchfaceFitnessAnalog::getAppName() { + return LANG_AFIT; +} + +void OswAppWatchfaceFitnessAnalog::onStart() { + OswAppV2::onStart(); + OswAppWatchface::addButtonDefaults(this->knownButtonStates); + + // Report that we support short presses on all buttons + this->knownButtonStates[Button::BUTTON_SELECT] = ButtonStateNames::SHORT_PRESS ; + this->knownButtonStates[Button::BUTTON_UP] = ButtonStateNames::SHORT_PRESS; + this->knownButtonStates[Button::BUTTON_DOWN] = ButtonStateNames::SHORT_PRESS; + + // Here is a snippet to also "support" double presses (on BUTTON_SELECT) - note that this WILL DELAY the reporting of any short press events on that button (as it may needs to wait for the second press) + this->knownButtonStates[Button::BUTTON_SELECT] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[Button::BUTTON_SELECT] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); // OR to set the bit + this->knownButtonStates[Button::BUTTON_UP] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[Button::BUTTON_UP] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); // OR to set the bit + this->knownButtonStates[Button::BUTTON_DOWN] = (OswAppV2::ButtonStateNames) (this->knownButtonStates[Button::BUTTON_DOWN] | OswAppV2::ButtonStateNames::DOUBLE_PRESS); // OR to set the bit + + this->lastTime = time(nullptr); // use +} + +void OswAppWatchfaceFitnessAnalog::onLoop() { + OswAppV2::onLoop(); + + this->needsRedraw = this->needsRedraw or time(nullptr) != this->lastTime; // redraw every second +} + +void OswAppWatchfaceFitnessAnalog::onDraw() { + OswAppV2::onDraw(); + +#ifdef GIF_BG + if(this->bgGif != nullptr) + this->bgGif->loop(); +#endif + + OswHal* hal = OswHal::getInstance(); + + OswTime oswTime = { }; + + if (this->screen == 0) { +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 + showFitnessTracking(hal); +#endif + + drawWatchFace(hal, oswTime.hour, oswTime.minute, oswTime.second, oswTime.afterNoon); + } else if (this->screen == 1) { + drawDateFace(hal, oswTime.hour, oswTime.minute, oswTime.second, oswTime.afterNoon); + + static int wait_time = 1; + if (wait_time >= 0) + --wait_time; + else { + this->screen = 0; + wait_time = 1; + } + } + + this->lastTime = time(nullptr); +} + +void OswAppWatchfaceFitnessAnalog::onButton(Button id, bool up, OswAppV2::ButtonStateNames state) { + OswAppV2::onButton(id, up, state); + + if(!up) return; + + if (state == OswAppV2::ButtonStateNames::DOUBLE_PRESS) { + if (this->screen < 1) + ++this->screen; + return; + } + + if(OswAppWatchface::onButtonDefaults(*this, id, up, state)) + return; // if the button was handled by the defaults, we are done here +} + +void OswAppWatchfaceFitnessAnalog::onStop() { + OswAppV2::onStop(); // always make sure to call the base class method! + // This is where you de-initialize stuff, gets called when another app is shown + +#ifdef GIF_BG + if(this->bgGif != nullptr) { + this->bgGif->stop(); + delete this->bgGif; + this->bgGif = nullptr; + } +#endif +} +#endif diff --git a/src/apps/watchfaces/OswAppWatchfaceMix.cpp b/src/apps/watchfaces/OswAppWatchfaceMix.cpp index ac455c93b..55e9afea3 100644 --- a/src/apps/watchfaces/OswAppWatchfaceMix.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceMix.cpp @@ -23,38 +23,45 @@ const char* OswAppWatchfaceMix::getAppName() { void OswAppWatchfaceMix::analogWatchDisplay() { OswHal* hal = OswHal::getInstance(); - uint32_t second = 0; - uint32_t minute = 0; // Unused, but required by function signature - uint32_t hour = 0; // Unused, but required by function signature + OswTime oswTime = { }; + hal->getLocalTime(oswTime); - hal->getLocalTime(&hour, &minute, &second); hal->gfx()->drawCircle((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, 100, 50, ui->getForegroundColor()); hal->gfx()->drawHourTicks((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, 100, 45, 40, ui->getForegroundDimmedColor()); // hour - hal->gfx()->drawLine((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, 100, rpx((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, (int)(33 * 0.5), hour * 30 + (int)( minute* 0.1 ) * 6), rpy(100, (int)(33 * 0.5), hour * 30 + (int)( minute* 0.1 ) * 6 ), ui->getForegroundColor()); + hal->gfx()->drawLine(DISP_W/2-OFF_SET_ANALOG_WATCH_X_COORD, 100, + rpx(DISP_W/3-OFF_SET_ANALOG_WATCH_X_COORD, 33 / 2, (int32_t) (oswTime.hour * 30 + oswTime.minute/10 * 6)), + rpy(100, 33 / 2, (int32_t)(oswTime.hour * 30 + oswTime.minute/10 * 6)), ui->getForegroundColor()); // minute - hal->gfx()->drawLine((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, 100, rpx((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, (int)(66 * 0.5), minute * 6), rpy(100, (int)(66 * 0.5), minute * 6), ui->getSuccessColor()); + hal->gfx()->drawLine(DISP_W/2-OFF_SET_ANALOG_WATCH_X_COORD, 100, + rpx(DISP_W/2-OFF_SET_ANALOG_WATCH_X_COORD, 66 / 2, (int32_t) oswTime.minute * 6), + rpy(100, 66 / 2, (int32_t)(oswTime.minute * 6)), ui->getSuccessColor()); // second - hal->gfx()->drawLine((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, 100, rpx((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, (int)(15 * 0.5), s2d(second) + 180), rpy(100, (int)(15 * 0.5), s2d(second) + 180), ui->getDangerColor()); // short backwards - hal->gfx()->drawLine((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, 100, rpx((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, (int)(90 * 0.5), s2d(second)), rpy(100, (int)(90 * 0.5), s2d(second)), ui->getDangerColor()); // long front + hal->gfx()->drawLine(DISP_W/2-OFF_SET_ANALOG_WATCH_X_COORD, 100, + rpx(DISP_W/2-OFF_SET_ANALOG_WATCH_X_COORD, 15 / 2, s2d(oswTime.second) + 180), + rpy(100, (int)(15 * 0.5f), s2d(oswTime.second) + 180), ui->getDangerColor()); // short backwards + hal->gfx()->drawLine(DISP_W/2-OFF_SET_ANALOG_WATCH_X_COORD, 100, + rpx(DISP_W/2-OFF_SET_ANALOG_WATCH_X_COORD, 90 / 2, s2d(oswTime.second)), + rpy(100, (int)(90 * 0.5f), s2d(oswTime.second)), ui->getDangerColor()); // long front } void OswAppWatchfaceMix::dateDisplay() { - uint32_t dayInt = 0; - uint32_t monthInt = 0; - uint32_t yearInt = 0; OswHal* hal = OswHal::getInstance(); - const char* weekday = hal->getLocalWeekday(); - hal->getLocalDate(&dayInt, &monthInt, &yearInt); + OswDate oswDate = { }; + hal->getLocalDate(oswDate); hal->gfx()->setTextSize(1); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextCursor(DISP_W / 2 - OFF_SET_DATE_DIGITAL_WATCH_X_COORD, 75); - - OswAppWatchfaceDigital::displayWeekDay3(weekday); + try { + const char* weekday = hal->getWeekDay.at(oswDate.weekDay); + OswAppWatchfaceDigital::displayWeekDay3(weekday); + } catch (const std::out_of_range& ignore) { + OSW_LOG_E("getWeekDay is out of range: ", ignore.what()); + } hal->gfx()->print(", "); @@ -64,14 +71,10 @@ void OswAppWatchfaceMix::dateDisplay() { hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextCursor(DISP_W / 2 - OFF_SET_DATE_DIGITAL_WATCH_X_COORD, 90); - OswAppWatchfaceDigital::dateOutput(yearInt, monthInt, dayInt); + OswAppWatchfaceDigital::dateOutput(oswDate.year, oswDate.month, oswDate.day); } void OswAppWatchfaceMix::digitalWatchDisplay() { - uint32_t second = 0; - uint32_t minute = 0; - uint32_t hour = 0; - bool afterNoon = false; char am[] = "AM"; char pm[] = "PM"; OswHal* hal = OswHal::getInstance(); @@ -81,18 +84,19 @@ void OswAppWatchfaceMix::digitalWatchDisplay() { hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextCursor(DISP_W / 2 - OFF_SET_DATE_DIGITAL_WATCH_X_COORD, DISP_H / 2); - hal->getLocalTime(&hour, &minute, &second, &afterNoon); - OswAppWatchfaceDigital::timeOutput(hour, minute, second,false); + OswTime oswTime = { }; + hal->getLocalTime(oswTime); + OswAppWatchfaceDigital::timeOutput(oswTime.hour, oswTime.minute, oswTime.second, false); if (!OswConfigAllKeys::timeFormat.get()) { hal->gfx()->setTextSize(1); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextBottomAligned(); hal->gfx()->setTextSize(3); - hal->gfx()->setTextCursor(DISP_W / 2 - OFF_SET_DATE_DIGITAL_WATCH_X_COORD + hal->gfx()->getTextOfsetColumns(5.25), 130); + hal->gfx()->setTextCursor(DISP_W / 2 - OFF_SET_DATE_DIGITAL_WATCH_X_COORD + hal->gfx()->getTextOfsetColumns(5.25f), 130); hal->gfx()->setTextSize(1); hal->gfx()->print(" "); - if (afterNoon) { + if (oswTime.afterNoon) { hal->gfx()->print(pm); } else { hal->gfx()->print(am); @@ -128,4 +132,4 @@ void OswAppWatchfaceMix::onButton(Button id, bool up, OswAppV2::ButtonStateNames OswAppV2::onButton(id, up, state); if(OswAppWatchface::onButtonDefaults(*this, id, up, state)) return; // if the button was handled by the defaults, we are done here -} \ No newline at end of file +} diff --git a/src/apps/watchfaces/OswAppWatchfaceMonotimer.cpp b/src/apps/watchfaces/OswAppWatchfaceMonotimer.cpp index d10b1503e..359e88f35 100644 --- a/src/apps/watchfaces/OswAppWatchfaceMonotimer.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceMonotimer.cpp @@ -25,7 +25,7 @@ * @param color color code */ void OswAppWatchfaceMonotimer::drawNShiftedTicks(Graphics2D* gfx, uint8_t cx, uint8_t cy, uint8_t r1, uint8_t r2, uint8_t nTicks, float shift, uint16_t color) { - float deltaAngle = 360.0 / nTicks; + float deltaAngle = 360.0f / nTicks; for (uint16_t i=0; idrawTick(cx, cy, r1, r2, (i * deltaAngle) + shift, color); } @@ -44,7 +44,7 @@ void OswAppWatchfaceMonotimer::drawNShiftedTicks(Graphics2D* gfx, uint8_t cx, ui * @param color color code */ void OswAppWatchfaceMonotimer::drawNShiftedMaskedTicks(Graphics2D* gfx, uint8_t cx, uint8_t cy, uint8_t r1, uint8_t r2, uint8_t nTicks, float shift, uint16_t m, uint16_t color) { - float deltaAngle = 360.0 / nTicks; + float deltaAngle = 360.0f / nTicks; for (uint16_t i=0; idrawTick(cx, cy, r1, r2, (i * deltaAngle) + shift, color); @@ -79,11 +79,11 @@ void OswAppWatchfaceMonotimer::drawWatch() { // hours hal->gfx()->drawNTicks(120, 120, 117, 100, 12, ui->getForegroundColor()); // 30 minutes - drawNShiftedTicks(hal->gfx(), 120, 120, 117, 105, 12, 360.0/24.0, ui->getForegroundColor()); + drawNShiftedTicks(hal->gfx(), 120, 120, 117, 105, 12, 360.0f/24.0f, ui->getForegroundColor()); // 15 minutes - drawNShiftedTicks(hal->gfx(), 120, 120, 110, 105, 24, 360.0/48.0, ui->getForegroundColor()); + drawNShiftedTicks(hal->gfx(), 120, 120, 110, 105, 24, 360.0f/48.0f, ui->getForegroundColor()); // 5 minutes - drawNShiftedMaskedTicks(hal->gfx(), 120, 120, 109, 108, 144, 0.0, 3, ui->getForegroundColor()); + drawNShiftedMaskedTicks(hal->gfx(), 120, 120, 109, 108, 144, 0.0f, 3, ui->getForegroundColor()); // hour labels hal->gfx()->setTextSize(2); @@ -104,21 +104,17 @@ void OswAppWatchfaceMonotimer::drawWatch() { #endif // ticks - uint32_t second = 0; - uint32_t minute = 0; - uint32_t hour = 0; - hal->getLocalTime(&hour, &minute, &second); + OswTime oswTime = { }; + hal->getLocalTime(oswTime); if (OswConfigAllKeys::settingDisplayDualHourTick.get()) { - uint32_t dualSecond = 0; - uint32_t dualMinute = 0; - uint32_t dualHour = 0; - hal->getDualTime(&dualHour, &dualMinute, &dualSecond); + OswTime oswDualTime = { }; + hal->getDualTime(oswDualTime); - hal->gfx()->drawThickTick(120, 120, 0, 105, (360.0 * (60 * dualHour + dualMinute)) / 720.0, 1, ui->getBackgroundDimmedColor()); + hal->gfx()->drawThickTick(120, 120, 0, 105, (360.0f * (60 * oswDualTime.hour + oswDualTime.minute)) / 720.0f, 1, ui->getBackgroundDimmedColor()); } - hal->gfx()->drawThickTick(120, 120, 0, 105, (360.0 * (60 * hour + minute)) / 720.0, 1, ui->getForegroundColor()); + hal->gfx()->drawThickTick(120, 120, 0, 105, (360.0f * (60 * oswTime.hour + oswTime.minute)) / 720.0f, 1, ui->getForegroundColor()); hal->gfx()->fillEllipse(120, 120, 4, 4, ui->getForegroundColor()); } @@ -172,4 +168,4 @@ void OswAppWatchfaceMonotimer::onButton(Button id, bool up, OswAppV2::ButtonStat OswAppV2::onButton(id, up, state); if(OswAppWatchface::onButtonDefaults(*this, id, up, state)) return; // if the button was handled by the defaults, we are done here -} \ No newline at end of file +} diff --git a/src/apps/watchfaces/OswAppWatchfaceNumerals.cpp b/src/apps/watchfaces/OswAppWatchfaceNumerals.cpp index f228c38e1..5dd604416 100644 --- a/src/apps/watchfaces/OswAppWatchfaceNumerals.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceNumerals.cpp @@ -22,8 +22,8 @@ const char* OswAppWatchfaceNumerals::getAppName() { void OswAppWatchfaceNumerals::drawWatch() { OswHal* hal = OswHal::getInstance(); - hal->gfx()->drawMinuteTicks(DISP_W * 0.5, DISP_H * 0.5, 116, 112, ui->getForegroundDimmedColor()); - hal->gfx()->drawHourTicks(DISP_W * 0.5, DISP_H * 0.5, 117, 107, ui->getForegroundColor()); + hal->gfx()->drawMinuteTicks(DISP_W / 2, DISP_H / 2, 116, 112, ui->getForegroundDimmedColor()); + hal->gfx()->drawHourTicks(DISP_W / 2, DISP_H / 2, 117, 107, ui->getForegroundColor()); // hour labels hal->gfx()->setTextSize(1); @@ -33,19 +33,21 @@ void OswAppWatchfaceNumerals::drawWatch() { OswAppWatchfaceMonotimer::drawHour(); - uint32_t dayInt = 0; - uint32_t monthInt = 0; - uint32_t yearInt = 0; - hal->getLocalDate(&dayInt, &monthInt, &yearInt); + OswDate oswDate = { }; + hal->getLocalDate(oswDate); + hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextSize(1); hal->gfx()->setTextColor(ui->getDangerColor()); hal->gfx()->setTextCursor(120, 85); - hal->gfx()->print(dayInt); - - const char* weekday = hal->getLocalWeekday(); + hal->gfx()->print(oswDate.day); hal->gfx()->setTextCursor(120, 70); - OswAppWatchfaceDigital::displayWeekDay3(weekday); + try { + const char* weekday = hal->getWeekDay.at(oswDate.weekDay); + OswAppWatchfaceDigital::displayWeekDay3(weekday); + } catch (const std::out_of_range& ignore) { + OSW_LOG_E("getWeekDay is out of range: ", ignore.what()); + } #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 uint32_t steps = hal->environment()->getStepsToday(); @@ -61,34 +63,30 @@ void OswAppWatchfaceNumerals::drawWatch() { #endif // ticks - uint32_t second = 0; - uint32_t minute = 0; - uint32_t hour = 0; - hal->getLocalTime(&hour, &minute, &second); + OswTime oswTime = { }; + hal->getLocalTime(oswTime); if(OswConfigAllKeys::settingDisplayDualHourTick.get()) { - uint32_t dualSecond = 0; - uint32_t dualMinute = 0; - uint32_t dualHour = 0; - hal->getDualTime(&dualHour, &dualMinute, &dualSecond); + OswTime oswDualTime = { }; + hal->getDualTime(oswDualTime); // dual-hours - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 0, 16, 360.0 / 12.0 * (1.0 * dualHour + dualMinute / 60.0), 2, ui->getBackgroundDimmedColor()); - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 16, 60, 360.0 / 12.0 * (1.0 * dualHour + dualMinute / 60.0), 5, ui->getBackgroundDimmedColor()); + hal->gfx()->drawThickTick(DISP_W / 2, DISP_H / 2, 0, 16, 360.0f / 12.0f * (oswDualTime.hour + oswDualTime.minute / 60.0f), 2, ui->getBackgroundDimmedColor()); + hal->gfx()->drawThickTick(DISP_W / 2, DISP_H / 2, 16, 60, 360.0f / 12.0f * (oswDualTime.hour + oswDualTime.minute / 60.0f), 5, ui->getBackgroundDimmedColor()); } // hours - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 0, 16, 360.0 / 12.0 * (1.0 * hour + minute / 60.0), 1, ui->getForegroundColor()); - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 16, 60, 360.0 / 12.0 * (1.0 * hour + minute / 60.0), 4, ui->getForegroundColor()); + hal->gfx()->drawThickTick(DISP_W / 2, DISP_H / 2, 0, 16, 360.0f / 12.0f * (oswTime.hour + oswTime.minute / 60.0f), 1, ui->getForegroundColor()); + hal->gfx()->drawThickTick(DISP_W / 2, DISP_H / 2, 16, 60, 360.0f / 12.0f * (oswTime.hour + oswTime.minute / 60.0f), 4, ui->getForegroundColor()); // minutes - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 0, 16, 360.0 / 60.0 * (1.0 * minute + second / 60.0), 1, ui->getForegroundColor()); - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 16, 80, 360.0 / 60.0 * (1.0 * minute + second / 60.0), 4, ui->getForegroundColor()); + hal->gfx()->drawThickTick(DISP_W / 2, DISP_H / 2, 0, 16, 360.0f / 60.0f * (oswTime.minute + oswTime.second / 60.0f), 1, ui->getForegroundColor()); + hal->gfx()->drawThickTick(DISP_W / 2, DISP_H / 2, 16, 80, 360.0f / 60.0f * (oswTime.minute + oswTime.second / 60.0f), 4, ui->getForegroundColor()); #ifndef GIF_BG // seconds - hal->gfx()->fillCircle(DISP_W * 0.5, DISP_H * 0.5, 3, ui->getDangerColor()); - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 0, 16, 180 + ( 360.0 / 60.0 * second ), 1, ui->getDangerColor()); - hal->gfx()->drawThickTick(DISP_W * 0.5, DISP_H * 0.5, 0, 105, 360.0 / 60.0 * second, 1, ui->getDangerColor()); + hal->gfx()->fillCircle(DISP_W / 2, DISP_H / 2, 3, ui->getDangerColor()); + hal->gfx()->drawThickTick(DISP_W / 2, DISP_H / 2, 0, 16, 180 + ( 360.0f / 60.0f * oswTime.second ), 1, ui->getDangerColor()); + hal->gfx()->drawThickTick(DISP_W / 2, DISP_H / 2, 0, 105, 360.0f / 60.0f * oswTime.second, 1, ui->getDangerColor()); #endif } diff --git a/src/devices/OswDevice.cpp b/src/devices/OswDevice.cpp index 6d1ebe65b..d770f9125 100644 --- a/src/devices/OswDevice.cpp +++ b/src/devices/OswDevice.cpp @@ -8,4 +8,4 @@ OswDevice::OswDevice() { OswDevice::~OswDevice() { this->allDevices.erase(this); -}; \ No newline at end of file +}; diff --git a/src/devices/bma400.cpp b/src/devices/bma400.cpp index 478c39e25..b987bed58 100644 --- a/src/devices/bma400.cpp +++ b/src/devices/bma400.cpp @@ -1,16 +1,12 @@ #ifndef OSW_EMULATOR +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_HARDWARE_BMA400 == 1 #include -#include #include - +#include +#include #include -// #include "BlueDot_BMA400.h" -// #include "bma400_defs.h" -#include "bma400.h" -#include -#include "osw_pins.h" - // Earth's gravity in m/s^2 #define GRAVITY_EARTH (9.80665f) @@ -18,12 +14,6 @@ #define SENSOR_TICK_TO_S (0.0000390625f) #define READ_WRITE_LENGTH UINT8_C(46) -struct bma400_dev bma; -float accelT = 0, accelX = 0, accelY = 0, accelZ = 0; - -static uint8_t dev_addr; -uint8_t act_int; -uint32_t step_count = 0; static float lsb_to_ms2(int16_t accel_data, uint8_t g_range, uint8_t bit_width) { float accel_ms2; @@ -35,43 +25,35 @@ static float lsb_to_ms2(int16_t accel_data, uint8_t g_range, uint8_t bit_width) return accel_ms2; } -void bma400_delay_us(uint32_t period, void* intf_ptr) { +static void bma400_delay_us(uint32_t period, void* intf_ptr) { delayMicroseconds(period); } -void bma400_check_rslt(const char api_name[], int8_t rslt) { - String prefix; - if (rslt != BMA400_OK) { - prefix = api_name; - prefix += ": "; - } - +static void bma400_check_rslt(const char api_name[], int8_t rslt) { switch (rslt) { case BMA400_OK: - // OSW_LOG_I(prefix, "BMA400 OK"); /* Do nothing */ break; case BMA400_E_NULL_PTR: - OSW_LOG_E(prefix, "Error [", rslt, "] : Null pointer"); + OSW_LOG_E(api_name, ": Error [", rslt, "] : Null pointer"); break; case BMA400_E_COM_FAIL: - OSW_LOG_E(prefix, "Error [", rslt, "] : Communication failure"); + OSW_LOG_E(api_name, ": Error [", rslt, "] : Communication failure"); break; case BMA400_E_INVALID_CONFIG: - OSW_LOG_E(prefix, "Error [", rslt, "] : Invalid configuration"); + OSW_LOG_E(api_name, ": Error [", rslt, "] : Invalid configuration"); break; case BMA400_E_DEV_NOT_FOUND: - OSW_LOG_E(prefix, "Error [", rslt, "] : Device not found"); + OSW_LOG_E(api_name, ": Error [", rslt, "] : Device not found"); break; default: - OSW_LOG_E(prefix, "Error [", rslt, "] : Unknown error code"); + OSW_LOG_E(api_name, ": Error [", rslt, "] : Unknown error code"); break; } } -BMA400_INTF_RET_TYPE bma400_i2c_read(uint8_t reg_addr, uint8_t* reg_data, uint32_t len, void* intf_ptr) { - uint8_t dev_addr = *(uint8_t*)intf_ptr; - Wire.beginTransmission(dev_addr); +static BMA400_INTF_RET_TYPE bma400_i2c_read(uint8_t reg_addr, uint8_t* reg_data, uint32_t len, void* intf_ptr) { + Wire.beginTransmission(*(uint8_t*)intf_ptr); if (!Wire.write(reg_addr)) { return 1; } @@ -80,7 +62,7 @@ BMA400_INTF_RET_TYPE bma400_i2c_read(uint8_t reg_addr, uint8_t* reg_data, uint32 // if (!) { // return 2; // } - if (!Wire.requestFrom(dev_addr, len)) { + if (!Wire.requestFrom(*(uint8_t*)intf_ptr, len)) { return 3; } for (uint32_t i = 0; i < len; i++) { @@ -95,10 +77,9 @@ BMA400_INTF_RET_TYPE bma400_i2c_read(uint8_t reg_addr, uint8_t* reg_data, uint32 return 0; } -BMA400_INTF_RET_TYPE bma400_i2c_write(uint8_t reg_addr, const uint8_t* reg_data, uint32_t len, void* intf_ptr) { - uint8_t dev_addr = *(uint8_t*)intf_ptr; +static BMA400_INTF_RET_TYPE bma400_i2c_write(uint8_t reg_addr, const uint8_t* reg_data, uint32_t len, void* intf_ptr) { // TODO: catch errors - Wire.beginTransmission(dev_addr); + Wire.beginTransmission(*(uint8_t*)intf_ptr); if (!Wire.write(reg_addr)) { return 1; } @@ -115,37 +96,7 @@ BMA400_INTF_RET_TYPE bma400_i2c_write(uint8_t reg_addr, const uint8_t* reg_data, return 0; } -int8_t bma400_interface_init(struct bma400_dev* bma400, uint8_t intf) { - int8_t rslt = BMA400_OK; - - if (bma400 != NULL) { - // delay(100); - - if (intf == BMA400_I2C_INTF) { - dev_addr = BMA400_I2C_ADDRESS_SDO_LOW; - bma400->read = bma400_i2c_read; - bma400->write = bma400_i2c_write; - bma400->intf = BMA400_I2C_INTF; - } - /* Bus configuration : SPI */ - else if (intf == BMA400_SPI_INTF) { - // not supported on open smartwatch - rslt = BMA400_E_NULL_PTR; - } - - bma400->intf_ptr = &dev_addr; - bma400->delay_us = bma400_delay_us; - bma400->read_write_len = READ_WRITE_LENGTH; - - // delay(200); - } else { - rslt = BMA400_E_NULL_PTR; - } - - return rslt; -} - -void setupTiltToWake() { +void OswDevices::BMA400::setupTiltToWake() { int8_t rslt = 0; // get current state of 0x1F register "load interrupt config part 0" @@ -204,10 +155,11 @@ void setupTiltToWake() { rslt = bma400_set_regs(0x21, ®Set, 1, &bma); } -void IRAM_ATTR isrStep() { +static void IRAM_ATTR isrStep() { OSW_LOG_D("Step"); } -void IRAM_ATTR isrTap() { + +static void IRAM_ATTR isrTap() { // check which interrupt fired // TODO: read INT_STAT0,INT_STAT1,INT_STAT2 @@ -215,10 +167,9 @@ void IRAM_ATTR isrTap() { } void OswDevices::BMA400::resetStepCount() { - int8_t rslt = bma400_soft_reset(&bma); - bma400_check_rslt("bma400_soft_reset", rslt); - step_count = 0; - this->setup(); + uint8_t resetStepCommand = 0xb1; + bma400_set_regs(BMA400_REG_COMMAND, &resetStepCommand, sizeof(resetStepCommand), &bma); + this->step_count = 0; } void OswDevices::BMA400::setup() { @@ -228,11 +179,20 @@ void OswDevices::BMA400::setup() { attachInterrupt(OSW_DEVICE_BMA400_INT2, isrStep, FALLING); int8_t rslt = 0; + static uint8_t device_address = BMA400_I2C_ADDRESS_SDO_LOW; // required for use via pointer struct bma400_sensor_conf accel_setting[3] = {{}}; struct bma400_int_enable int_en[3]; - rslt = bma400_interface_init(&bma, BMA400_I2C_INTF); - bma400_check_rslt("bma400_interface_init", rslt); + // simplified bma400_interface_init function + { + bma.read = bma400_i2c_read; + bma.write = bma400_i2c_write; + bma.intf = BMA400_I2C_INTF; + + bma.intf_ptr = (void*) &device_address; // nullptr is not recognized for default with this library + bma.delay_us = bma400_delay_us; + bma.read_write_len = READ_WRITE_LENGTH; + } rslt = bma400_init(&bma); bma400_check_rslt("bma400_init", rslt); @@ -286,6 +246,7 @@ void OswDevices::BMA400::setup() { } void OswDevices::BMA400::update() { + uint8_t act_int; int8_t rslt = BMA400_OK; struct bma400_sensor_data data; @@ -295,13 +256,29 @@ void OswDevices::BMA400::update() { rslt = bma400_get_accel_data(BMA400_DATA_SENSOR_TIME, &data, &bma); bma400_check_rslt("bma400_get_accel_data", rslt); - /* 12-bit accelerometer at range 2G */ + // 12-bit accelerometer at range 2G accelX = lsb_to_ms2(data.x, 2, 12); accelY = lsb_to_ms2(data.y, 2, 12); accelZ = lsb_to_ms2(data.z, 2, 12); // TODO: add getter accelT = (float)data.sensortime * SENSOR_TICK_TO_S; + + // activity mode + switch(act_int) { + case BMA400_STILL_ACT: + this->activityMode = OswAccelerationProvider::ActivityMode::STILL; + break; + case BMA400_WALK_ACT: + this->activityMode = OswAccelerationProvider::ActivityMode::WALK; + break; + case BMA400_RUN_ACT: + this->activityMode = OswAccelerationProvider::ActivityMode::RUN; + break; + default: + this->activityMode = OswAccelerationProvider::ActivityMode::UNKNOWN; + break; + } } float OswDevices::BMA400::getAccelerationX() { @@ -333,13 +310,15 @@ float OswDevices::BMA400::getTemperature() { int16_t temperature; rslt = bma400_get_temperature_data(&temperature, &bma); bma400_check_rslt("bma400_get_temperature_data", rslt); - return temperature / 10; + return temperature / 10.0f; } uint32_t OswDevices::BMA400::getStepCount() { return step_count; } -uint8_t OswDevices::BMA400::getActivityMode() { - return act_int; + +OswAccelerationProvider::ActivityMode OswDevices::BMA400::getActivityMode() { + return this->activityMode; } -#endif \ No newline at end of file +#endif +#endif diff --git a/src/devices/bme280.cpp b/src/devices/bme280.cpp index 5b1767bc3..461e6b4d1 100644 --- a/src/devices/bme280.cpp +++ b/src/devices/bme280.cpp @@ -43,4 +43,4 @@ float OswDevices::BME280::getTemperature() { float OswDevices::BME280::getHumidity() { return _hum; } -#endif \ No newline at end of file +#endif diff --git a/src/devices/bmi270.cpp b/src/devices/bmi270.cpp new file mode 100644 index 000000000..8cccfe003 --- /dev/null +++ b/src/devices/bmi270.cpp @@ -0,0 +1,230 @@ +#ifndef OSW_EMULATOR +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_HARDWARE_BMI270 == 1 +#include +#include +#include + +#include + +static int8_t bmi2_i2c_read(uint8_t reg_addr, uint8_t* reg_data, uint32_t len, void* intf_ptr) { + if ((reg_data == NULL) || (len == 0) || (len > 32)) { + return -1; + } + uint8_t bytes_received; + + Wire.beginTransmission(BMI2_I2C_PRIM_ADDR); + Wire.write(reg_addr); + if (Wire.endTransmission() == 0) { + bytes_received = Wire.requestFrom(BMI2_I2C_PRIM_ADDR, len); + // Optionally, throw an error if bytes_received != len + for (uint16_t i = 0; i < bytes_received; i++) { + reg_data[i] = Wire.read(); + } + } else { + return -1; + } + + return 0; +} + +static int8_t bmi2_i2c_write(uint8_t reg_addr, const uint8_t* reg_data, uint32_t len, void* intf_ptr) { + if ((reg_data == NULL) || (len == 0) || (len > 32)) { + return -1; + } + + Wire.beginTransmission(BMI2_I2C_PRIM_ADDR); + Wire.write(reg_addr); + for (uint16_t i = 0; i < len; i++) { + Wire.write(reg_data[i]); + } + if (Wire.endTransmission() != 0) { + return -1; + } + + return 0; +} + +static void bmi2_delay_us(uint32_t period, void* intf_ptr) { + delayMicroseconds(period); +} + +void OswDevices::BMI270::setup() { + int8_t rslt; + { + this->bmi2.chip_id = BMI2_I2C_PRIM_ADDR; + this->bmi2.read = bmi2_i2c_read; + this->bmi2.write = bmi2_i2c_write; + this->bmi2.delay_us = bmi2_delay_us; + this->bmi2.intf = BMI2_I2C_INTF; + this->bmi2.intf_ptr = nullptr; // we are using the default address anyways + this->bmi2.read_write_len = 30; // Bosch mentioned limitations of the "Wire library" + this->bmi2.config_file_ptr = nullptr; // we are not using a config file + + rslt = bmi270_init(&this->bmi2); + if(rslt != BMI2_OK) + throw std::runtime_error("Failed to initialize BMI270!"); + } + + { + struct bmi2_int_pin_config int_pin_cfg; + int_pin_cfg.pin_type = BMI2_INT1; + int_pin_cfg.int_latch = BMI2_INT_NON_LATCH; + int_pin_cfg.pin_cfg[0].lvl = BMI2_INT_ACTIVE_HIGH; + int_pin_cfg.pin_cfg[0].od = BMI2_INT_PUSH_PULL; + int_pin_cfg.pin_cfg[0].output_en = BMI2_INT_OUTPUT_ENABLE; + int_pin_cfg.pin_cfg[0].input_en = BMI2_INT_INPUT_DISABLE; + + struct bmi2_sens_config sens_cfg[2]; + sens_cfg[0].type = BMI2_ACCEL; + sens_cfg[0].cfg.acc.bwp = BMI2_ACC_OSR2_AVG2; + sens_cfg[0].cfg.acc.odr = BMI2_ACC_ODR_100HZ; + sens_cfg[0].cfg.acc.filter_perf = BMI2_PERF_OPT_MODE; + sens_cfg[0].cfg.acc.range = BMI2_ACC_RANGE_4G; + sens_cfg[1].type = BMI2_GYRO; + sens_cfg[1].cfg.gyr.filter_perf = BMI2_PERF_OPT_MODE; + sens_cfg[1].cfg.gyr.bwp = BMI2_GYR_OSR2_MODE; + sens_cfg[1].cfg.gyr.odr = BMI2_GYR_ODR_100HZ; + sens_cfg[1].cfg.gyr.range = BMI2_GYR_RANGE_2000; + sens_cfg[1].cfg.gyr.ois_range = BMI2_GYR_OIS_2000; + + rslt = bmi2_set_int_pin_config(&int_pin_cfg, &this->bmi2); + if (rslt != BMI2_OK) + throw std::runtime_error("Failed configure pins of BMI270!"); + + rslt = bmi2_map_data_int(BMI2_DRDY_INT, BMI2_INT1, &this->bmi2); + if (rslt != BMI2_OK) + throw std::runtime_error("Failed to map data interrupt of BMI270!"); + + rslt = bmi2_set_sensor_config(sens_cfg, 2, &this->bmi2); + if (rslt != BMI2_OK) + throw std::runtime_error("Failed to configure sensors of BMI270!"); + + uint8_t cmndSetFeaturePage = 6; + if(bmi2_set_regs(0x2F, &cmndSetFeaturePage, sizeof(cmndSetFeaturePage), &this->bmi2) < 0) + throw std::runtime_error("Failed to set configuration page of BMI270!"); + + uint8_t cmnd[2] = { 0x00, 0x10 | 0x20 }; // ...; enable counter, enable activity + if(bmi2_set_regs(0x32, cmnd, sizeof(cmnd), &this->bmi2) < 0) + throw std::runtime_error("Failed to configure step counter of BMI270!"); + + uint8_t sens_list[2] = { BMI2_ACCEL, BMI2_GYRO }; + rslt = bmi2_sensor_enable(sens_list, 2, &this->bmi2); + if (rslt != BMI2_OK) + throw std::runtime_error("Failed to enable sensors of BMI270!"); + } + + // We are NOT initializing the IMM150, because there is no hardware with it ;) +} + +void OswDevices::BMI270::update() { + this->updateAcceleration(); + this->updateSteps(); + this->updateTemperature(); + this->updateActivityMode(); +} + +void OswDevices::BMI270::updateAcceleration() { + int8_t rslt; + struct bmi2_sens_data sensor_data; + + rslt = bmi2_get_sensor_data(&sensor_data, &this->bmi2); + if (rslt != BMI2_OK) { + OSW_LOG_E("BMI270 Acceleration read error (SPI error)"); + return; + } + + this->accX = (float) sensor_data.acc.x / 1000; + this->accY = (float) sensor_data.acc.y / 1000; + this->accZ = (float) sensor_data.acc.z / 1000; +} + +void OswDevices::BMI270::updateSteps() { + uint8_t data[2]; + if (bmi2_get_regs(0x1E, data, sizeof(data), &this->bmi2) < 0) { + OSW_LOG_E("BMI270 Steps read error"); + return; + } + + this->step_count = (data[1] << 8) | data[0]; +} + +void OswDevices::BMI270::updateTemperature() { + uint8_t data[2]; + if (bmi2_get_regs(0x22, data, sizeof(data), &this->bmi2) < 0) { + OSW_LOG_E("BMI270 Temperature read error"); + return; + } + + int16_t temp = (data[1] << 8) | data[0]; + + if(temp == 0x8000) { + OSW_LOG_E("BMI270 Temperature read error (value error)"); + return; + } + + this->temperature = temp / 100.0f; +} + +void OswDevices::BMI270::updateActivityMode() { + uint8_t data; + if (bmi2_get_regs(0x20, &data, sizeof(data), &this->bmi2) < 0) { + OSW_LOG_E("BMI270 Activity mode read error"); + return; + } + data = data >> 2; // drop the first two bytes by shifting to the right + data = data & 0x03; // drop the last 6 bytes by masking + + switch(data) { + case 0x00: + this->activityMode = OswAccelerationProvider::ActivityMode::STILL; + break; + case 0x01: + this->activityMode = OswAccelerationProvider::ActivityMode::WALK; + break; + case 0x02: + this->activityMode = OswAccelerationProvider::ActivityMode::RUN; + break; + default: + this->activityMode = OswAccelerationProvider::ActivityMode::UNKNOWN; // also known as 0x03 + break; + } +} + +float OswDevices::BMI270::getAccelerationX() { + return this->accX; +} + +float OswDevices::BMI270::getAccelerationY() { + return this->accY; +} + +float OswDevices::BMI270::getAccelerationZ() { + return this->accZ; +} + +uint32_t OswDevices::BMI270::getStepCount() { + return this->step_count; +} + +OswAccelerationProvider::ActivityMode OswDevices::BMI270::getActivityMode() { + return this->activityMode; +} + +void OswDevices::BMI270::resetStepCount() { + uint8_t cmndSetFeaturePage = 6; + if(bmi2_set_regs(0x2F, &cmndSetFeaturePage, sizeof(cmndSetFeaturePage), &this->bmi2) < 0) + throw std::runtime_error("Failed to set configuration page of BMI270!"); + + uint8_t cmnd[2] = { 0x00, 0x4 | 0x10 | 0x20 }; // ...; reset steps, enable counter, enable activity + if(bmi2_set_regs(0x32, cmnd, sizeof(cmnd), &this->bmi2) < 0) + throw std::runtime_error("Failed to configure step counter of BMI270!"); + + this->step_count = 0; +} + +float OswDevices::BMI270::getTemperature() { + return this->temperature; +} +#endif +#endif \ No newline at end of file diff --git a/src/devices/bmp581.cpp b/src/devices/bmp581.cpp new file mode 100644 index 000000000..e58dee748 --- /dev/null +++ b/src/devices/bmp581.cpp @@ -0,0 +1,111 @@ +#ifndef OSW_EMULATOR +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_HARDWARE_BMP581 == 1 +#include +#include +#include + +#include + +static int8_t bmp5_i2c_read(uint8_t reg_addr, uint8_t* reg_data, uint32_t len, void* intf_ptr) { + if ((reg_data == NULL) || (len == 0) || (len > 32)) { + return -1; + } + uint8_t bytes_received; + + Wire.beginTransmission(BMP5_I2C_ADDR_PRIM); + Wire.write(reg_addr); + if (Wire.endTransmission() == 0) { + bytes_received = Wire.requestFrom(BMP5_I2C_ADDR_PRIM, len); + // Optionally, throw an error if bytes_received != len + for (uint16_t i = 0; i < bytes_received; i++) { + reg_data[i] = Wire.read(); + } + } else { + return -1; + } + + return 0; +} + +static int8_t bmp5_i2c_write(uint8_t reg_addr, const uint8_t* reg_data, uint32_t len, void* intf_ptr) { + if ((reg_data == NULL) || (len == 0) || (len > 32)) { + return -1; + } + + Wire.beginTransmission(BMP5_I2C_ADDR_PRIM); + Wire.write(reg_addr); + for (uint16_t i = 0; i < len; i++) { + Wire.write(reg_data[i]); + } + if (Wire.endTransmission() != 0) { + return -1; + } + + return 0; +} + +static void bmp5_delay_us(uint32_t period, void* intf_ptr) { + delayMicroseconds(period); +} + +void OswDevices::BMP581::setup() { + int8_t rslt; + { + this->bmp5.chip_id = BMP5_I2C_ADDR_PRIM; + this->bmp5.read = bmp5_i2c_read; + this->bmp5.write = bmp5_i2c_write; + this->bmp5.delay_us = bmp5_delay_us; + this->bmp5.intf = BMP5_I2C_INTF; + this->bmp5.intf_ptr = nullptr; // we are using the default address anyways + + rslt = bmp5_init(&this->bmp5); + if(rslt != BMP5_OK) + throw std::runtime_error("Failed to initialize BMP581!"); + } + { + rslt = bmp5_set_power_mode(BMP5_POWERMODE_STANDBY, &this->bmp5); + if(rslt != BMP5_OK) + throw std::runtime_error("Failed to reconfigure BMP581 power mode!"); + + struct bmp5_iir_config set_iir_cfg; + rslt = bmp5_get_osr_odr_press_config(&this->osr_odr_press_cfg, &this->bmp5); + + osr_odr_press_cfg.odr = BMP5_ODR_50_HZ; + osr_odr_press_cfg.press_en = BMP5_ENABLE; + osr_odr_press_cfg.osr_t = BMP5_OVERSAMPLING_64X; + osr_odr_press_cfg.osr_p = BMP5_OVERSAMPLING_4X; + rslt = bmp5_set_osr_odr_press_config(&this->osr_odr_press_cfg, &this->bmp5); + + set_iir_cfg.set_iir_t = BMP5_IIR_FILTER_COEFF_1; + set_iir_cfg.set_iir_p = BMP5_IIR_FILTER_COEFF_1; + set_iir_cfg.shdw_set_iir_t = BMP5_ENABLE; + set_iir_cfg.shdw_set_iir_p = BMP5_ENABLE; + rslt = bmp5_set_iir_config(&set_iir_cfg, &this->bmp5); + + rslt = bmp5_set_power_mode(BMP5_POWERMODE_NORMAL, &this->bmp5); + if(rslt != BMP5_OK) + throw std::runtime_error("Failed to reconfigure BMP581 power mode!"); + } + // TODO proper sensor reading configuration +} + +void OswDevices::BMP581::update() { + int8_t rslt; + struct bmp5_sensor_data sensor_data; + + rslt = bmp5_get_sensor_data(&sensor_data, &this->osr_odr_press_cfg, &this->bmp5); + + this->pressure = sensor_data.pressure; + this->temperature = sensor_data.temperature; +} + +float OswDevices::BMP581::getPressure() { + return this->pressure; +} + +float OswDevices::BMP581::getTemperature() { + return this->temperature; +} +#endif +#endif \ No newline at end of file diff --git a/src/devices/ds3231mz.cpp b/src/devices/ds3231mz.cpp index 403328563..fab6c3c9b 100644 --- a/src/devices/ds3231mz.cpp +++ b/src/devices/ds3231mz.cpp @@ -1,4 +1,5 @@ -#ifndef OSW_EMULATOR +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_HARDWARE_DS3231MZ == 1 #include #include @@ -75,4 +76,4 @@ float OswDevices::DS3231MZ::getTemperature() { return 0.0f; return rtcTemp.AsFloatDegC(); } -#endif \ No newline at end of file +#endif diff --git a/src/devices/esp32.cpp b/src/devices/esp32.cpp index 1cc3bb196..a0b593cfe 100644 --- a/src/devices/esp32.cpp +++ b/src/devices/esp32.cpp @@ -13,7 +13,7 @@ #include #include -// Following forward declaration to access the interal temperature sensor of the ESP32, which is may not built-in (-> https://gist.github.com/xxlukas42/7e7e18604f61529b8398f7fcc5785251?permalink_comment_id=3532040#gistcomment-3532040)... +// Following forward declaration to access the internal temperature sensor of the ESP32, which is may not built-in (-> https://gist.github.com/xxlukas42/7e7e18604f61529b8398f7fcc5785251?permalink_comment_id=3532040#gistcomment-3532040)... #ifdef __cplusplus extern "C" { #endif @@ -31,9 +31,13 @@ uint8_t temprature_sens_read() { void OswDevices::NativeESP32::setup() { // Test temperature for 128 (sensor not available) for 10 times +#if OSW_DEVICE_ESP32_USE_INTTEMP == 1 for(int i = 0; i < 10; i++) if(temprature_sens_read() == 128) this->tempSensorIsBuiltIn = false; +#else + this->tempSensorIsBuiltIn = false; +#endif setenv("TZ", "UTC0", 1); // Force systems clock to correspond to UTC } @@ -108,10 +112,14 @@ time_t OswDevices::NativeESP32::getTimezoneOffset(const time_t& timestamp, const } float OswDevices::NativeESP32::getTemperature() { +#if OSW_DEVICE_ESP32_USE_INTTEMP == 1 const uint8_t temp = temprature_sens_read(); if(!this->tempSensorIsBuiltIn) return 0.0f; - return (temp - 32) / 1.8; + return (temp - 32) / 1.8f; +#else + return 0.0f; +#endif } bool OswDevices::NativeESP32::isTemperatureSensorAvailable() { @@ -137,9 +145,9 @@ void OswDevices::NativeESP32::triggerNTPUpdate() { } /** - * @brief After an NTP update was triggered, check if it was sucessful and set the time. This will also update or reset the internal state of e.g. the time resync. + * @brief After an NTP update was triggered, check if it was successful and set the time. This will also update or reset the internal state of e.g. the time resync. * - * @return true Only ONCE after the NTP update was sucessful + * @return true Only ONCE after the NTP update was successful * @return false */ bool OswDevices::NativeESP32::checkNTPUpdate() { @@ -163,4 +171,4 @@ void OswDevices::NativeESP32::setClockResyncEnabled(const bool& enable) { bool OswDevices::NativeESP32::isClockResyncEnabled() { return this->enableTimeResync; -} \ No newline at end of file +} diff --git a/src/devices/interfaces/OswAccelerationProvider.cpp b/src/devices/interfaces/OswAccelerationProvider.cpp index fa65c4c8a..3a6f352c0 100644 --- a/src/devices/interfaces/OswAccelerationProvider.cpp +++ b/src/devices/interfaces/OswAccelerationProvider.cpp @@ -1,3 +1,3 @@ #include -std::list OswAccelerationProvider::allDevices; \ No newline at end of file +std::list OswAccelerationProvider::allDevices; diff --git a/src/devices/interfaces/OswHumidityProvider.cpp b/src/devices/interfaces/OswHumidityProvider.cpp index d5d650570..8c3b1524b 100644 --- a/src/devices/interfaces/OswHumidityProvider.cpp +++ b/src/devices/interfaces/OswHumidityProvider.cpp @@ -1,3 +1,3 @@ #include -std::list OswHumidityProvider::allDevices; \ No newline at end of file +std::list OswHumidityProvider::allDevices; diff --git a/src/devices/interfaces/OswMagnetometerProvider.cpp b/src/devices/interfaces/OswMagnetometerProvider.cpp index 0708f3681..a3ecc2d2a 100644 --- a/src/devices/interfaces/OswMagnetometerProvider.cpp +++ b/src/devices/interfaces/OswMagnetometerProvider.cpp @@ -1,3 +1,3 @@ #include -std::list OswMagnetometerProvider::allDevices; \ No newline at end of file +std::list OswMagnetometerProvider::allDevices; diff --git a/src/devices/interfaces/OswPressureProvider.cpp b/src/devices/interfaces/OswPressureProvider.cpp index d68730de2..2b724ee24 100644 --- a/src/devices/interfaces/OswPressureProvider.cpp +++ b/src/devices/interfaces/OswPressureProvider.cpp @@ -1,3 +1,3 @@ #include -std::list OswPressureProvider::allDevices; \ No newline at end of file +std::list OswPressureProvider::allDevices; diff --git a/src/devices/interfaces/OswTemperatureProvider.cpp b/src/devices/interfaces/OswTemperatureProvider.cpp index 094f349b9..98167927d 100644 --- a/src/devices/interfaces/OswTemperatureProvider.cpp +++ b/src/devices/interfaces/OswTemperatureProvider.cpp @@ -1,3 +1,3 @@ #include -std::list OswTemperatureProvider::allDevices; \ No newline at end of file +std::list OswTemperatureProvider::allDevices; diff --git a/src/devices/interfaces/OswTimeProvider.cpp b/src/devices/interfaces/OswTimeProvider.cpp index 32c467a57..f62ed0d51 100644 --- a/src/devices/interfaces/OswTimeProvider.cpp +++ b/src/devices/interfaces/OswTimeProvider.cpp @@ -1,3 +1,3 @@ #include -std::list OswTimeProvider::allDevices; \ No newline at end of file +std::list OswTimeProvider::allDevices; diff --git a/src/devices/qmc5883l.cpp b/src/devices/qmc5883l.cpp index 21ca8dfe3..0066e733e 100644 --- a/src/devices/qmc5883l.cpp +++ b/src/devices/qmc5883l.cpp @@ -1,4 +1,5 @@ -#ifndef OSW_EMULATOR +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_HARDWARE_QMC5883L == 1 #include #include @@ -40,7 +41,7 @@ int OswDevices::QMC5883L::getMagnetometerZ() { int OswDevices::QMC5883L::getMagnetometerAzimuth() { // NOT (y,x),(y,z) (z,y) (x,y) - int a = atan2(qmc5883l.getY(), qmc5883l.getX()) * 180.0 / PI; + int a = atan2(qmc5883l.getY(), qmc5883l.getX()) * 180.0f / PI; a = a < 0 ? 360 + a : a; #if defined(GPS_EDITION_ROTATED) @@ -53,4 +54,4 @@ byte OswDevices::QMC5883L::getMagnetometerBearing() { int a = getMagnetometerAzimuth(); return qmc5883l.getBearing(a); } -#endif \ No newline at end of file +#endif diff --git a/src/devices/virtual.cpp b/src/devices/virtual.cpp index 06bc3fd82..08f00dc27 100644 --- a/src/devices/virtual.cpp +++ b/src/devices/virtual.cpp @@ -35,4 +35,4 @@ time_t Virtual::getTimezoneOffset(const time_t& timestamp, const String& timezon return local - utc; } #endif -} \ No newline at end of file +} diff --git a/src/gfx_2d.cpp b/src/gfx_2d.cpp new file mode 100644 index 000000000..793d3ac27 --- /dev/null +++ b/src/gfx_2d.cpp @@ -0,0 +1,1582 @@ + +#include + +#include "gfx_2d.h" +#include "gfx_util.h" +#include "math_angles.h" + +#include + +#pragma GCC optimize("O2") + +void Graphics2D::fillBuffer(uint16_t color = rgb565(0, 0, 0)) { + if (!hasBuffer()) + return; + + for (int chunk = numChunks - 1; chunk >= 0; --chunk) { + for (int i = (chunkWidths[chunk] << chunkHeightLd) - 1; i >= 0; --i) { + buffer[chunk][i] = color; + } + } +} + +void Graphics2D::enableBuffer() { + drawPixelCallback = NULL; + numChunks = height >> chunkHeightLd; + buffer = new uint16_t* [numChunks]; + if (isRound) { + missingPixelColor = rgb565(128, 128, 128); + chunkXOffsets = new uint16_t[numChunks]; + chunkWidths = new uint16_t[numChunks]; + for (uint16_t i = 0; i < numChunks; i++) { + uint16_t y = i << chunkHeightLd; + float y1 = (y + (y < height / 2 ? (1<= 0; --i) { + delete[] buffer[i]; + buffer[i] = NULL; + } + delete[] buffer; + buffer = NULL; + + delete[] chunkXOffsets; + chunkXOffsets = NULL; + + delete[] chunkWidths; + chunkWidths = NULL; +} + +Graphics2D::~Graphics2D() { + for (int32_t i = numChunks - 1; i >= 0; --i) { + delete[] buffer[i]; + buffer[i] = NULL; + } + delete[] buffer; + buffer = NULL; + + delete[] chunkXOffsets; + chunkXOffsets = NULL; + + delete[] chunkWidths; + chunkWidths = NULL; +} + +void Graphics2D::drawPixelClipped(int32_t x, int32_t y, uint16_t color) { + if (x >= width || y >= height || x < 0 || y < 0) { + return; + } + if (maskEnabled && color == maskColor) { + return; + } + + // if we have a pixel callback, there is now buffer + // draw with the callback and return.. + if (drawPixelCallback != NULL) { + drawPixelCallback->drawPixel(x, y, color); + return; + } + + uint8_t chunkId = y >> chunkHeightLd; + int16_t chunkY = y - (chunkId << chunkHeightLd); + + bool isRoundAndInsideChunkCached = isRound && isInsideChunk(x, y); + if (alphaEnabled) { + if (isRoundAndInsideChunkCached) { + int16_t chunkX = x - chunkXOffsets[chunkId]; + color = blend(buffer[chunkId][chunkX + chunkY * chunkWidths[chunkId]], color, alpha); + } else { + color = blend(buffer[chunkId][x + chunkY * width], color, alpha); + } + } + + if (isRoundAndInsideChunkCached) { + int16_t chunkX = x - chunkXOffsets[chunkId]; + buffer[chunkId][chunkX + chunkY * chunkWidths[chunkId]] = color; + } else if (!isRound) { // fix for round module + buffer[chunkId][x + chunkY * width] = color; + } +} + +uint16_t Graphics2D::getPixel(uint16_t x, uint16_t y) { + if (x >= width || y >= height) { + return 0; + } + uint8_t chunkId = y >> chunkHeightLd; + uint16_t chunkY = y - (chunkId << chunkHeightLd); + // printf("chunkid %d, offetY %d for y=%d and chunkHeight=%d\n", chunkId, chunkY, y, chunkHeight); + if (isRound) { + // TODO: check if inside chunk + if (isInsideChunk(x, y)) { + uint16_t chunkX = x - chunkXOffsets[chunkId]; + return buffer[chunkId][chunkX + chunkY * chunkWidths[chunkId]]; + } else { + return missingPixelColor; + } + } else { + return buffer[chunkId][x + chunkY * width]; + } +} + +bool Graphics2D::isInsideChunk(uint16_t x, uint16_t y) { + uint8_t chunkId = y >> chunkHeightLd; + // uint16_t chunkY = y - (chunkId << chunkHeightLd); + uint16_t chunkOffset = chunkXOffsets[chunkId]; + uint16_t chunkWidth = chunkWidths[chunkId]; + bool xFit = chunkOffset < x && x < chunkOffset + chunkWidth; + // y always fits, because we chunk in rows + return xFit; +} + +/** + * @brief Draw an horizontal line from the point (x,y) to an other horizontal point at h pixels + * + * @param x x-axis of the start point + * @param y y-axis of the start point + * @param w width of the horizontal line + * @param color color code of the line + */ +void Graphics2D::drawHLine(int32_t x, int32_t y, uint16_t w, uint16_t color) { + for (uint16_t i = 0; i < w; i++) { + drawPixel(x + i, y, color); + } +} + +/** + * @brief Draw a vertical line from the bottom point (x,y) to an other vertical point at h pixels + * + * @param x x-axis of the start point + * @param y y-axis of the start point + * @param h height of the vertical line + * @param color color code of the line + */ +void Graphics2D::drawVLine(int32_t x, int32_t y, uint16_t h, uint16_t color) { + for (int32_t i = 0; i < h; i++) { + drawPixel(x, y + i, color); + } +} + +void Graphics2D::drawFrame(int32_t x, int32_t y, uint16_t w, uint16_t h, uint16_t color) { + drawHLine(x, y, w, color); + drawHLine(x, y + h, w, color); + drawVLine(x, y, h, color); + drawVLine(x + w, y, h, color); +} + +void Graphics2D::fillFrame(int32_t x0, int32_t y0, uint16_t w, uint16_t h, uint16_t color) { + for (int32_t y = y0; y < y0 + h; y++) { + drawHLine(x0, y, w, color); + } +} + +/** + * Draw line from (x1,y1) to (x2,y2) point with color + * + * @param x1 + * @param y1 + * @param x2 + * @param y2 + * @param color + */ +void Graphics2D::drawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint16_t color) { // see p3dt_gfx_2d_license.txt + // printf("\ndrawLine(%d, %d, %d, %d)",x1,y1,x2,y2); + // see p3dt_gfx_2d_license.txt + int32_t tmp; + int32_t x, y; + int32_t dx, dy; + int32_t err; + int32_t ystep; + + uint8_t swapxy = 0; + + /* no intersection check at the moment, should be added... */ + + if (x1 > x2) + dx = x1 - x2; + else + dx = x2 - x1; + if (y1 > y2) + dy = y1 - y2; + else + dy = y2 - y1; + + if (dy > dx) { + swapxy = 1; + tmp = dx; + dx = dy; + dy = tmp; + tmp = x1; + x1 = y1; + y1 = tmp; + tmp = x2; + x2 = y2; + y2 = tmp; + } + if (x1 > x2) { + tmp = x1; + x1 = x2; + x2 = tmp; + tmp = y1; + y1 = y2; + y2 = tmp; + } + err = dx / 2; + if (y2 > y1) + ystep = 1; + else + ystep = -1; + y = y1; + + if (x2 == 0xffff) + x2--; + + for (x = x1; x <= x2; x++) { + if (swapxy == 0) + drawPixel(x, y, color); + else + drawPixel(y, x, color); + err -= abs(dy); + if (err < 0) { + y += ystep; + err += dx; + } + } +} + +/** + * Draw a thin anti-aliased line from (x1,y1) to (x2,y2) point with color + * + * @param x1 + * @param y1 + * @param x2 + * @param y2 + * @param color + */ +void Graphics2D::drawLineAA(int32_t x0, int32_t y0, int32_t x1, int32_t y1, const uint16_t color) { + // anti-aliased line + + int dx = abs(x1-x0); + int sx = x0 < x1 ? 1 : -1; + int dy = abs(y1-y0); + int sy = y0 < y1 ? 1 : -1; + int err = dx-dy, e2, x2; /* error value e_xy */ + int ed = dx+dy == 0 ? 1 : hypotf(dx, dy); //sqrtf(dx*dx+dy*dy); + + for ( ; ; ) { /* pixel loop */ + drawPixelAA(x0, y0, color, 255-255*abs(err-dx+dy)/ed); + e2 = err; + x2 = x0; + if (2*e2 >= -dx) { /* x step */ + if (x0 == x1) + break; + if (e2+dy < ed) + drawPixelAA(x0, y0+sy, color, 255-255*(e2+dy)/ed); + err -= dy; + x0 += sx; + } + if (2*e2 <= dy) { /* y step */ + if (y0 == y1) + break; + if (dx-e2 < ed) + drawPixelAA(x2+sx, y0, color, 255-255*(dx-e2)/ed); + err += dx; + y0 += sy; + } + } +} + +/** + * @brief Draw a line between (x1,y1) and (x2,y2) with a thick of radius and with specific color + * + * Radius is a multiple of 4 pixels. + * + * @param x1 x-axis of the start point + * @param y1 y-axis of the start point + * @param x2 x-axis of the end point + * @param y2 y-axis of the end point + * @param radius radius of the line. Example : radius = 1 give a line of 4 px of diameter, radius 2 -> 8px, etc.... + * @param color color code use to draw the line. + * @param highQuality + */ +void Graphics2D::drawThickLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint8_t radius, uint16_t color, + bool highQuality) { // see p3dt_gfx_2d_license.txt + + // see p3dt_gfx_2d_license.txt + int32_t tmp; + int32_t x, y; + int32_t dx, dy; + int32_t err; + int32_t ystep; + + uint8_t swapxy = 0; + + /* no intersection check at the moment, should be added... */ + + if (x1 > x2) + dx = x1 - x2; + else + dx = x2 - x1; + if (y1 > y2) + dy = y1 - y2; + else + dy = y2 - y1; + + if (dy > dx) { + swapxy = 1; + tmp = dx; + dx = dy; + dy = tmp; + tmp = x1; + x1 = y1; + y1 = tmp; + tmp = x2; + x2 = y2; + y2 = tmp; + } + if (x1 > x2) { + tmp = x1; + x1 = x2; + x2 = tmp; + tmp = y1; + y1 = y2; + y2 = tmp; + } + err = dx >> 1; + if (y2 > y1) + ystep = 1; + else + ystep = -1; + y = y1; + + if (x2 == 0xffff) x2--; + + for (x = x1; x <= x2; x++) { + if (swapxy == 0) { + if (highQuality) { + fillCircle(x, y, radius, color); + } else { + drawCircle(x, y, radius, color); + if (radius > 2) { + drawCircle(x, y, radius - 1, color); + } + if (radius > 3) { + drawCircle(x, y, radius - 2, color); + } + } + } else { + if (highQuality) { + fillCircle(y, x, radius, color); + } else { + drawCircle(y, x, radius, color); + if (radius > 2) { + drawCircle(y, x, radius - 1, color); + } + if (radius > 3) { + drawCircle(y, x, radius - 2, color); + } + } + } + + err -= (uint8_t)dy; + if (err < 0) { + y += (uint16_t)ystep; + err += (uint16_t)dx; + } + } +} + +/** + * @brief Draw an anti-aliased line between (x1,y1) and (x2,y2) with a thicknes of line_width and with a specific color + * + * @param x1 x-axis of the start point + * @param y1 y-axis of the start point + * @param x2 x-axis of the end point + * @param y2 y-axis of the end point + * @param line_width thickness of the line + * @param color color code use to draw the line. + */ +void Graphics2D::drawThickLineAA(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t line_width, + const uint16_t color, LINE_END_OPT eol) { + // thanks to https://github.com/foo123/Rasterizer + + int32_t tmp, + sx, sy, + w, w2, wx, wy, + wsx, wsy, + dx, dy, n, + xa, xb, xc, xd, + ya, yb, yc, yd; + + /* + given line's thickness w and dx,dy of line, wx, wy are computed as: + n = hypot(dx, dy) + w2 = (w-1)/2 + wx = dy*w2/n + wy = dx*w2/n + */ + + w = line_width; + w2 = (w-1)/2; + + if (x0 > x1) { + tmp = x0; + x0 = x1; + x1 = tmp; + tmp = y0; + y0 = y1; + y1 = tmp; + } + + sx = 1; + sy = y1 > y0 ? 1 : -1; + + dx = abs(x1 - x0); + dy = abs(y1 - y0); + + if (dx == 0) + return fillBoxHV(x0 - w2, y0, x1 - w2 + w, y1, color); + else if (dy == 0) + return fillBoxHV(x0, y0 - w2, x1, y1 - w2 + w, color); + + n = hypotf(dx, dy) + 0.5f; //sqrtf(dx*dx + dy*dy) + 0.5f; + // more readable: wx = (dy*w/2 + (n/2))/n; where (n/2) is for rounding + wx = (dy*w+n)/2/n; // +1 is for rounding of /2 + wy = (dx*w+n)/2/n; + +// printf("xxx x0=%d, y0=%d, x1=%d, y1=%d, dx=%d, dy=%d, w2=%d, wx=%d, wy=%d, %d, %d\n", x0, y0, x1, y1, dx, dy, w2, wx, wy); + + /* + wx .b + +-----.(0) . + wy |.a | . . + . | . .f + . . . + dy | .g . .d + +---.-----.(1) + dx .c + + a: y0 + wsy - y0 = -(x - x0)/m => x = x0 - m*wsy: (xs-wsx, y0+wsy) + b: y0 - wsy - y0 = -(x - x0)/m => x = x0 + m*wsy: (xs+wsx, y0-wsy) + c: y1 + wsy - y1 = -(x - x1)/m => x = x1 - m*wsy: (xe-wsx, y1+wsy) + d: y1 - wsy - y1 = -(x - x1)/m => x = x1 + m*wsy: (xe+wsx, y1-wsy) + */ + + wsx = sx*wx; + wsy = sy*wy; + + xa = x0 - wsx; + ya = y0 + wsy; + xb = x0 + wsx; + yb = y0 - wsy; + xc = x1 - wsx; + yc = y1 + wsy; + xd = x1 + wsx; + yd = y1 - wsy; + +// printf("xxx xa=%d,ya=%d xb=%d,yb=%d xc=%d,yc=%d xd=%d,yd=%d\n", xa,ya, xb,yb, xc,yc, xd,yd); + + // outline + drawLineAA(xa, ya, xb, yb, color); + drawLineAA(xb, yb, xd, yd, color); + drawLineAA(xd, yd, xc, yc, color); + drawLineAA(xc, yc, xa, ya, color); + + // fill + drawFilledTriangle(xb, yb, xa, ya, xc, yc, color); + drawFilledTriangle(xb, yb, xd, yd, xc, yc, color); + + switch (eol) { + case STRAIGHT_END: + break; + case ROUND_END: // circle at end + fillCircleAA(x0, y0, (line_width)/2, color); + fillCircleAA(x1, y1, (line_width)/2, color); + break; + case TRIANGLE_END: { + // still experimental and not finished + int32_t x, y; + int32_t xo = sx * line_width * dx / n; + int32_t yo = sy * line_width * dy / n; + x = x0 - xo; + y = y0 - yo; + drawFilledTriangle(xa, ya, xb, yb, x, y, color/2); + x = x1 + xo; + y = y1 + yo; + drawFilledTriangle(xc, yc, xd, yd, x, y, color/2); + } + break; + default: + break; + } + + /* + // Center pixel + drawPixel(x0, y0, rgb565(255,255,0)); + drawPixel(x1, y1, rgb565(255,255,0)); + + // Draw vertices + drawPixel(xa, ya, rgb565(0,0,255)); + drawPixel(xb, yb, rgb565(0,0,255)); + drawPixel(xd, yd, rgb565(0,0,255)); + drawPixel(xc, yc, rgb565(0,0,255)); + */ +} + +void Graphics2D::drawFilledTriangle(int32_t ax, int32_t ay, int32_t bx, int32_t by, int32_t cx, int32_t cy, const uint16_t color) { + int32_t tmp, + x, xx, y, + xac, xab, xbc, + yac, yab, ybc, + zab, zbc; + + // correction if tirangles edge AC is rising + int32_t corr = cy-ay < 0 ? 0 : 1; + + if (ay > by) { + tmp = ax; + ax = bx; + bx = tmp; + tmp = ay; + ay = by; + by = tmp; + } + if (ay > cy) { + tmp = ax; + ax = cx; + cx = tmp; + tmp = ay; + ay = cy; + cy = tmp; + } + if (by > cy) { + tmp = bx; + bx = cx; + cx = tmp; + tmp = by; + by = cy; + cy = tmp; + } + + yac = cy - ay; + if (yac == 0) { + // line or single point + y = ay; + x = min(ax, min(bx, cx)); + xx = max(ax, max(bx, cx)); + return fillBoxHV(x, y, xx, y, color); + } + + yab = by - ay; + ybc = cy - by; + xac = cx - ax; + xab = bx - ax; + xbc = cx - bx; + + zab = yab == 0; + zbc = ybc == 0; + + for (y = ay; y < cy; ++y) { + if (y < by) { // upper part + if (zab) { + x = ax; + xx = bx; + } else { + x = (xac*(y - ay))/yac + ax; + xx = (xab*(y - ay))/yab + ax + corr; + } + } else { // lower part + if (zbc) { + x = bx; + xx = cx; + } else { + x = (xac*(y - ay))/yac + ax; + xx = (xbc*(y - by))/ybc + bx + corr; + } + } + if (x > xx) { // left handed ;-) + tmp = x; + x = xx; + xx = tmp; + } + + if (abs(xx-x) <= 0) { + drawPixel(x, y, color); + } else { + for (x = x; x < xx; ++x) + drawPixel(x, y, color); + } + } +} + + +/** + * @brief Draw a horizontal/vertical box (x1,y1) and (x2,y2) with a specific color + * + * @param x1 x-axis of the start point + * @param y1 y-axis of the start point + * @param x2 x-axis of the end point + * @param y2 y-axis of the end point + * @param color color code use to fill the box. + */ +void Graphics2D::fillBoxHV(int32_t x0, int32_t y0, int32_t x1, int32_t y1, const uint16_t color) { + int sx, sy; + sx = x1 > x0 ? 1 : -1; + sy = y1 > y0 ? 1 : -1; + + for (int32_t x = x0; x != x1; x += sx) + for (int32_t y = y0; y != y1; y += sy) + drawPixel(x, y, color); +} + +void Graphics2D::drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) { + drawLine(x0, y0, x1, y1, color); + drawLine(x1, y1, x2, y2, color); + drawLine(x2, y2, x0, y0, color); +} + +/* + * "Complex" Stuff: + */ + +void Graphics2D::_drawCircleSection(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, uint16_t color, + CIRC_OPT option) { // see p3dt_gfx_2d_license.txt + + if (option == DRAW_UPPER_RIGHT || option == DRAW_ALL) { + drawPixel(x0 + x, y0 - y, color); + drawPixel(x0 + y, y0 - x, color); + } + + if (option == DRAW_UPPER_LEFT || option == DRAW_ALL) { + drawPixel(x0 - x, y0 - y, color); + drawPixel(x0 - y, y0 - x, color); + } + + if (option == DRAW_LOWER_RIGHT || option == DRAW_ALL) { + drawPixel(x0 + x, y0 + y, color); + drawPixel(x0 + y, y0 + x, color); + } + + if (option == DRAW_LOWER_LEFT || option == DRAW_ALL) { + drawPixel(x0 - x, y0 + y, color); + drawPixel(x0 - y, y0 + x, color); + } +} + +/** + * @brief Draw a circle + * + * @param x0 x-axis of the center of the circle + * @param y0 y-axis of the center of the circle + * @param rad radius of the circle + * @param color color code of the circle + * @param option + */ +void Graphics2D::drawCircle(int16_t x0, int16_t y0, int16_t rad, uint16_t color, + CIRC_OPT option) { // see p3dt_gfx_2d_license.txt + + float f; + float ddFx; + float ddFy; + float x; + float y; + + f = 1; + f -= rad; + ddFx = 1; + ddFy = 0; + ddFy -= rad; + ddFy *= 2; + x = 0; + y = rad; + + _drawCircleSection(x, y, x0, y0, color, option); + + while (x < y) { + if (f >= 0) { + y--; + ddFy += 2; + f += ddFy; + } + x++; + ddFx += 2; + f += ddFx; + + _drawCircleSection(x, y, x0, y0, color, option); + } +} + +void Graphics2D::isPixelMaskedByAnglesInit(int32_t off_x, int32_t off_y, int32_t sa, int32_t ea) { + start_angle = sa; + end_angle = ea; + if (ea != -1 && sa != -1) { + ox = off_x; + oy = off_y; + tan_sa = tanf(start_angle*(float)PI/180.0f); + tan_ea = tanf(end_angle*(float)PI/180.0f); + } +} + +bool Graphics2D::isPixelMaskedByAngles(int32_t x, int32_t y) { + if (end_angle == -1 && start_angle == -1) + return false; + else { + float tan_pixel = - (float)(y-oy) / (float)(x-ox); + if (start_angle < 90) { + if (x-ox >= 0 && y-oy <= 0 && tan_pixel < tan_sa) + return true; + } else if (start_angle < 180) { + if (x-ox >= 0 && y-oy <= 0) + return true; // 1.quadrant + else if (x-ox < 0 && y-oy <= 0) + if (tan_pixel < 0 && tan_pixel < tan_sa) + return true; // 2.quadrant + } else if (start_angle < 270) { + if (x-ox >= 0 && y-oy <= 0) + return true; // 1.quadrant + else if (x-ox < 0 && y-oy <= 0) + return true; // 2.quadrant + else if (x-ox < 0 && y-oy > 0) + if (tan_pixel > 0 && tan_pixel < tan_sa) + return true; // 3.quadrant + } else if (start_angle <= 360) { + if (x-ox >= 0 && y-oy <= 0) + return true; // 1.quadrant + else if (x-ox < 0 && y-oy <= 0) + return true; // 2.quadrant + else if (x-ox < 0 && y-oy > 0) + return true; // 3.quadrant + else if (tan_pixel < 0 && tan_pixel < tan_sa) + return true; // 4.quadrant + } + + // end angle + if (end_angle < 90) { + if (x-ox >= 0 && y-oy <= 0 && tan_pixel > tan_ea) + return true; // 1.quadrant + else if (x-ox <= 0) + return true; // 2.&3.quadrant + else if (x-ox >= 0 && y-oy >0) + return true; // 4. quadrant + } else if (end_angle < 180) { + if (x-ox < 0 && y-oy <= 0 && tan_pixel > tan_ea) + return true; // 2.quadrant + else if (y-oy >= 0) + return true; // 3.&4.quadrant + } else if (end_angle < 270) { + if (x-oy <= 0 && y-oy >= 0 && tan_pixel > tan_ea) + return true; // 3.quadrant + else if (x-ox >= 0 && y-oy >= 0) + return true; // 4.quadrant + } else if (end_angle <= 360) { + if (x-ox >= 0 && y-oy >= 0 && tan_pixel >= tan_ea) + return true; // 4.quadrant + } + } + return false; +} + + +/** + * @brief Draw an anti-aliased circle with thicknes + * + * @param x0 x-axis of the center of the circle + * @param y0 y-axis of the center of the circle + * @param r radius of the circle + * @param bw thickness of th circle + * @param color color code of the circle + */ +void Graphics2D::drawCircleAA(int16_t off_x, int16_t off_y, int16_t r, int16_t bw, + uint16_t color, int16_t sa, int16_t ea) { + + int x0 = -r; + int y0 = -r; + int x1 = r; + int y1 = r; + + isPixelMaskedByAnglesInit(off_x, off_y, sa, ea); + + // for a filled circle + if (bw >= r || bw <= 0) { + bw = r - 1; + drawPixel(off_x, off_y, color); + } + + int o_diam = 2*r; // outer diameter + const int odd_diam = 0; // o_diam&1; // odd diameter + int a2 = 2*r-2*bw; + int dx = 4*(o_diam-1)*o_diam*o_diam; + int dy = 4*(odd_diam-1)*o_diam*o_diam; // error increment + int err = odd_diam*o_diam*o_diam; + int dx2, dy2, e2, ed; + + if ((bw-1)*(2*o_diam-bw) > o_diam*o_diam) { + a2 = 0; + bw = o_diam/2; + } + + if (x0 > x1) { // if called with swapped points + x0 = x1; + x1 += o_diam; + } + if (y0 > y1) + y0 = y1; // .. exchange them + if (a2 <= 0) + bw = o_diam; // filled ellipse + e2 = bw; + bw = x0+bw-e2; + dx2 = 4*(a2+2*e2-1)*a2*a2; + dy2 = 4*(odd_diam-1)*a2*a2; + e2 = dx2*e2; + y0 += (o_diam+1)>>1; + y1 = y0-odd_diam+1; // starting pixel + int a1; + a1 = 8*o_diam*o_diam; + a2 = 8*a2*a2; + + int i = 0; + + do { + for (;;) { + if (err <= 0 || x0 >= x1) { + i = x0; + break; + } + i = dx < dy ? dx : dy; + ed = dx > dy ? dx : dy; + + ed += 2*ed*i*i/(4*ed*ed+i*i+1)+1;// approx ed=sqrtf(dx*dx+dy*dy) + + int alpha = 255 - 255.0f*err/ed; // outside anti-aliasing; integer overflow for big radius + if (alpha < 0) + alpha = 0; + else if (alpha > 255) + alpha = 255; + + if (!isPixelMaskedByAngles(off_x + x0, off_y + y0)) drawPixelAA(off_x + x0, off_y + y0, color, alpha); // 3. quadrant + if (!isPixelMaskedByAngles(off_x + x0, off_y + y1 - 1)) drawPixelAA(off_x + x0, off_y + y1 - 1, color, alpha); // 2. quadrant + if (!isPixelMaskedByAngles(off_x + x1, off_y + y0)) drawPixelAA(off_x + x1, off_y + y0, color, alpha); // 1. quadrant + if (!isPixelMaskedByAngles(off_x + x1, off_y + y1-1)) drawPixelAA(off_x + x1, off_y + y1-1, color, alpha); // 4. quadrant + + if (err+dy+a1 < dx) { + i = x0+1; + break; + } + ++x0; + --x1; + err -= dx; + dx -= a1; // x error increment + } + for ( ; i < bw && 2*i <= x0+x1; ++i) { // fill line pixel + if (!isPixelMaskedByAngles(off_x + i, off_y + y0)) drawPixel(off_x + i, off_y + y0, color); // 3. quadrant + if (!isPixelMaskedByAngles(off_x + i, off_y + y1 - 1)) drawPixel(off_x + i, off_y + y1 - 1, color); // 2. quadrant + if (!isPixelMaskedByAngles(off_x + x0 + x1 - i, off_y + y1 - 1)) drawPixel(off_x + x0 + x1 - i, off_y + y1 - 1, color); // 1. quadrant + if (!isPixelMaskedByAngles(off_x + x0 + x1 - i, off_y + y0)) drawPixel(off_x + x0 + x1 - i, off_y + y0, color); // 4. quadrant + } + while (e2 >= 0 && 2*bw <= x0+x1) { // inside anti-aliasing + i = dx2 < dy2 ? dx2 : dy2; + ed = dx2 > dy2 ? dx2 : dy2; + + ed += 2*ed*i*i/(4*ed*ed+i*i+1)+1; // approx ed=sqrtf(dx*dx+dy*dy) + + int alpha = 255.0f*e2/ed; + if (alpha < 0) + alpha = 0; + else if (alpha > 255) + alpha = 255; + + if (!isPixelMaskedByAngles(off_x + bw, off_y + y0)) drawPixelAA(off_x + bw, off_y + y0, color, alpha); // 3. quadrant + if (!isPixelMaskedByAngles(off_x + bw, off_y + y1 - 1)) drawPixelAA(off_x + bw, off_y + y1 - 1, color, alpha); // 2. quadrant + if (!isPixelMaskedByAngles(off_x + x0 + x1 - bw, off_y + y1 - 1)) drawPixelAA(off_x + x0 + x1 - bw, off_y + y1 - 1, color, alpha); // 1. quadrant + if (!isPixelMaskedByAngles(off_x + x0 + x1 - bw, off_y + y0)) drawPixelAA(off_x + x0 + x1 - bw, off_y + y0, color, alpha); // 4. quadrant + if (e2+dy2+a2 < dx2) + break; + ++bw; + e2 -= dx2; + dx2 -= a2; // x error increment + } + dy2 += a2; + e2 += dy2; + dy += a1; // y step + err += dy; + y0++; + y1--; + } while (x0 < x1); +} + +void Graphics2D::_fillCircleSection(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, uint16_t color, + CIRC_OPT option) { // see p3dt_gfx_2d_license.txt + + if (option == DRAW_UPPER_RIGHT || option == DRAW_ALL) { + drawVLine(x0 + x, y0 - y, y + 1, color); + drawVLine(x0 + y, y0 - x, x + 1, color); + } + + if (option == DRAW_UPPER_LEFT || option == DRAW_ALL) { + drawVLine(x0 - x, y0 - y, y + 1, color); + drawVLine(x0 - y, y0 - x, x + 1, color); + } + + if (option == DRAW_LOWER_RIGHT || option == DRAW_ALL) { + drawVLine(x0 + x, y0, y + 1, color); + drawVLine(x0 + y, y0, x + 1, color); + } + + if (option == DRAW_LOWER_LEFT || option == DRAW_ALL) { + drawVLine(x0 - x, y0, y + 1, color); + drawVLine(x0 - y, y0, x + 1, color); + } +} + +void Graphics2D::fillCircle(uint16_t x0, uint16_t y0, uint16_t rad, uint16_t color, + CIRC_OPT option) { // see p3dt_gfx_2d_license.txt + + float f; + float ddFx; + float ddFy; + float x; + float y; + + f = 1; + f -= rad; + ddFx = 1; + ddFy = 0; + ddFy -= rad; + ddFy *= 2; + x = 0; + y = rad; + + _fillCircleSection(x, y, x0, y0, color, option); + + while (x < y) { + if (f >= 0) { + y--; + ddFy += 2; + f += ddFy; + } + x++; + ddFx += 2; + f += ddFx; + + _fillCircleSection(x, y, x0, y0, color, option); + } +} + +void Graphics2D::_drawEllipseSection(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, uint16_t color, + CIRC_OPT option) { // see p3dt_gfx_2d_license.txt + + /* upper right */ + if (option == DRAW_UPPER_RIGHT || option == DRAW_ALL) { + drawPixel(x0 + x, y0 - y, color); + } + + /* upper left */ + if (option == DRAW_UPPER_LEFT || option == DRAW_ALL) { + drawPixel(x0 - x, y0 - y, color); + } + + /* lower right */ + if (option == DRAW_LOWER_RIGHT || option == DRAW_ALL) { + drawPixel(x0 + x, y0 + y, color); + } + + /* lower left */ + if (option == DRAW_LOWER_LEFT || option == DRAW_ALL) { + drawPixel(x0 - x, y0 + y, color); + } +} + +void Graphics2D::drawEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, uint16_t color, + CIRC_OPT option) { // see p3dt_gfx_2d_license.txt + + float x; + float y; + float xchg; + float ychg; + float err; + float rxrx2; + float ryry2; + float stopx; + float stopy; + + rxrx2 = rx; + rxrx2 *= rx; + rxrx2 *= 2; + + ryry2 = ry; + ryry2 *= ry; + ryry2 *= 2; + + x = rx; + y = 0; + + xchg = 1; + xchg -= rx; + xchg -= rx; + xchg *= ry; + xchg *= ry; + + ychg = rx; + ychg *= rx; + + err = 0; + + stopx = ryry2; + stopx *= rx; + stopy = 0; + + while (stopx >= stopy) { + _drawEllipseSection(x, y, x0, y0, color, option); + y++; + stopy += rxrx2; + err += ychg; + ychg += rxrx2; + if (2 * err + xchg > 0) { + x--; + stopx -= ryry2; + err += xchg; + xchg += ryry2; + } + } + + x = 0; + y = ry; + + xchg = ry; + xchg *= ry; + + ychg = 1; + ychg -= ry; + ychg -= ry; + ychg *= rx; + ychg *= rx; + + err = 0; + + stopx = 0; + + stopy = rxrx2; + stopy *= ry; + + while (stopx <= stopy) { + _drawEllipseSection(x, y, x0, y0, color, option); + x++; + stopx += ryry2; + err += xchg; + xchg += ryry2; + if (2 * err + ychg > 0) { + y--; + stopy -= rxrx2; + err += ychg; + ychg += rxrx2; + } + } +} + +void Graphics2D::_fillEllipseSection(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, uint16_t color, + CIRC_OPT option) { // see p3dt_gfx_2d_license.txt + + /* upper right */ + if (option == DRAW_UPPER_RIGHT || option == DRAW_ALL) { + drawVLine(x0 + x, y0 - y, y + 1, color); + } + + /* upper left */ + if (option == DRAW_UPPER_LEFT || option == DRAW_ALL) { + drawVLine(x0 - x, y0 - y, y + 1, color); + } + + /* lower right */ + if (option == DRAW_LOWER_RIGHT || option == DRAW_ALL) { + drawVLine(x0 + x, y0, y + 1, color); + } + + /* lower left */ + if (option == DRAW_LOWER_LEFT || option == DRAW_ALL) { + drawVLine(x0 - x, y0, y + 1, color); + } +} + +void Graphics2D::fillEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, uint16_t color, + CIRC_OPT option) { // see p3dt_gfx_2d_license.txt + + float x; + float y; + float xchg; + float ychg; + float err; + float rxrx2; + float ryry2; + float stopx; + float stopy; + + rxrx2 = rx; + rxrx2 *= rx; + rxrx2 *= 2; + + ryry2 = ry; + ryry2 *= ry; + ryry2 *= 2; + + x = rx; + y = 0; + + xchg = 1; + xchg -= rx; + xchg -= rx; + xchg *= ry; + xchg *= ry; + + ychg = rx; + ychg *= rx; + + err = 0; + + stopx = ryry2; + stopx *= rx; + stopy = 0; + + while (stopx >= stopy) { + _fillEllipseSection(x, y, x0, y0, color, option); + y++; + stopy += rxrx2; + err += ychg; + ychg += rxrx2; + if (2 * err + xchg > 0) { + x--; + stopx -= ryry2; + err += xchg; + xchg += ryry2; + } + } + + x = 0; + y = ry; + + xchg = ry; + xchg *= ry; + + ychg = 1; + ychg -= ry; + ychg -= ry; + ychg *= rx; + ychg *= rx; + + err = 0; + + stopx = 0; + + stopy = rxrx2; + stopy *= ry; + + while (stopx <= stopy) { + _fillEllipseSection(x, y, x0, y0, color, option); + x++; + stopx += ryry2; + err += xchg; + xchg += ryry2; + if (2 * err + ychg > 0) { + y--; + stopy -= rxrx2; + err += ychg; + ychg += rxrx2; + } + } +} + +void Graphics2D::drawRFrame(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, + uint16_t color) { // see p3dt_gfx_2d_license.txt + + uint16_t xl; + uint16_t yu; + + xl = x; + xl += r; + yu = y; + yu += r; + + { + uint16_t yl; + uint16_t xr; + + xr = x; + xr += w; + xr -= r; + xr -= 1; + + yl = y; + yl += h; + yl -= r; + yl -= 1; + + drawCircle(xl, yu, r, color, DRAW_UPPER_LEFT); + drawCircle(xr, yu, r, color, DRAW_UPPER_RIGHT); + drawCircle(xl, yl, r, color, DRAW_LOWER_LEFT); + drawCircle(xr, yl, r, color, DRAW_LOWER_RIGHT); + } + + { + uint16_t ww; + uint16_t hh; + + ww = w; + ww -= r; + ww -= r; + hh = h; + hh -= r; + hh -= r; + + xl++; + yu++; + + if (ww >= 3) { + ww -= 2; + h--; + drawHLine(xl, y, ww, color); + drawHLine(xl, y + h, ww, color); + } + + if (hh >= 3) { + hh -= 2; + w--; + drawVLine(x, yu, hh, color); + drawVLine(x + w, yu, hh, color); + } + } +} + +void Graphics2D::fillRFrame(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, + uint16_t color) { // see p3dt_gfx_2d_license.txt + //Prevent infinite looping + if(h < 2 * r) return; + + uint16_t xl; + uint16_t yu; + uint16_t yl; + uint16_t xr; + + xl = x; + xl += r; + yu = y; + yu += r; + + xr = x; + xr += w; + xr -= r; + xr -= 1; + + yl = y; + yl += h; + yl -= r; + yl -= 1; + + fillCircle(xl, yu, r, color, DRAW_UPPER_LEFT); + fillCircle(xr, yu, r, color, DRAW_UPPER_RIGHT); + fillCircle(xl, yl, r, color, DRAW_LOWER_LEFT); + fillCircle(xr, yl, r, color, DRAW_LOWER_RIGHT); + + { + uint16_t ww; + uint16_t hh; + + ww = w; + ww -= r; + ww -= r; + xl++; + yu++; + + if (ww >= 3) { + ww -= 2; + fillFrame(xl, y, ww, r + 1, color); + fillFrame(xl, yl, ww, r + 1, color); + } + + hh = h; + hh -= r; + hh -= r; + // h--; + if (hh >= 3) { + hh -= 2; + fillFrame(x, yu, w, hh, color); + } + } +} + +/** + * @brief Draw N ticks around the clock to visualize the hours. + * + * @param cx center x axis + * @param cy center y axis + * @param r1 radius from the begin of the tick. + * @param r2 radius from the end of the tick. + * @param nTicks number of ticks to draw + * @param color color code + */ +void Graphics2D::drawNTicks(int16_t cx, int16_t cy, int16_t r1, int16_t r2, int16_t nTicks, uint16_t color, int16_t skip_every_nth) { + if (360 % nTicks != 0) { + const float deltaAngle = 360.0f / nTicks; + for (int h = nTicks; h >= 0; --h) { + if (h % skip_every_nth != 0) + drawTick(cx, cy, r1, r2, h * deltaAngle, color); + } + } else { + const int deltaAngle = 360 / nTicks; + for (int h = nTicks; h >= 0; --h) { + if (h % skip_every_nth != 0) + drawTick(cx, cy, r1, r2, h * deltaAngle, color); + } + } +} + +/** + * @brief Draw N ticks around the clock to visualize the hours. + * + * @param cx center x axis + * @param cy center y axis + * @param r1 radius from the begin of the tick. + * @param r2 radius from the end of the tick. + * @param nTicks number of ticks to draw + * @param color color code + */ + +void Graphics2D::drawNTicksAA(int16_t cx, int16_t cy, int16_t r1, int16_t r2, int16_t nTicks, uint16_t color, int16_t skip_every_nth) { + if (360 % nTicks != 0) { + const float deltaAngle = 360.0f / nTicks; + for (int h = nTicks-1; h >= 0; --h) { + if (h % skip_every_nth != 0) + drawTickAA(cx, cy, r1, r2, h * deltaAngle, color); + } + } else { + const int deltaAngle = 360 / nTicks; + for (int h = nTicks-1; h >= 0; --h) { + if (h % skip_every_nth != 0) + drawTickAA(cx, cy, r1, r2, h * deltaAngle, color); + } + } +} + +/** + * Draw an arc + * + * @param cx Arc X center coordinates + * @param cy Arc Y center coordinates + * @param start Beginning angle of the arc (in deg). O° is equivalent to 12AM + * @param stop End angle of the arc (in deg). + * @param steps Number of lines that will compose the arc. + * @param radius Radius of the arc from the cx/cy center + * @param lineRadius Radius of the line. Example : radius = 1 give a line of 4 px of diameter, radius 2 -> 8px, + * etc.... + * @param color Color code of the arc + * @param highQuality + * @param anti_alias + */ +void Graphics2D::drawArc(int16_t cx, int16_t cy, float start, float stop, int16_t steps, int16_t radius, int16_t lineRadius, + uint16_t color, bool highQuality, bool anti_alias) { + + int32_t old_x = radius * 4; // impossible value + int32_t old_y = radius * 4; + for (float alpha = start; alpha <= stop; alpha += 0.1f) { + int32_t x = rpx(cx, radius, alpha); + int32_t y = rpy(cy, radius, alpha); + if (old_x != x || old_y != y) { + if (anti_alias) + fillCircleAA(x, y, lineRadius, color); + else + fillCircle(x, y, lineRadius, color); + } + old_x = x; + old_y = y; + } + return; +} + +void Graphics2D::drawBWBitmap(int16_t x0, int16_t y0, int16_t cnt, int16_t h, uint8_t* bitmap, uint16_t color, + uint16_t bgColor, bool drawBackground) { + // cnt: Number of bytes of the bitmap in horizontal direction. The width of the bitmap is cnt*8. + // h: Height of the bitmap. + + for (int32_t x = 0; x < cnt; x++) { + for (int32_t y = 0; y < h; y++) { + uint8_t bits = bitmap[x + y * cnt]; + for (uint8_t b = 1; b <= 8; b++) { + if (bits & (1 << (8 - b))) { + drawPixel(x * 8 + x0 + b, y + y0, color); + } else if (drawBackground) { + drawPixel(x * 8 + x0 + b, y + y0, bgColor); + } + } + } + } +} + +/** + * @brief Fill all the display with a color. + * + * Used for initialisation of the display with a background color. + * + * @param color Color code + */ +void Graphics2D::fill(uint16_t color) { + for (int16_t x = width-1; x >= 0; --x) { + for (int16_t y = height-1; y >= 0 ; --y) { + drawPixel(x, y, color); + } + } +} + +void Graphics2D::dim(uint8_t amount) { + for (int16_t x = width-1; x >= 0; --x) { + for (int16_t y = height-1; y >= 0 ; --y) { + drawPixel(x, y, dimColor(getPixel(x, y), amount)); + } + } +} + +void Graphics2D::drawGraphics2D(int16_t offsetX, int16_t offsetY, Graphics2D* source) { + for (int16_t y = source->getHeight()-1; y >= 0; --y) { + for (int16_t x = source->getWidth() - 1; x >= 0; --x) { + drawPixel(x + offsetX, y + offsetY, source->getPixel(x, y)); + } + } +} + +void Graphics2D::drawGraphics2D(int16_t offsetX, int16_t offsetY, Graphics2D* source, int16_t sourceOffsetX, + int16_t sourceOffsetY, int16_t sourceWidth, int16_t sourceHeight) { + for (int16_t x = sourceWidth - 1; x >= 0; --x) { + for (int16_t y = sourceHeight - 1; y >= 0; --y) { + drawPixel(x + offsetX, y + offsetY, source->getPixel(x + sourceOffsetX, y + sourceOffsetY)); + } + } +} + +// draw scaled by 2x +void Graphics2D::drawGraphics2D_2x(int16_t offsetX, int16_t offsetY, Graphics2D* source) { + for (int32_t x = source->getWidth() * 2 - 1; x >= 0; --x) { + for (int32_t y = source->getHeight() * 2 -1; y >= 0; --y) { + drawPixel(x + offsetX, y + offsetY, source->getPixel(x / 2, y / 2)); + } + } +} + +// draw section scaled by 2x +void Graphics2D::drawGraphics2D_2x(int16_t offsetX, int16_t offsetY, Graphics2D* source, int16_t sourceOffsetX, + int16_t sourceOffsetY, int16_t sourceWidth, int16_t sourceHeight) { + for (int16_t x = sourceWidth * 2 - 1; x >= 0; --x) { + for (int16_t y = sourceHeight * 2 -1; y >= 0; --y) { + drawPixel(x + offsetX, y + offsetY, source->getPixel(sourceOffsetX + x / 2, sourceOffsetY + y / 2)); + } + } +} + +#ifdef ROTATE_LEGACY +// this rotate function is faster, but it has artifacts +void Graphics2D::drawGraphics2D_rotatedLegacy(uint16_t offsetX, uint16_t offsetY, Graphics2D* source, uint16_t rotationX, + uint16_t rotationY, float angle) { + float cosA = cosh(angle); + float sinA = sinh(angle); + for (uint16_t x = 0; x < source->getWidth(); x++) { + for (uint16_t y = 0; y < source->getHeight(); y++) { + int32_t newX = (x - rotationX) * cosA + (y - rotationY) * sinA; + int32_t newY = (y - rotationY) * cosA - (x - rotationX) * sinA; + drawPixel(newX + offsetX, newY + offsetY, source->getPixel(x, y)); + } + } +} +#endif + +void Graphics2D::drawGraphics2D_rotated(int16_t offsetX, int16_t offsetY, Graphics2D* source, int16_t rx, int16_t ry, + float angle) { + float cosA = cosf(angle); + float sinA = sinf(angle); + // rotateX = (x - rx) * cosf(angle) + (y - ry) * sinf(angle); + // rotateY = (y - ry) * cosf(angle) - (x - rx) * sinf(angle); + + // first calculate the bounding box of the new image + // // top left + int32_t tl_x = rotateX(0, 0, rx, ry, cosA, sinA); + int32_t tl_y = rotateY(0, 0, rx, ry, cosA, sinA); + // // top right + int32_t tr_x = rotateX(source->getWidth() - 1, 0, rx, ry, cosA, sinA); + int32_t tr_y = rotateY(source->getWidth() - 1, 0, rx, ry, cosA, sinA); + + // // bottom left + int32_t bl_x = rotateX(0, source->getHeight() - 1, rx, ry, cosA, sinA); + int32_t bl_y = rotateY(0, source->getHeight() - 1, rx, ry, cosA, sinA); + + // // bottom right + int32_t br_x = rotateX(source->getWidth(), source->getHeight(), rx, ry, cosA, sinA); + int32_t br_y = rotateY(source->getWidth(), source->getHeight(), rx, ry, cosA, sinA); + + // debug: draw rotated image + // this->drawLine(offsetX + tl_x, offsetY + tl_y, offsetX + tr_x, offsetY + tr_y, rgb565(255, 0, 0)); + // this->drawLine(offsetX + tr_x, offsetY + tr_y, offsetX + br_x, offsetY + br_y, rgb565(255, 0, 0)); + // this->drawLine(offsetX + bl_x, offsetY + bl_y, offsetX + br_x, offsetY + br_y, rgb565(255, 0, 0)); + // this->drawLine(offsetX + bl_x, offsetY + bl_y, offsetX + tl_x, offsetY + tl_y, rgb565(255, 0, 0)); + + // determine bounding box + int32_t boxX = min(tl_x, min(tr_x, min(bl_x, br_x))); + int32_t boxY = min(tl_y, min(tr_y, min(bl_y, br_y))); + int32_t boxW = max(tl_x, max(tr_x, max(bl_x, br_x))) - boxX; + int32_t boxH = max(tl_y, max(tr_y, max(bl_y, br_y))) - boxY; + + // debug: draw bounding box + // this->drawFrame(boxX + offsetX, boxY + offsetY, boxW, boxH, rgb565(0, 255, 0)); + cosA = cosA; // cosA = cos(-angle); + sinA = -sinA; //sinA = sin(-angle); + for (int16_t x = boxX; x < boxX + boxW; x++) { + for (int16_t y = boxY; y < boxY + boxH; y++) { + if (pointInsideTriangle(x, y, tl_x, tl_y, tr_x, tr_y, br_x, br_y)) { + int16_t origX = rotateX(x, y, 0, 0, cosA, sinA); + int16_t origY = rotateY(x, y, 0, 0, cosA, sinA); + drawPixel(x + offsetX, y + offsetY, source->getPixel(origX + rx, origY + ry)); + } else if (pointInsideTriangle(x, y, tl_x, tl_y, bl_x, bl_y, br_x, br_y)) { + int16_t origX = rotateX(x, y, 0, 0, cosA, sinA); + int16_t origY = rotateY(x, y, 0, 0, cosA, sinA); + drawPixel(x + offsetX, y + offsetY, source->getPixel(origX + rx, origY + ry)); + } + } + } +} diff --git a/src/gfx_util.cpp b/src/gfx_util.cpp index 425a5b9c5..6202ee13c 100644 --- a/src/gfx_util.cpp +++ b/src/gfx_util.cpp @@ -2,26 +2,21 @@ #include -uint16_t rgb565(uint8_t red, uint8_t green, uint8_t blue) { - return ((red & 0b00011111000) << 8) | ((green & 0b00011111100) << 3) | (blue >> 3); -} - -uint32_t rgb888(uint8_t red, uint8_t green, uint8_t blue) { - return ((uint32_t)red << 16) | ((uint32_t)green << 8) | (uint32_t)blue; -} +uint16_t blend(uint16_t target, uint16_t source, float alpha) { + uint8_t r = rgb565_red(source) * alpha + rgb565_red(target) * (1.0f - alpha); + uint8_t g = rgb565_green(source) * alpha + rgb565_green(target) * (1.0f - alpha); + uint8_t b = rgb565_blue(source) * alpha + rgb565_blue(target) * (1.0f - alpha); -uint16_t rgb888to565(uint32_t rgb888) { - return rgb565(rgb888_red(rgb888), rgb888_green(rgb888), rgb888_blue(rgb888)); + return rgb565(r, g, b); } -uint32_t rgb565to888(uint16_t rgb565) { - return rgb888(rgb565_red(rgb565), rgb565_green(rgb565), rgb565_blue(rgb565)); -} +// optimized integer version +uint16_t blend(uint16_t target, uint16_t source, uint8_t alpha) { + const uint8_t a_inv = 255 - alpha; -uint16_t blend(uint16_t target, uint16_t source, float alpha) { - uint8_t r = rgb565_red(source) * alpha + rgb565_red(target) * (1.0 - alpha); - uint8_t g = rgb565_green(source) * alpha + rgb565_green(target) * (1.0 - alpha); - uint8_t b = rgb565_blue(source) * alpha + rgb565_blue(target) * (1.0 - alpha); + uint8_t r = (rgb565_red(source) * alpha + rgb565_red(target) * a_inv) / 255; + uint8_t g = (rgb565_green(source) * alpha + rgb565_green(target) * a_inv) / 255; + uint8_t b = (rgb565_blue(source) * alpha + rgb565_blue(target) * a_inv) / 255; return rgb565(r, g, b); } @@ -57,36 +52,6 @@ uint16_t changeColor(uint16_t oc, float amount) { return nc; } -uint8_t rgb565_red(uint16_t rgb565) { - // |rrrrrggg|gggbbbbb| - return (rgb565 >> 8) & 0b11111000; -} - -uint8_t rgb565_green(uint16_t rgb565) { - // |rrrrrggg|gggbbbbb| - return (rgb565 >> 3) & 0b11111100; -} - -uint8_t rgb565_blue(uint16_t rgb565) { - // |rrrrrggg|gggbbbbb| - return (rgb565 << 3); -} - -uint8_t rgb888_red(uint32_t rgb888) { - // |rrrrrrrr|gggggggg|bbbbbbbb| - return rgb888 >> 16; -} - -uint8_t rgb888_green(uint32_t rgb888) { - // |rrrrrrrr|gggggggg|bbbbbbbb| - return rgb888 >> 8; -} - -uint8_t rgb888_blue(uint32_t rgb888) { - // |rrrrrrrr|gggggggg|bbbbbbbb| - return rgb888; -} - // Shamelessly copied from // https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both void hsvToRgb(const unsigned char& h, const unsigned char& s, const unsigned char& v, unsigned char& r, diff --git a/src/globals.cpp b/src/globals.cpp index fd6dc2743..d06082260 100644 --- a/src/globals.cpp +++ b/src/globals.cpp @@ -5,4 +5,12 @@ namespace OswGlobals { RTC_DATA_ATTR size_t main_AppIndex = OswAppDrawer::UNDEFINED_SLEEP_APP_INDEX; OswAppDrawer main_mainDrawer{&main_AppIndex}; std::unique_ptr main_tutorialApp; -} \ No newline at end of file +bool main_delayedAppInit = true; + +#ifdef OSW_EMULATOR +void resetGlobals() { + main_delayedAppInit = true; + main_mainDrawer.reset(); +} +#endif +} diff --git a/src/hal/Arduino_Canvas_Graphics2D.cpp b/src/hal/Arduino_Canvas_Graphics2D.cpp index 65dfba64c..c75186d52 100644 --- a/src/hal/Arduino_Canvas_Graphics2D.cpp +++ b/src/hal/Arduino_Canvas_Graphics2D.cpp @@ -5,30 +5,15 @@ #endif #include -#include "config_defaults.h" +Arduino_Canvas_Graphics2D::Arduino_Canvas_Graphics2D(int16_t w, int16_t h, Arduino_G* output, int16_t output_x, int16_t output_y) + : Graphics2DPrint(w, h, DISP_CHUNK_H_LD, true), _output(output), _output_x(output_x), _output_y(output_y) +{} -Arduino_Canvas_Graphics2D::Arduino_Canvas_Graphics2D(int16_t w, int16_t h, Arduino_G* output, int16_t output_x, - int16_t output_y) - : Graphics2DPrint(w, h, DISP_CHUNK_H, true), _output(output), _output_x(output_x), _output_y(output_y) {} - -void Arduino_Canvas_Graphics2D::begin(int32_t speed) { - _output->begin(speed); - // _output->fillScreen(BLACK); -} -void Arduino_Canvas_Graphics2D::writePixelPreclipped(int16_t x, int16_t y, uint16_t color) { - this->drawPixel(x, y, color); -} -void Arduino_Canvas_Graphics2D::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { - this->drawVLine(x, y, h, color); -} -void Arduino_Canvas_Graphics2D::writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { - this->drawHLine(x, y, w, color); -} void Arduino_Canvas_Graphics2D::flush() { // only flush if there is a buffer if (this->hasBuffer()) { - uint8_t chunkHeight = this->getChunkHeight(); - for (uint8_t chunk = 0; chunk < this->numChunks(); chunk++) { + uint8_t chunkHeight = 1 << chunkHeightLd; + for (uint8_t chunk = 0; chunk < this->getNumChunks(); chunk++) { _output->draw16bitRGBBitmap(this->getChunkOffset(chunk), chunk * chunkHeight, this->getChunk(chunk), this->getChunkWidth(chunk), chunkHeight); } diff --git a/src/hal/buttons.cpp b/src/hal/buttons.cpp index 5dc821157..862eb48d4 100644 --- a/src/hal/buttons.cpp +++ b/src/hal/buttons.cpp @@ -5,23 +5,23 @@ #include "osw_pins.h" const char* ButtonNames[BTN_NUMBER] = BTN_NAME_ARRAY; +#if OSW_PLATFORM_IS_FLOW3R_BADGE != 1 static uint8_t buttonPins[BTN_NUMBER] = BTN_PIN_ARRAY; static uint8_t buttonClickStates[BTN_NUMBER] = BTN_STATE_ARRAY; +#endif static int16_t buttonPositionsX[BTN_NUMBER] = BTN_POSX_ARRAY; static int16_t buttonPositionsY[BTN_NUMBER] = BTN_POSY_ARRAY; static bool buttonIsTop[BTN_NUMBER] = BTN_POS_ISTOP_ARRAY; static bool buttonIsLeft[BTN_NUMBER] = BTN_POS_ISLEFT_ARRAY; -void OswHal::setupButtons(void) { - // rtc_gpio_deinit(GPIO_NUM_0); - // rtc_gpio_deinit(GPIO_NUM_10); - // rtc_gpio_deinit(GPIO_NUM_13); +void OswHal::setupButtons() { +#if OSW_PLATFORM_IS_FLOW3R_BADGE != 1 pinMode(BTN_1, INPUT); pinMode(BTN_2, INPUT); pinMode(BTN_3, INPUT); -#if defined(GPS_EDITION) || defined(GPS_EDITION_ROTATED) - - pinMode(VIBRATE, OUTPUT); +#endif +#if OSW_PLATFORM_HARDWARE_VIBRATE != 0 + pinMode(OSW_PLATFORM_HARDWARE_VIBRATE, OUTPUT); #endif // Buttons (Engine) @@ -34,23 +34,34 @@ void OswHal::setupButtons(void) { } } -#if defined(GPS_EDITION) || defined(GPS_EDITION_ROTATED) - +#if OSW_PLATFORM_HARDWARE_VIBRATE != 0 void OswHal::vibrate(long millis) { - digitalWrite(VIBRATE, HIGH); + digitalWrite(OSW_PLATFORM_HARDWARE_VIBRATE, HIGH); OSW_LOG_D("Vibrate for: ", millis); delay(millis); - digitalWrite(VIBRATE, LOW); + digitalWrite(OSW_PLATFORM_HARDWARE_VIBRATE, LOW); } #endif -void OswHal::checkButtons(void) { - // Buttons (Engine) +void OswHal::checkButtons() { +#if OSW_PLATFORM_IS_FLOW3R_BADGE == 1 + uint8_t ur = ~this->readGpioExtender(); + bool r1 = ur & 0b00000001; + bool l1 = ur & 0b10000000; + bool r2 = ur & 0b00100000; + bool l2 = ur & 0b00010000; + _btnIsDown[0] = !digitalRead(0) or !digitalRead(3); + _btnIsDown[1] = l1 or l2; + _btnIsDown[2] = r1 or r2; + if(_btnIsDown[0] or _btnIsDown[1] or _btnIsDown[2]) + this->noteUserInteraction(); // Button pressing counts as user interaction +#else for (uint8_t i = 0; i < BTN_NUMBER; i++) { _btnIsDown[i] = digitalRead(buttonPins[i]) == buttonClickStates[i]; if(_btnIsDown[i]) this->noteUserInteraction(); // Button pressing counts as user interaction } +#endif for (uint8_t i = 0; i < BTN_NUMBER; i++) { _btnGoneUp[i] = _btnLastState[i] == true && _btnIsDown[i] == false; @@ -134,4 +145,4 @@ bool OswHal::btnIsLeftAligned(Button btn) { void OswHal::getButtonCoordinates(Button btn, int16_t& x, int16_t& y) { x = buttonPositionsX[btn]; y = buttonPositionsY[btn]; -} \ No newline at end of file +} diff --git a/src/hal/devices.cpp b/src/hal/devices.cpp index 34e289155..c15bae3c6 100644 --- a/src/hal/devices.cpp +++ b/src/hal/devices.cpp @@ -1,3 +1,4 @@ +#include OSW_TARGET_PLATFORM_HEADER #include #include @@ -6,6 +7,12 @@ OswHal::Devices::Devices() { #if OSW_PLATFORM_HARDWARE_BMA400 == 1 this->bma400 = new OswDevices::BMA400(); #endif +#if OSW_PLATFORM_HARDWARE_BMI270 == 1 + this->bmi270 = new OswDevices::BMI270(); +#endif +#if OSW_PLATFORM_HARDWARE_BMP581 == 1 + this->bmp581 = new OswDevices::BMP581(); +#endif #if OSW_PLATFORM_HARDWARE_QMC5883L == 1 this->qmc5883l = new OswDevices::QMC5883L(); #endif @@ -39,6 +46,9 @@ OswHal::Devices::~Devices() { #if OSW_PLATFORM_HARDWARE_QMC5883L == 1 delete this->qmc5883l; #endif +#if OSW_PLATFORM_HARDWARE_BMI270 == 1 + delete this->bmi270; +#endif #if OSW_PLATFORM_HARDWARE_BMA400 == 1 delete this->bma400; #endif @@ -57,4 +67,4 @@ void OswHal::Devices::update() { void OswHal::Devices::stop(const bool& toLightSleep) { for(auto& d : *OswDevice::getAllDevices()) d->stop(); -} \ No newline at end of file +} diff --git a/src/hal/display.cpp b/src/hal/display.cpp index 4d26cb6ee..5a834fdb2 100644 --- a/src/hal/display.cpp +++ b/src/hal/display.cpp @@ -1,5 +1,5 @@ -#include #ifndef OSW_EMULATOR +#include #include #include #endif @@ -12,14 +12,24 @@ #include "config_defaults.h" #include "osw_hal.h" #include "osw_pins.h" +#include OSW_TARGET_PLATFORM_HEADER -#ifndef OSW_EMULATOR -Arduino_DataBus* bus = new Arduino_ESP32SPI(TFT_DC, TFT_CS, TFT_SCK, TFT_MOSI, TFT_MISO, VSPI /* spi_num */); -#if defined(GPS_EDITION_ROTATED) -Arduino_GC9A01* tft = new Arduino_GC9A01(bus, TFT_RST, 1 /* rotation */, true /* IPS */); -#else -Arduino_GC9A01* tft = new Arduino_GC9A01(bus, TFT_RST, 0 /* rotation */, true /* IPS */); +#if OSW_PLATFORM_HARDWARE_DISPLAY_RST == 0 +#define OSW_PLATFORM_HARDWARE_DISPLAY_RST -1 #endif +#ifndef OSW_PLATFORM_HARDWARE_DISPLAY_ROTATION +#define OSW_PLATFORM_HARDWARE_DISPLAY_ROTATION -1 +#endif + +#ifndef OSW_EMULATOR +Arduino_DataBus* bus = new Arduino_ESP32SPI( + OSW_PLATFORM_HARDWARE_DISPLAY_DC, + OSW_PLATFORM_HARDWARE_DISPLAY_CS, + OSW_PLATFORM_HARDWARE_DISPLAY_SCK, + OSW_PLATFORM_HARDWARE_DISPLAY_MOSI, + -1, // no data coming back + OSW_PLATFORM_HARDWARE_DISPLAY_SPI_NUM); +Arduino_GC9A01* tft = new Arduino_GC9A01(bus, OSW_PLATFORM_HARDWARE_DISPLAY_RST, OSW_PLATFORM_HARDWARE_DISPLAY_ROTATION, true /* IPS */); #else FakeDisplay* tft = nullptr; #endif @@ -55,12 +65,6 @@ bool OswHal::displayBufferEnabled() { } void OswHal::setupDisplay() { -#ifdef ESP32 - // nasty hack to avoid display flicker - ledcAttachPin(TFT_LED, 1); - ledcSetup(1, 12000, 8); // 12 kHz PWM, 8-bit resolution - ledcWrite(1, 0); -#endif #ifdef OSW_EMULATOR // Always fetch the current instance, just in case the emulator replaced it in the meantime (and as tft is not bound to this objects lifetime) tft = fakeDisplayInstance.get(); @@ -71,6 +75,12 @@ void OswHal::setupDisplay() { this->canvas = new Arduino_Canvas_Graphics2D(DISP_W, DISP_H, tft); this->canvas->begin(); // use default speed and default SPI mode + + // Another nasty hack to avoid display flicker when turning on + // Let the display settle a bit befor sending commands to it. + // This avoids a partially white screen on turning on the device. + // 45 ms is tested on an V3.3 device. + delay(45); this->displayOn(); } @@ -86,11 +96,12 @@ void OswHal::flushCanvas(void) { } void OswHal::displayOff(void) { -#ifdef ESP32 - ledcDetachPin(TFT_LED); +#if OSW_PLATFORM_HARDWARE_DISPLAY_LED != 0 + ledcDetachPin(OSW_PLATFORM_HARDWARE_DISPLAY_LED); + // just pull down the backlight pin + pinMode(OSW_PLATFORM_HARDWARE_DISPLAY_LED, OUTPUT); + digitalWrite(OSW_PLATFORM_HARDWARE_DISPLAY_LED, LOW); #endif - pinMode(TFT_LED, OUTPUT); - digitalWrite(TFT_LED, LOW); tft->displayOff(); _screenOffSince = millis(); } @@ -104,9 +115,13 @@ unsigned long OswHal::screenOffTime() { void OswHal::displayOn() { _screenOnSince = millis(); -#ifdef ESP32 - ledcAttachPin(TFT_LED, 1); +#if OSW_PLATFORM_HARDWARE_DISPLAY_LED != 0 + ledcAttachPin(OSW_PLATFORM_HARDWARE_DISPLAY_LED, 1); ledcSetup(1, 12000, 8); // 12 kHz PWM, 8-bit resolution +#else +#ifndef OSW_EMULATOR // meh, the emulator ignores this for now... +#warning "Display LED pin unconfigured; can't control backlight brightness" +#endif #endif setBrightness(OswConfigAllKeys::settingDisplayBrightness.get(), false); tft->displayOn(); @@ -114,10 +129,8 @@ void OswHal::displayOn() { void OswHal::setBrightness(uint8_t b, bool storeToNVS) { _brightness = b; -#ifdef ESP32 +#if OSW_PLATFORM_HARDWARE_DISPLAY_LED != 0 ledcWrite(1, _brightness); -#else - digitalWrite(TFT_LED, _brightness); #endif if(storeToNVS) { OswConfig::getInstance()->enableWrite(); @@ -169,10 +182,8 @@ uint8_t OswHal::screenBrightness(bool checkHardware) { uint8_t screen_brightness = 0; if(checkHardware) { -#ifdef ESP32 +#if OSW_PLATFORM_HARDWARE_DISPLAY_LED != 0 screen_brightness = ledcRead(1); -#else - screen_brightness = digitalRead(TFT_LED); #endif _brightness = screen_brightness; } diff --git a/src/hal/environment.cpp b/src/hal/environment.cpp index 4338c877b..df06fbc68 100644 --- a/src/hal/environment.cpp +++ b/src/hal/environment.cpp @@ -1,3 +1,5 @@ +#include OSW_TARGET_PLATFORM_HEADER +#if OSW_PLATFORM_ENVIRONMENT == 1 #include #ifdef OSW_EMULATOR #include @@ -82,6 +84,12 @@ float OswHal::Environment::getAccelerationZ() { return this->accelSensor->getAccelerationZ(); } +OswAccelerationProvider::ActivityMode OswHal::Environment::getActivityMode() { + if(!this->accelSensor) + throw std::runtime_error("No acceleration provider!"); + return this->accelSensor->getActivityMode(); +} + uint32_t OswHal::Environment::getStepsToday() { if(!this->accelSensor) throw std::runtime_error("No acceleration provider!"); @@ -124,10 +132,9 @@ void OswHal::Environment::setupStepStatistics() { * @param alwaysPrintStepStatistics Set to true to print the step history to the console */ void OswHal::Environment::commitStepStatistics(const bool& alwaysPrintStepStatistics) { - uint32_t currDoM = 0; // Unused, but required by function signature - uint32_t currDoW = 0; - OswHal::getInstance()->getLocalDate(&currDoM, &currDoW); - bool changedDoW = currDoW != this->_stepsLastDoW; + OswDate oswDate = { }; + OswHal::getInstance()->getLocalDate(oswDate); + bool changedDoW = oswDate.weekDay != this->_stepsLastDoW; if(changedDoW) { Preferences prefs; bool res = prefs.begin(PREFS_STEPS, false); // Open in RW, just in case @@ -136,14 +143,14 @@ void OswHal::Environment::commitStepStatistics(const bool& alwaysPrintStepStatis this->_stepsSum += currentSteps; // Let's just hope this never rolls over... OswHal::getInstance()->environment()->resetStepCount(); if(OswConfigAllKeys::stepsHistoryClear.get()) { - if(currDoW > this->_stepsLastDoW) { - // set stepscache to 0 in ]lastDoW, currDoW[ - for(uint32_t i = currDoW; this->_stepsLastDoW + 1 < i; i--) + if(oswDate.weekDay > this->_stepsLastDoW) { + // set stepscache to 0 in ]lastDoW, oswDate.weekDay[ + for(uint32_t i = oswDate.weekDay; this->_stepsLastDoW + 1 < i; i--) this->_stepsCache[i - 1] = 0; } else { // set > last dow to 0 && set < curr dow to 0 - if(currDoW > 0) - for(uint32_t i = currDoW; 0 < i; i--) + if(oswDate.weekDay > 0) + for(uint32_t i = oswDate.weekDay; 0 < i; i--) this->_stepsCache[i - 1] = 0; for(uint32_t i = this->_stepsLastDoW + 1; i < 7; i++) this->_stepsCache[i] = 0; @@ -152,11 +159,11 @@ void OswHal::Environment::commitStepStatistics(const bool& alwaysPrintStepStatis // Check if today is the initialization day short resetDay = OswConfigAllKeys::resetDay.get(); - if ((resetDay >= 0 && resetDay < 8) && (unsigned short) resetDay == currDoW + 1) // (e.g. 1 - 7 are days, 0 is disabled) + if ((resetDay >= 0 && resetDay < 8) && (unsigned short) resetDay == oswDate.weekDay + 1) // (e.g. 1 - 7 are days, 0 is disabled) this->_stepsSum = 0; - this->_stepsLastDoW = currDoW; - OSW_LOG_D("Updated steps from DoW ", this->_stepsLastDoW, " to DoW ", currDoW); + this->_stepsLastDoW = oswDate.weekDay; + OSW_LOG_D("Updated steps from DoW ", this->_stepsLastDoW, " to DoW ", oswDate.weekDay); // write step cache + stepsum res = prefs.putBytes(PREFS_STEPS_STATS, &this->_stepsCache, sizeof(this->_stepsCache)) == sizeof(this->_stepsCache); @@ -170,14 +177,14 @@ void OswHal::Environment::commitStepStatistics(const bool& alwaysPrintStepStatis #ifndef NDEBUG if(changedDoW or alwaysPrintStepStatistics) { - String stepHistoryDbgMsg = "Current step history (day " + String(currDoW) + ", today " + String(OswHal::getInstance()->environment()->getStepsToday()) + ", sum " + String(this->_stepsSum) + ") is: {"; + String stepHistoryDbgMsg = "Current step history (day " + String(oswDate.weekDay) + ", today " + String(OswHal::getInstance()->environment()->getStepsToday()) + ", sum " + String(this->_stepsSum) + ") is: {"; for(size_t i = 0; i < 7; i++) { if(i > 0) stepHistoryDbgMsg += ", "; - if(i == currDoW) + if(i == oswDate.weekDay) stepHistoryDbgMsg += "["; stepHistoryDbgMsg += this->_stepsCache[i]; - if(i == currDoW) + if(i == oswDate.weekDay) stepHistoryDbgMsg += "]"; } stepHistoryDbgMsg += "}"; @@ -188,13 +195,11 @@ void OswHal::Environment::commitStepStatistics(const bool& alwaysPrintStepStatis uint32_t OswHal::Environment::getStepsOnDay(uint8_t dayOfWeek, bool lastWeek) { this->commitStepStatistics(); - uint32_t day = 0; - uint32_t weekday = 0; - OswHal::getInstance()->getLocalDate(&day, &weekday); - - if (!lastWeek and dayOfWeek == weekday) + OswDate oswDate = { }; + OswHal::getInstance()->getLocalDate(oswDate); + if (!lastWeek and dayOfWeek == oswDate.weekDay) return this->getStepsToday(); - else if(!lastWeek or (lastWeek and dayOfWeek == weekday)) + else if(!lastWeek or (lastWeek and dayOfWeek == oswDate.weekDay)) return this->_stepsCache[dayOfWeek]; else return 0; // In that case we don't have any history left anymore - just reply with a zero... @@ -217,11 +222,10 @@ uint32_t OswHal::Environment::getStepsTotalWeek() { #ifdef OSW_FEATURE_STATS_STEPS this->commitStepStatistics(); uint32_t sum = 0; - uint32_t currDoM = 0; // Unused, but required by function signature - uint32_t currDoW = 0; - OswHal::getInstance()->getLocalDate(&currDoM, &currDoW); + OswDate oswDate = { }; + OswHal::getInstance()->getLocalDate(oswDate); for (uint8_t i = 0; i < 7; i++) { - if (i == currDoW) { + if (i == oswDate.weekDay) { sum = sum + this->getStepsToday(); } sum = sum + this->_stepsCache[i]; @@ -250,9 +254,28 @@ float OswHal::Environment::getHumidity() { #endif #if OSW_PLATFORM_ENVIRONMENT_MAGNETOMETER == 1 +int OswHal::Environment::getMagnetometerX() { + if(!this->magSensor) + throw std::runtime_error("No magnetometer provider!"); + return this->magSensor->getMagnetometerX(); +} + +int OswHal::Environment::getMagnetometerY() { + if(!this->magSensor) + throw std::runtime_error("No magnetometer provider!"); + return this->magSensor->getMagnetometerY(); +} + +int OswHal::Environment::getMagnetometerZ() { + if(!this->magSensor) + throw std::runtime_error("No magnetometer provider!"); + return this->magSensor->getMagnetometerZ(); +} + int OswHal::Environment::getMagnetometerAzimuth() { if(!this->magSensor) throw std::runtime_error("No magnetometer provider!"); return this->magSensor->getMagnetometerAzimuth(); } -#endif \ No newline at end of file +#endif +#endif diff --git a/src/hal/esp32/sd_filesystem.cpp b/src/hal/esp32/sd_filesystem.cpp index 31c2608d7..b3c4e3792 100644 --- a/src/hal/esp32/sd_filesystem.cpp +++ b/src/hal/esp32/sd_filesystem.cpp @@ -31,4 +31,4 @@ bool SDFileSystemHal::initialize() { return true; } } -#endif \ No newline at end of file +#endif diff --git a/src/hal/esp32/spiffs_filesystem.cpp b/src/hal/esp32/spiffs_filesystem.cpp index 84fd68d5f..948d00b87 100644 --- a/src/hal/esp32/spiffs_filesystem.cpp +++ b/src/hal/esp32/spiffs_filesystem.cpp @@ -5,4 +5,4 @@ bool SPIFFSFileSystemHal::initialize() { // Mount the filesystem and register vfs return SPIFFS.begin(true, FS_MOUNT_POINT); } -#endif \ No newline at end of file +#endif diff --git a/src/hal/filesystem.cpp b/src/hal/filesystem.cpp index e9ffaf315..292ed33a1 100644 --- a/src/hal/filesystem.cpp +++ b/src/hal/filesystem.cpp @@ -4,4 +4,4 @@ void OswHal::setupFileSystem() { if (fileSystem != NULL && !fileSystem->initialize()) { perror("Failed to initialize osw filesystem"); } -} \ No newline at end of file +} diff --git a/src/hal/gps.cpp b/src/hal/gps.cpp index 4343579c6..81312a346 100644 --- a/src/hal/gps.cpp +++ b/src/hal/gps.cpp @@ -18,7 +18,7 @@ NMEAGPS* OswHal::gps(void) { void OswHal::setupGps(void) { pinMode(GPS_FON, OUTPUT); digitalWrite(GPS_FON, HIGH); - SerialGPS.begin(9600, SERIAL_8N1, RX1, TX1); + SerialGPS.begin(9600, SERIAL_8N1, GPS_RX1, GPS_TX1); } bool OswHal::hasGPS(void) { return _hasGPS; @@ -105,4 +105,4 @@ HardwareSerial OswHal::getSerialGPS(void) { return SerialGPS; } #endif -#endif \ No newline at end of file +#endif diff --git a/src/hal/power.cpp b/src/hal/power.cpp index 2c48553b0..6f771a4fa 100644 --- a/src/hal/power.cpp +++ b/src/hal/power.cpp @@ -14,6 +14,64 @@ #define V_REF 1100 // ADC reference voltage #define CHANNEL ADC2_CHANNEL_8 +// Some functions to determine the capacity of batteries +// see https://github.com/rlogiacco/BatterySense +// define one of the following +#define BATT_ASIGMOIDAL +//#define BATT_SIGMOIDAL +//#define BATT_LINEAR +//#define BATT_LEGACY + +/** + * Symmetric sigmoidal approximation + * https://www.desmos.com/calculator/7m9lu26vpy + * + * c - c / (1 + k*x/v)^3 + */ +static inline uint8_t sigmoidal(uint16_t voltage, uint16_t minVoltage, uint16_t maxVoltage) { + int volt_diff = maxVoltage - minVoltage; + if ( volt_diff <= 0) + volt_diff = 1; + + // slow + // uint8_t result = 110 - (110 / (1 + pow(1.468f * (voltage - minVoltage)/(volt_diff), 6f))); + + // steep + // uint8_t result = 102 - (102 / (1 + pow(1.621f * (voltage - minVoltage)/(volt_diff), 8.1f))); + + // normal + uint8_t result = 105 - (105 / (1 + powf(1.724f * (voltage - minVoltage) / volt_diff, 5.5f))); + return result >= 100 ? 100 : result; +} + +/** + * Asymmetric sigmoidal approximation + * https://www.desmos.com/calculator/oyhpsu8jnw + * + * c - c / [1 + (k*x/v)^4.5]^3 + */ +static inline uint8_t asigmoidal(uint16_t voltage, uint16_t minVoltage, uint16_t maxVoltage) { + int volt_diff = maxVoltage - minVoltage; + if ( volt_diff <= 0) + volt_diff = 1; + uint8_t result = 101 - (101 / powf(1 + powf(1.33f * (voltage - minVoltage) / volt_diff, 4.5f), 3)); + return result >= 100 ? 100 : result; +} + +/** + * Linear mapping + * https://www.desmos.com/calculator/sowyhttjta + * + * x * 100 / v + */ +static inline uint8_t linear(uint16_t voltage, uint16_t minVoltage, uint16_t maxVoltage) { + int volt_diff = maxVoltage - minVoltage; + if ( volt_diff <= 0) + volt_diff = 1; + + return (unsigned long)(voltage - minVoltage) * 100 / volt_diff; +} + uint16_t OswHal::getBatteryRawMin() { return this->powerPreferences.getUShort("-", 60); // Every battery should be able to deliver lower than this at some point } @@ -24,11 +82,19 @@ uint16_t OswHal::getBatteryRawMax() { void OswHal::setupPower(bool fromLightSleep) { if(!fromLightSleep) { +#if OSW_DEVICE_TPS2115A_STATPWR != 0 pinMode(OSW_DEVICE_TPS2115A_STATPWR, INPUT); +#endif +#if OSW_DEVICE_ESP32_BATLVL != 0 pinMode(OSW_DEVICE_ESP32_BATLVL, INPUT); +#endif bool res = powerPreferences.begin("osw-power", false); assert(res && "Could not initialize power preferences!"); +#if OSW_PLATFORM_DEFAULT_CPUFREQ != 0 this->setCPUClock(OSW_PLATFORM_DEFAULT_CPUFREQ); +#else +#warning "OSW_PLATFORM_DEFAULT_CPUFREQ is not set, so CPU frequency won't be configured!" +#endif } esp_sleep_wakeup_cause_t reason = esp_sleep_get_wakeup_cause(); if(reason == ESP_SLEEP_WAKEUP_TIMER) { @@ -70,19 +136,31 @@ void OswHal::updatePowerStatistics(uint16_t currBattery) { } } -bool OswHal::isCharging(void) { +bool OswHal::isCharging() { +#if OSW_DEVICE_TPS2115A_STATPWR != 0 return digitalRead(OSW_DEVICE_TPS2115A_STATPWR); // != 0 means there is V(IN2) in use +#else +#if OSW_PLATFORM_IS_FLOW3R_BADGE == 1 + return ~this->readGpioExtender() & 0b00000100; +#else + return false; +#endif +#endif } /** * Reports the average of numAvg subsequent measurements */ uint16_t OswHal::getBatteryRaw(const uint16_t numAvg) { +#if OSW_DEVICE_ESP32_BATLVL != 0 uint16_t b = 0; for (uint8_t i = 0; i < numAvg; i++) b = b + analogRead(OSW_DEVICE_ESP32_BATLVL); b = b / numAvg; return b > 40 ? b / 2 : b; +#else + return 0; // TODO we should properly report no battery information available +#endif } /** @@ -92,15 +170,23 @@ uint16_t OswHal::getBatteryRaw(const uint16_t numAvg) { uint8_t OswHal::getBatteryPercent(void) { const uint16_t batRaw = this->getBatteryRaw(); +#ifdef BATT_ASIGMOIDAL + return asigmoidal(batRaw, this->getBatteryRawMin(), this->getBatteryRawMax()); +#elif BATT_SIGMOIDAL + return sigmoidal(batRaw, this->getBatteryRawMin(), this->getBatteryRawMax()); +#elif BATT_LINEAR + return linear(batRaw, this->getBatteryRawMin(), this->getBatteryRawMax()); +#else // BATT_LEGACY + // https://en.wikipedia.org/wiki/Logistic_function - // The value for k (=12) is choosen by guessing, just make sure f(0) < 0.5 to indicate the calibration process... + // f(x)=L/(1+e(-k(x-x0))) + // The value for k (=12) is chosen by guessing, just make sure f(0) < 0.5 to indicate the calibration process... // Original Formula: 1/(1+e^(-12*(x-0.5))*((1/0.5)-1)) // Optimized Formula: 1/(1+e^(-12*(x-0.5))) const float minMaxDiff = (float) max(abs(this->getBatteryRawMax() - this->getBatteryRawMin()), 1); // To prevent division by zero const float batNormalized = ((float) batRaw - (float) this->getBatteryRawMin()) * (1.0f / minMaxDiff); - const float batTransformed = 1 / (1 + pow(2.71828, -12 * (batNormalized - 0.5))); - + const float batTransformed = 1.0f / (1 + powf(2.71828f, -12 * (batNormalized - 0.5f))); // Just in case here is a bug ;) // OSW_LOG_D("r", batRaw, @@ -111,6 +197,7 @@ uint8_t OswHal::getBatteryPercent(void) { // "t", batTransformed); return max(min((uint8_t) roundf(batTransformed * 100), (uint8_t) 100), (uint8_t) 0); +#endif } // float OswHal::getBatteryVoltage(void) { @@ -125,7 +212,7 @@ uint8_t OswHal::getBatteryPercent(void) { // esp_adc_cal_get_voltage(ADC_CHANNEL_8, &characteristics, &voltage); // // some dodgy math to get a representable value -// return voltage / (100.0) + 0.3; +// return voltage / (100.0f) + 0.3f; // } void OswHal::setCPUClock(uint8_t mhz) { @@ -141,11 +228,16 @@ uint8_t OswHal::getCPUClock() { } void OswHal::doSleep(bool deepSleep) { +#if OSW_PLATFORM_BLOCK_SLEEP == 1 + OSW_LOG_I("Sleeping is blocked by OSW_PLATFORM_BLOCK_SLEEP."); + this->noteUserInteraction(); // reset sleep timer + return; +#else this->stop(!deepSleep); // register user wakeup sources if (OswConfigAllKeys::buttonToWakeEnabled.get()) - // ore set Button1 wakeup if no sensor wakeups registered + // or set Button1 wakeup if no sensor wakeups registered esp_sleep_enable_ext0_wakeup(GPIO_NUM_0 /* BTN_0 */, LOW); // special handling as low is the trigger, otherwise ↓ bitmask should be used! /** @@ -181,6 +273,7 @@ void OswHal::doSleep(bool deepSleep) { esp_deep_sleep_start(); else esp_light_sleep_start(); +#endif } void OswHal::deepSleep() { @@ -188,6 +281,7 @@ void OswHal::deepSleep() { } void OswHal::lightSleep() { +#if OSW_PLATFORM_BLOCK_SLEEP != 1 if(!OswConfigAllKeys::lightSleepEnabled.get()) { // The light sleep was not enabled, ignore this request and go to deep sleep instead! OSW_LOG_D("Request for light sleep ignored, as only deep sleep is enabled."); @@ -196,6 +290,7 @@ void OswHal::lightSleep() { _isLightSleep = true; doSleep(false); } +#endif } void OswHal::handleWakeupFromLightSleep(void) { @@ -291,7 +386,8 @@ void OswHal::noteUserInteraction() { void OswHal::handleDisplayTimout() { // Did enough time pass since the last user interaction? - if(OswConfigAllKeys::settingDisplayTimeout.get() == 0 or this->_lastUserInteraction + OswConfigAllKeys::settingDisplayTimeout.get() * 1000 > millis()) + const int lastDisplayTimeout = OswConfigAllKeys::settingDisplayTimeout.get(); + if (lastDisplayTimeout == 0 or this->_lastUserInteraction + lastDisplayTimeout * 1000 > millis()) return; // Does the UI allow us to go to sleep? OswAppV2* app = OswUI::getInstance()->getRootApplication(); @@ -299,4 +395,4 @@ void OswHal::handleDisplayTimout() { return; this->lightSleep(); this->noteUserInteraction(); // Oh, we came back from sleep, so we are "interacting" with the watch -} \ No newline at end of file +} diff --git a/src/hal/sd.cpp b/src/hal/sd.cpp index 86d040504..40316f097 100644 --- a/src/hal/sd.cpp +++ b/src/hal/sd.cpp @@ -118,4 +118,4 @@ void OswHal::sdOff(void) { } #endif -#endif \ No newline at end of file +#endif diff --git a/src/hal/time.cpp b/src/hal/time.cpp index 63dbe32ad..a8d3b45b0 100644 --- a/src/hal/time.cpp +++ b/src/hal/time.cpp @@ -26,37 +26,37 @@ void OswHal::updateTimeProvider() { OSW_LOG_D("No provider for Time is available!"); } -void OswHal::getUTCTime(uint32_t* hour, uint32_t* minute, uint32_t* second) { +void OswHal::getUTCTime(OswTime& oswTime) { RtcDateTime d = RtcDateTime(); d.InitWithUnix32Time(this->getUTCTime()); - *hour = d.Hour(); - *minute = d.Minute(); - *second = d.Second(); + oswTime.hour = d.Hour(); + oswTime.minute = d.Minute(); + oswTime.second = d.Second(); } -void OswHal::getTime(time_t& offset, uint32_t* hour, uint32_t* minute, uint32_t* second, bool* afterNoon) { +void OswHal::getTime(time_t& offset, OswTime& oswTime) { RtcDateTime d = RtcDateTime(); d.InitWithUnix32Time(this->getTime(offset)); if (!OswConfigAllKeys::timeFormat.get()) { if (d.Hour() > 12) { - *hour = d.Hour() - 12; - if (afterNoon != nullptr) *afterNoon = true; + oswTime.hour = d.Hour() - 12; + oswTime.afterNoon = true; } else if (d.Hour() == 0) { - *hour = 12; - if (afterNoon != nullptr) *afterNoon = false; + oswTime.hour = 12; + oswTime.afterNoon = false; } else if (d.Hour() == 12) { - *hour = d.Hour(); - if (afterNoon != nullptr) *afterNoon = true; + oswTime.hour = d.Hour(); + oswTime.afterNoon = true; } else { - *hour = d.Hour(); - if (afterNoon != nullptr) *afterNoon = false; + oswTime.hour = d.Hour(); + oswTime.afterNoon = false; } } else { - *hour = d.Hour(); - if (afterNoon != nullptr) *afterNoon = false; + oswTime.hour = d.Hour(); + oswTime.afterNoon = false; } - *minute = d.Minute(); - *second = d.Second(); + oswTime.minute = d.Minute(); + oswTime.second = d.Second(); } /** @@ -122,27 +122,11 @@ time_t OswHal::getTime(time_t& offset) { return this->getUTCTime() + offset; } -void OswHal::getDate(time_t& offset, uint32_t* day, uint32_t* weekDay) { +void OswHal::getDate(time_t& offset, OswDate& oswDate) { RtcDateTime d = RtcDateTime(); d.InitWithUnix32Time(this->getTime(offset)); - *weekDay = d.DayOfWeek(); - *day = d.Day(); -} - -void OswHal::getDate(time_t& offset, uint32_t* day, uint32_t* month, uint32_t* year) { - RtcDateTime d = RtcDateTime(); - d.InitWithUnix32Time(this->getTime(offset)); - *day = d.Day(); - *month = d.Month(); - *year = d.Year(); -} - -const char* OswHal::getWeekday(time_t& offset, uint32_t* setWDay) { - uint32_t day = 0; - uint32_t wDay = 0; - this->getDate(offset, &day, &wDay); - - const char* dayMap[7] = {LANG_SUNDAY, LANG_MONDAY, LANG_TUESDAY, LANG_WEDNESDAY, LANG_THURSDAY, LANG_FRIDAY, LANG_SATURDAY}; - if (setWDay != nullptr) wDay = *setWDay; - return dayMap[wDay]; + oswDate.year = d.Year(); + oswDate.month = d.Month(); + oswDate.day = d.Day(); + oswDate.weekDay = d.DayOfWeek(); } \ No newline at end of file diff --git a/src/icon/OswIconProgmem.cpp b/src/icon/OswIconProgmem.cpp index c56ea8d14..1bcb1e278 100644 --- a/src/icon/OswIconProgmem.cpp +++ b/src/icon/OswIconProgmem.cpp @@ -44,4 +44,4 @@ void OswIconProgmem::draw(Graphics2D* gfx, int x, int y, uint16_t color, float s void OswIconProgmem::draw(Graphics2D* gfx, int x, int y, float scale, OswImage::Alignment xAlign, OswImage::Alignment yAlign) const { this->draw(gfx, x, y, this->color, scale, xAlign, yAlign); -} \ No newline at end of file +} diff --git a/src/main.cpp b/src/main.cpp index 553fd4ab7..3dcbb6892 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include //time #ifdef OSW_FEATURE_WIFI @@ -68,13 +69,14 @@ #include "./apps/watchfaces/OswAppWatchfaceBinary.h" #include "./apps/watchfaces/OswAppWatchfaceMonotimer.h" #include "./apps/watchfaces/OswAppWatchfaceNumerals.h" +#include "./apps/watchfaces/OswAppWatchfaceFitnessAnalog.h" #if OSW_PLATFORM_ENVIRONMENT_MAGNETOMETER == 1 && OSW_PLATFORM_HARDWARE_QMC5883L == 1 #include "./apps/_experiments/magnetometer_calibrate.h" #endif #if defined(GPS_EDITION) || defined(GPS_EDITION_ROTATED) #include "./apps/main/map.h" #endif -#include "./services/OswServiceTaskBLECompanion.h" +#include "services/OswServiceTaskBLECompanion.h" #include "services/OswServiceTaskMemMonitor.h" #include "services/OswServiceTasks.h" #ifdef OSW_FEATURE_WIFI @@ -96,7 +98,7 @@ using OswGlobals::main_tutorialApp; #endif void setup() { - Serial.begin(115200); + OswSerial::getInstance()->begin(115200); OSW_LOG_I("Welcome to the OSW-OS! This build is based on commit ", GIT_COMMIT_HASH, " from ", GIT_BRANCH_NAME, ". Compiled at ", __DATE__, " ", __TIME__, " for platform ", PIO_ENV_NAME, "."); @@ -107,7 +109,7 @@ void setup() { try { OswHal::getInstance()->setup(false); } catch(const std::exception& e) { - OSW_LOG_E("CRITICAL ERROR AT BOOTUP: ", + e.what()); + OSW_LOG_E("CRITICAL ERROR AT BOOTUP: ", e.what()); sleep(_MAIN_CRASH_SLEEP); ESP.restart(); } @@ -117,7 +119,10 @@ void setup() { main_mainDrawer.registerAppLazy(LANG_WATCHFACES); main_mainDrawer.registerAppLazy(LANG_WATCHFACES); main_mainDrawer.registerAppLazy(LANG_WATCHFACES); +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 main_mainDrawer.registerAppLazy(LANG_WATCHFACES); + main_mainDrawer.registerAppLazy(LANG_WATCHFACES); +#endif main_mainDrawer.registerAppLazy(LANG_WATCHFACES); main_mainDrawer.registerAppLazy(LANG_WATCHFACES); main_mainDrawer.registerAppLazy(LANG_WATCHFACES); @@ -144,7 +149,6 @@ void setup() { void loop() { static time_t lastPowerUpdate = time(nullptr) + 2; // We consider a run of at least 2 seconds as "success" static time_t nextTimezoneUpdate = time(nullptr) + 60; // Already done after sleep -> revisit in a while - static bool delayedAppInit = true; // check possible interaction with ULP program #if USE_ULP == 1 @@ -185,13 +189,9 @@ void loop() { sleep(_MAIN_CRASH_SLEEP); ESP.restart(); } - if (delayedAppInit) { - // fix flickering display on latest Arduino_GFX library - ledcWrite(1, OswConfigAllKeys::settingDisplayBrightness.get()); - } - if (delayedAppInit) { - delayedAppInit = false; + if (OswGlobals::main_delayedAppInit) { + OswGlobals::main_delayedAppInit = false; // TODO port all v1 apps to v2, to allow for lazy loading (or let them in compat mode) @@ -214,6 +214,7 @@ void loop() { #endif // Fitness App +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 #ifdef OSW_FEATURE_STATS_STEPS static OswAppStepStats fitnessStepStats; static OswAppKcalStats fitnessKcalStats; @@ -224,6 +225,7 @@ void loop() { #endif static OswAppFitnessStats fitnessStats; main_mainDrawer.registerApp(LANG_FITNESS, new OswAppV2Compat("osw.fit.fs", "Fitness Statistics", fitnessStats)); +#endif // Tools #if TOOL_CLOCK == 1 @@ -237,7 +239,7 @@ void loop() { #if TOOL_FLASHLIGHT == 1 main_mainDrawer.registerAppLazy(LANG_TOOLS); #endif -#if TOOL_WATERLEVEL == 1 +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 && TOOL_WATERLEVEL == 1 static OswAppWaterLevel toolWaterLevel; main_mainDrawer.registerApp(LANG_TOOLS, new OswAppV2Compat("osw.tool.wl", "Water Level", toolWaterLevel, true, waterlevel_png)); #endif diff --git a/src/math_angles.cpp b/src/math_angles.cpp index 740943fa1..40aec5455 100644 --- a/src/math_angles.cpp +++ b/src/math_angles.cpp @@ -2,30 +2,6 @@ #include -// rotate a point around a center (cy,cy), with a radius r, 0 degrees ist 12 o'clock -float rpx(float cx, float r, float d) { - return cx + r * cos((d - 90) * 1000.0 / 57296.0); -} -float rpy(float cy, float r, float d) { - return cy + r * sin((d - 90) * 1000.0 / 57296.0); -} - -// rotate a point around a point -int32_t rotateX(int32_t x, int32_t y, int32_t rx, int32_t ry, float cosA, float sinA) { - return (x - rx) * cosA + (y - ry) * sinA; -} -int32_t rotateY(int32_t x, int32_t y, int32_t rx, int32_t ry, float cosA, float sinA) { - return (y - ry) * cosA - (x - rx) * sinA; -} - -int32_t rotateX(int32_t x, int32_t y, int32_t rx, int32_t ry, float a) { - return (x - rx) * cos(a) + (y - ry) * sin(a); -} -int32_t rotateY(int32_t x, int32_t y, int32_t rx, int32_t ry, float a) { - return (y - ry) * cos(a) - (x - rx) * sin(a); -} - - // seconds to degrees (0-360) float s2d(long seconds) { return (seconds % 60) * 6; @@ -34,13 +10,13 @@ float s2d(long seconds) { // minutes to degrees (0-360) float m2d(long seconds) { long fh = (seconds / 3600); // full hours - return (((seconds - fh * 3600) / 60.0)) * 6; + return (((seconds - fh * 3600) / 60.0f)) * 6; } // hours to degrees (0-360) float h2d(long seconds) { long fd = (seconds / 3600) / 24; // full days - return ((seconds - fd * 24 * 3600) / 3600.0) * 30; + return ((seconds - fd * 24 * 3600) / 3600.0f) * 30; } float sign(float x1, float y1, float x2, float y2, float x3, float y3) { @@ -60,4 +36,4 @@ bool pointInsideTriangle(float px, float py, float x1, float y1, float x2, float has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0); return !(has_neg && has_pos); -} \ No newline at end of file +} diff --git a/src/math_osm.cpp b/src/math_osm.cpp index ac65ab18b..16cfe140e 100644 --- a/src/math_osm.cpp +++ b/src/math_osm.cpp @@ -7,12 +7,12 @@ // we return float here, because we need the fraction float lon2tilex(float lon, uint8_t z) { - return (lon + 180.0) / 360.0 * (float)(1 << z); + return (lon + 180.0f) / 360.0f * (float)(1 << z); } float lat2tiley(float lat, uint8_t z) { - float latrad = lat * PI / 180.0; - return (1.0 - asinh(tan(latrad)) / PI) / 2.0 * (float)(1 << z); + float latrad = lat * PI / 180.0f; + return (1.0f - asinh(tanf(latrad)) / PI) / 2.0f * (float)(1 << z); } // helper function to get the offset within the tile @@ -22,18 +22,18 @@ int32_t tileOffset(float tilex) { } float tilex2lon(float x, uint8_t z) { - return x / (float)(1 << z) * 360.0 - 180; + return x / (float)(1 << z) * 360.0f - 180.0f; } float tiley2lat(float y, uint8_t z) { float n = PI - TWO_PI * y / (float)(1 << z); - return 180.0 / PI * atan(0.5 * (exp(n) - exp(-n))); + return 180.0f / PI * atanf(0.5f * (expf(n) - expf(-n))); } -float osmResolution[] = {156543.03, 78271.52, 39135.76, 19567.88, 9783.94, 4891.97, 2445.98, 1222.99, 611.50, 305.75, - 152.87, 76.43, 38.21, 19.10, 9.55, 4.77, 2.38, 1.19, 0.59 +float osmResolution[] = {156543.03f, 78271.52f, 39135.76f, 19567.88f, 9783.94f, 4891.97f, 2445.98f, 1222.99f, 611.50f, 305.75f, + 152.87f, 76.43f, 38.21f, 19.10f, 9.55f, 4.77f, 2.38f, 1.19f, 0.59f }; float getTileResolution(float lat, uint8_t z) { - return 156543.03 /*meters/pixel*/ * cos(lat) / (2 ^ z); + return 156543.03f /*meters/pixel*/ * cosf(lat) / (2 ^ z); } diff --git a/src/math_tables.cpp b/src/math_tables.cpp new file mode 100644 index 000000000..9af5a1a2c --- /dev/null +++ b/src/math_tables.cpp @@ -0,0 +1,53 @@ + +// These are values for the trigonometric functions +// sinDeg[12]=sinf(12*PI/180.0f) + +extern const float sinDeg[]; + +const float sinDeg[] = { + +0.000000, +0.017452, +0.034899, +0.052336, +0.069756, +0.087156, +0.104528, +0.121869, + +0.139173, +0.156434, +0.173648, +0.190809, +0.207912, +0.224951, +0.241922, +0.258819, + +0.275637, +0.292372, +0.309017, +0.325568, +0.342020, +0.358368, +0.374607, +0.390731, + +0.406737, +0.422618, +0.438371, +0.453991, +0.469472, +0.484810, +0.500000, +0.515038, + +0.529919, +0.544639, +0.559193, +0.573577, +0.587785, +0.601815, +0.615662, +0.629320, + +0.642788, +0.656059, +0.669131, +0.681998, +0.694658, +0.707107, +0.719340, +0.731354, + +0.743145, +0.754710, +0.766044, +0.777146, +0.788011, +0.798636, +0.809017, +0.819152, + +0.829038, +0.838671, +0.848048, +0.857167, +0.866025, +0.874620, +0.882948, +0.891007, + +0.898794, +0.906308, +0.913545, +0.920505, +0.927184, +0.933580, +0.939693, +0.945519, + +0.951057, +0.956305, +0.961262, +0.965926, +0.970296, +0.974370, +0.978148, +0.981627, + +0.984808, +0.987688, +0.990268, +0.992546, +0.994522, +0.996195, +0.997564, +0.998630, + +0.999391, +0.999848, +1.000000, +0.999848, +0.999391, +0.998630, +0.997564, +0.996195, + +0.994522, +0.992546, +0.990268, +0.987688, +0.984808, +0.981627, +0.978148, +0.974370, + +0.970296, +0.965926, +0.961262, +0.956305, +0.951056, +0.945519, +0.939693, +0.933580, + +0.927184, +0.920505, +0.913545, +0.906308, +0.898794, +0.891006, +0.882948, +0.874620, + +0.866025, +0.857167, +0.848048, +0.838671, +0.829037, +0.819152, +0.809017, +0.798635, + +0.788011, +0.777146, +0.766044, +0.754710, +0.743145, +0.731354, +0.719340, +0.707107, + +0.694658, +0.681998, +0.669131, +0.656059, +0.642787, +0.629320, +0.615661, +0.601815, + +0.587785, +0.573576, +0.559193, +0.544639, +0.529919, +0.515038, +0.500000, +0.484810, + +0.469472, +0.453990, +0.438371, +0.422618, +0.406737, +0.390731, +0.374606, +0.358368, + +0.342020, +0.325568, +0.309017, +0.292372, +0.275637, +0.258819, +0.241922, +0.224951, + +0.207912, +0.190809, +0.173648, +0.156434, +0.139173, +0.121869, +0.104528, +0.087156, + +0.069756, +0.052336, +0.034899, +0.017452, -0.000000, -0.017453, -0.034900, -0.052336, + -0.069756, -0.087156, -0.104528, -0.121869, -0.139173, -0.156435, -0.173648, -0.190809, + -0.207912, -0.224951, -0.241922, -0.258819, -0.275638, -0.292372, -0.309017, -0.325568, + -0.342020, -0.358368, -0.374607, -0.390731, -0.406737, -0.422618, -0.438371, -0.453991, + -0.469472, -0.484810, -0.500000, -0.515038, -0.529919, -0.544639, -0.559193, -0.573577, + -0.587785, -0.601815, -0.615661, -0.629320, -0.642788, -0.656059, -0.669131, -0.681998, + -0.694659, -0.707107, -0.719340, -0.731354, -0.743145, -0.754710, -0.766045, -0.777146, + -0.788011, -0.798635, -0.809017, -0.819152, -0.829038, -0.838671, -0.848048, -0.857167, + -0.866025, -0.874620, -0.882948, -0.891007, -0.898794, -0.906308, -0.913545, -0.920505, + -0.927184, -0.933581, -0.939693, -0.945519, -0.951057, -0.956305, -0.961262, -0.965926, + -0.970296, -0.974370, -0.978148, -0.981627, -0.984808, -0.987688, -0.990268, -0.992546, + -0.994522, -0.996195, -0.997564, -0.998630, -0.999391, -0.999848, -1.000000, -0.999848, + -0.999391, -0.998630, -0.997564, -0.996195, -0.994522, -0.992546, -0.990268, -0.987688, + -0.984808, -0.981627, -0.978148, -0.974370, -0.970296, -0.965926, -0.961262, -0.956305, + -0.951056, -0.945519, -0.939693, -0.933580, -0.927184, -0.920505, -0.913545, -0.906308, + -0.898794, -0.891006, -0.882948, -0.874620, -0.866025, -0.857167, -0.848048, -0.838670, + -0.829038, -0.819152, -0.809017, -0.798635, -0.788011, -0.777146, -0.766044, -0.754709, + -0.743145, -0.731354, -0.719339, -0.707107, -0.694658, -0.681998, -0.669131, -0.656059, + -0.642787, -0.629320, -0.615661, -0.601815, -0.587785, -0.573576, -0.559193, -0.544639, + -0.529919, -0.515038, -0.500000, -0.484809, -0.469471, -0.453991, -0.438371, -0.422618, + -0.406736, -0.390731, -0.374606, -0.358368, -0.342020, -0.325568, -0.309017, -0.292372, + -0.275638, -0.258819, -0.241922, -0.224951, -0.207911, -0.190809, -0.173648, -0.156434, + -0.139173, -0.121869, -0.104529, -0.087156, -0.069756, -0.052336, -0.034900, -0.017452, 0.000000 + }; diff --git a/src/osm_render.cpp b/src/osm_render.cpp index 8f6022320..eed3af7db 100644 --- a/src/osm_render.cpp +++ b/src/osm_render.cpp @@ -30,7 +30,7 @@ Graphics2D* getTile(BufferedTile** buffer, uint8_t bufferLength, loadTile loadTi } } - // overwrite withe new tile + // overwrite with new tile buffer[oldestIndex]->loadTile(loadTileFn, tileX, tileY, tileZ); // return fresh tile diff --git a/src/osw_config.cpp b/src/osw_config.cpp index 8125ed946..b6bf186cf 100644 --- a/src/osw_config.cpp +++ b/src/osw_config.cpp @@ -173,4 +173,4 @@ void OswConfig::notifyChange() { // OswUI::getInstance()->resetTextColors(); // nope - this is done by the ui itself OswHal::getInstance()->updateTimezoneOffsets(); OswAppWatchfaceDigital::refreshDateFormatCache(); -} \ No newline at end of file +} diff --git a/src/osw_config_keys.cpp b/src/osw_config_keys.cpp index 3baa34ac4..e3c0fedc1 100644 --- a/src/osw_config_keys.cpp +++ b/src/osw_config_keys.cpp @@ -1,4 +1,5 @@ #include "osw_config_keys.h" +#include OSW_TARGET_PLATFORM_HEADER #include #ifndef OSW_EMULATOR @@ -16,6 +17,7 @@ #include "apps/watchfaces/OswAppWatchfaceBinary.h" #include "apps/watchfaces/OswAppWatchfaceMonotimer.h" #include "apps/watchfaces/OswAppWatchfaceNumerals.h" +#include "apps/watchfaces/OswAppWatchfaceFitnessAnalog.h" /** * !!!WARNING!!! @@ -60,7 +62,10 @@ OswConfigKeyDropDown settingDisplayDefaultWatchface("n", "Display", "Default Wat OswAppWatchfaceDigital::APP_ID, OswAppWatchfaceMix::APP_ID, OswAppWatchfaceDual::APP_ID, +#if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 OswAppWatchfaceFitness::APP_ID, + OswAppWatchfaceFitnessAnalog::APP_ID, +#endif OswAppWatchfaceBinary::APP_ID, OswAppWatchfaceMonotimer::APP_ID, OswAppWatchfaceNumerals::APP_ID @@ -73,6 +78,7 @@ OswConfigKeyShort oswAppV2ButtonDoublePress("d4", "Display", "Button double pres OswConfigKeyShort oswAppV2ButtonLongPress("d5", "Display", "Button long press time", "Unit: ms", CONFIG_APPV2_LONG_PRESS_TIME); OswConfigKeyShort oswAppV2ButtonVeryLongPress("d6", "Display", "Button very long press time", "Unit: ms", CONFIG_APPV2_VERY_LONG_PRESS_TIME); +#if OSW_PLATFORM_BLOCK_SLEEP != 1 OswConfigKeyBool raiseToWakeEnabled("s5", "Power", "Raise/Tilt to Wake", "Enables Raise to Wake", WAKE_FROM_RAISE); OswConfigKeyShort raiseToWakeSensitivity("s6", "Power", "Raise to Wake Sensitivity", @@ -84,6 +90,7 @@ OswConfigKeyBool tapToWakeEnabled("s8", "Power", "Tap to Wake", WAKE_FROM_TAP); OswConfigKeyBool buttonToWakeEnabled("m", "Power", "Button to Wake", "This will always be used, in case no other trigger is enabled", WAKE_FROM_BTN1); +#endif OswConfigKeyRGB themeBackgroundColor("c1", "Theme & UI", "Background color", nullptr, THEME_BACKROUND_COLOR); OswConfigKeyRGB themeBackgroundDimmedColor("c8", "Theme & UI", "Background color (dimmed)", nullptr, @@ -102,8 +109,8 @@ OswConfigKeyBool timeFormat("g", "Date & Time", "Use 24h time format?", nullptr, OswConfigKeyString timezonePrimary("p1", "Date & Time", "Primary Timezone", "Empty = UTC0, use values from https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv", CONFIG_TIMEZONE_PRIMARY); OswConfigKeyString timezoneSecondary("p2", "Date & Time", "Secondary Timezone", nullptr, CONFIG_TIMEZONE_SECONDARY); #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 -OswConfigKeyShort configHeight("f4", "Fitness", "User Height", "E.g 175.7 cm -> 175 (Rounds off)", 175); -OswConfigKeyShort configWeight("f5", "Fitness", "User Weight", "E.g 70.3 kg -> 70 (Rounds off)", 70); +OswConfigKeyShort configHeight("f4", "Fitness", "User Height", "E.g 182.7 cm -> 182 (Rounds off)", 182); +OswConfigKeyShort configWeight("f5", "Fitness", "User Weight", "E.g 85.3 kg -> 70 (Rounds off)", 85); OswConfigKeyInt stepsPerDay("f1", "Fitness", "Steps per day", "> 0!", STEPS_PER_DAY); OswConfigKeyInt distPerDay("f2", "Fitness", "Distance per day", "> 0!", DIST_PER_DAY); OswConfigKeyInt kcalPerDay("f3", "Fitness", "kcalorie per day", "> 0!", KCAL_PER_DAY); @@ -141,14 +148,16 @@ OswConfigKey* oswConfigKeys[] = { #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 & OswConfigAllKeys::settingDisplayStepsGoal, #endif +#if OSW_PLATFORM_BLOCK_SLEEP != 1 // energy &OswConfigAllKeys::buttonToWakeEnabled, &OswConfigAllKeys::raiseToWakeEnabled, &OswConfigAllKeys::raiseToWakeSensitivity, &OswConfigAllKeys::tapToWakeEnabled, &OswConfigAllKeys::lightSleepEnabled, +#endif // date + time &OswConfigAllKeys::dateFormat, &OswConfigAllKeys::timezonePrimary, &OswConfigAllKeys::timezoneSecondary, - &OswConfigAllKeys::timeFormat, &OswConfigAllKeys::resetDay, + &OswConfigAllKeys::timeFormat, // colors &OswConfigAllKeys::themeBackgroundColor, &OswConfigAllKeys::themeBackgroundDimmedColor, &OswConfigAllKeys::themeForegroundColor, &OswConfigAllKeys::themeForegroundDimmedColor, @@ -157,9 +166,10 @@ OswConfigKey* oswConfigKeys[] = { #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 // fitness &OswConfigAllKeys::configHeight, &OswConfigAllKeys::configWeight, &OswConfigAllKeys::stepsPerDay, - &OswConfigAllKeys::distPerDay, &OswConfigAllKeys::kcalPerDay, &OswConfigAllKeys::stepsHistoryClear - //weather + &OswConfigAllKeys::distPerDay, &OswConfigAllKeys::kcalPerDay, &OswConfigAllKeys::stepsHistoryClear, + &OswConfigAllKeys::resetDay #ifdef OSW_FEATURE_WEATHER + //weather ,&OswConfigAllKeys::weatherApiKey,&OswConfigAllKeys::weatherLocation1, &OswConfigAllKeys::weatherState1 #endif #endif diff --git a/src/osw_hal.cpp b/src/osw_hal.cpp index 6af8297da..7c4a5e205 100644 --- a/src/osw_hal.cpp +++ b/src/osw_hal.cpp @@ -34,7 +34,12 @@ void OswHal::resetInstance() { OswHal::OswHal(FileSystemHal* fs) : fileSystem(fs) { //begin I2c communication #ifndef OSW_EMULATOR - Wire.begin(OSW_DEVICE_I2C_SDA, OSW_DEVICE_I2C_SCL, 100000L); +#if defined(OSW_DEVICE_I2C_SDA) && defined(OSW_DEVICE_I2C_SCL) + bool res = Wire.begin(OSW_DEVICE_I2C_SDA, OSW_DEVICE_I2C_SCL, 100000L); + assert(res); +#else +#warning "I2C pins are not set on this platform, ignoring it then..." +#endif #endif } @@ -55,6 +60,7 @@ void OswHal::setup(bool fromLightSleep) { this->environment()->updateProviders(); #endif } + this->setupPower(fromLightSleep); this->setupButtons(); this->setupFileSystem(); @@ -63,6 +69,7 @@ void OswHal::setup(bool fromLightSleep) { this->setupPower(fromLightSleep); this->displayOn(); } + this->devices()->setup(fromLightSleep); this->devices()->update(); // Update internal cache to refresh / initialize the value obtained by calling this->getAccelStepCount() - needed for e.g. the step statistics! this->updateTimezoneOffsets(); // Always update, just in case DST changed during (light) sleep - after all devices are setup/updated, as they might use their time for this calculation @@ -86,10 +93,27 @@ void OswHal::stop(bool toLightSleep) { this->displayOff(); // This disables the display OswServiceManager::getInstance().stop(); - if(!toLightSleep) { + if (!toLightSleep) { + this->gfx()->fillBuffer(rgb565(0,0,0)); // This makes the display black + this->flushCanvas(); +#if OSW_PLATFORM_ENVIRONMENT == 1 this->_environment.reset(); +#endif this->_devices.reset(); this->timeProvider = nullptr; // He is properly destroyed after devices destruction ↑ } OSW_LOG_D(toLightSleep ? "-> light sleep " : "-> deep sleep "); -} \ No newline at end of file +} + +#if OSW_PLATFORM_IS_FLOW3R_BADGE == 1 +uint8_t OswHal::readGpioExtender(uint8_t address) { + Wire.beginTransmission(address); + Wire.write(0xFF); // we do not want to output anything (who knows if this is a good idea) + uint8_t error = Wire.endTransmission(); + if (error != 0) + OSW_LOG_W("Failed to communicate with GPIO extender chip!"); + uint8_t bytes = 1; // using a variable to prevent compiler warnings.. + Wire.requestFrom(address, bytes); + return Wire.read(); +} +#endif diff --git a/src/osw_lua.cpp b/src/osw_lua.cpp index fd28c52bb..4c0ca58e8 100644 --- a/src/osw_lua.cpp +++ b/src/osw_lua.cpp @@ -71,4 +71,4 @@ LUALIB_API void luaL_openlibs (lua_State* L) { lua_pop(L, 1); /* remove lib */ } } -#endif \ No newline at end of file +#endif diff --git a/src/osw_service.cpp b/src/osw_service.cpp index d1cdf970d..3cc163f09 100644 --- a/src/osw_service.cpp +++ b/src/osw_service.cpp @@ -9,4 +9,4 @@ void OswServiceTask::stop() { bool OswServiceTask::isRunning() { return this->taskEnabled; -} \ No newline at end of file +} diff --git a/src/osw_ui.cpp b/src/osw_ui.cpp index dabb906f6..4780e3e34 100644 --- a/src/osw_ui.cpp +++ b/src/osw_ui.cpp @@ -151,7 +151,7 @@ void OswUI::loop() { // Full-Screen progress OswHal::getInstance()->gfx()->setTextCenterAligned(); OswHal::getInstance()->gfx()->setTextSize(2.0f); - OswHal::getInstance()->gfx()->setTextCursor(DISP_W * 0.5, DISP_W * 0.5); + OswHal::getInstance()->gfx()->setTextCursor(DISP_W * 0.5f, DISP_H * 0.5f); OswHal::getInstance()->gfx()->print(this->mProgressText); this->mProgressBar->draw(); } @@ -184,7 +184,7 @@ bool OswUI::getProgressActive() { void OswUI::startProgress(const char* text) { if (!this->getProgressActive()) - this->mProgressBar = new OswUI::OswUIProgress((short)DISP_W * 0.2, (short)DISP_H * 0.6, (short)DISP_W * 0.6); + this->mProgressBar = new OswUI::OswUIProgress((short)DISP_W * 0.2f, (short)DISP_H * 0.6f, (short)DISP_W * 0.6f); this->mProgressText = text; } @@ -269,7 +269,7 @@ float OswUI::OswUIProgress::calcValue() { } void OswUI::OswUIProgress::draw() { - const float barWidth = 0.4; // For unknown progress bouncing + const float barWidth = 0.4f; // For unknown progress bouncing const short barHeight = 6; const short barRadius = 3; const float value = this->calcValue(); @@ -312,6 +312,6 @@ void OswUI::OswUINotification::draw(unsigned y) const { gfx->drawHLine(0, y, DISP_W, OswUI::getInstance()->getInfoColor()); gfx->resetText(); gfx->setTextCenterAligned(); - gfx->setTextCursor(DISP_W * 0.5, y + (this->sDrawHeight * 0.5) + 8 / 2); // To center the text, it is assumed that one char has a height of 8 pixels + gfx->setTextCursor(DISP_W * 0.5f, y + (this->sDrawHeight * 0.5f) + 8 / 2); // To center the text, it is assumed that one char has a height of 8 pixels gfx->print(this->message); -} \ No newline at end of file +} diff --git a/src/osw_ulp.cpp b/src/osw_ulp.cpp index 153fba468..ed0ffbbaa 100644 --- a/src/osw_ulp.cpp +++ b/src/osw_ulp.cpp @@ -8,7 +8,7 @@ RTC_DATA_ATTR ulp_var_t ulp_tsens_val; void init_ulp() { - // Define the ULP Programm here + // Define the ULP Program here const ulp_insn_t program[] = { I_TSENS(R0, 1000), I_MOVI(R2, 0), diff --git a/src/overlays/overlays.cpp b/src/overlays/overlays.cpp index 68c48a1d5..99cf2862d 100644 --- a/src/overlays/overlays.cpp +++ b/src/overlays/overlays.cpp @@ -26,19 +26,20 @@ void drawBattery(uint16_t x, uint16_t y) { batColor = batLvl < 50 ? OswUI::getInstance()->getWarningColor() : batColor; batColor = batLvl < 25 ? OswUI::getInstance()->getDangerColor() : batColor; - if (batLvl < 0.5) { + if (batLvl < 0.5f) { // This happens initial discharging (calibration phase) of the battery or when you're in trouble! gfx->fillFrame(x + 2, y + 2, 25, 9, OswUI::getInstance()->getInfoColor()); } else { - gfx->fillFrame(x + 2, y + 2, 25 * (batLvl / 100.0), 9, batColor); // charge + gfx->fillFrame(x + 2, y + 2, 25 * (batLvl / 100.0f), 9, batColor); // charge } } #ifdef OSW_FEATURE_WIFI void drawWiFi(uint16_t x, uint16_t y) { + Graphics2DPrint* gfx = OswHal::getInstance()->gfx(); if (OswServiceAllTasks::wifi.isWiFiEnabled()) { for (uint8_t i = 0; i < OswServiceAllTasks::wifi.getSignalQuality() / 20; i++) { - OswHal::getInstance()->gfx()->fillFrame(x + 3 * i, y + 12 - i * 2, 2, i * 2, OswUI::getInstance()->getForegroundColor()); // outer frame + gfx->fillFrame(x + 3 * i, y + 12 - i * 2, 2, i * 2, OswUI::getInstance()->getForegroundColor()); // outer frame } } } diff --git a/src/services/NotifierClient.cpp b/src/services/NotifierClient.cpp index b77f36e77..7991d7e25 100644 --- a/src/services/NotifierClient.cpp +++ b/src/services/NotifierClient.cpp @@ -19,4 +19,4 @@ std::vector NotifierClient::readNotifications() { void NotifierClient::deleteNotification(unsigned id) { OswServiceAllTasks::notifier.deleteNotification(id, publisher); -} \ No newline at end of file +} diff --git a/src/services/OswServiceManager.cpp b/src/services/OswServiceManager.cpp index 8ea6bda4c..b5cb80863 100644 --- a/src/services/OswServiceManager.cpp +++ b/src/services/OswServiceManager.cpp @@ -53,4 +53,4 @@ void OswServiceManager::stop() { for (unsigned char i = 0; i < oswServiceTasksCount; i++) if(oswServiceTasks[i]) oswServiceTasks[i]->stop(); -} \ No newline at end of file +} diff --git a/src/services/OswServiceTaskBLECompanion.cpp b/src/services/OswServiceTaskBLECompanion.cpp index 07490d263..2e516b2af 100644 --- a/src/services/OswServiceTaskBLECompanion.cpp +++ b/src/services/OswServiceTaskBLECompanion.cpp @@ -1,4 +1,10 @@ #ifndef OSW_EMULATOR + +#if SERVICE_BLE_COMPANION == 1 +#ifdef OSW_FEATURE_WIFI +#error "The RAM on all current OSW models is not big enough to hold both WiFi AND Bluetooth stacks during runtime. This WILL lead to a crash. Please only use one of these features simultaneously!" +#endif + #include "./services/OswServiceTaskBLECompanion.h" #include "osw_hal.h" @@ -11,12 +17,6 @@ #include #include "config_defaults.h" -#ifdef OSW_FEATURE_WIFI -#if SERVICE_BLE_COMPANION == 1 -#error "The RAM on all current OSW models is not big enough to hold both WiFi AND Bluetooth stacks during runtime. This WILL lead to a crash. Please only use one of these features simultaneously!" -#endif -#endif - class NotificationCallback: public BLECharacteristicCallbacks { public: NotificationCallback(OswServiceTaskBLECompanion* comp) { @@ -94,4 +94,5 @@ void OswServiceTaskBLECompanion::loop() { void OswServiceTaskBLECompanion::stop() { OswServiceTask::stop(); } -#endif \ No newline at end of file +#endif +#endif diff --git a/src/services/OswServiceTaskConsole.cpp b/src/services/OswServiceTaskConsole.cpp index b77ced93d..a3aabfd96 100644 --- a/src/services/OswServiceTaskConsole.cpp +++ b/src/services/OswServiceTaskConsole.cpp @@ -1,3 +1,4 @@ +#include #include "./services/OswServiceTaskConsole.h" #include "osw_hal.h" @@ -12,8 +13,9 @@ void OswServiceTaskConsole::setup() { void OswServiceTaskConsole::loop() { while(true) { - if(!Serial.available()) break; - char c = Serial.read(); + OswSerial* serial = OswSerial::getInstance(); + char c; + if(!serial->getc((uint8_t&) c)) break; switch (c) { case 10: // LF case 13: // CR @@ -26,19 +28,19 @@ void OswServiceTaskConsole::loop() { if(this->m_inputBuffer.length() > 0) { this->m_inputBuffer.pop_back(); } - Serial.print(c); + serial->print(c); break; case 9: // tab - Serial.println(); // finish the prompt line + serial->println(); // finish the prompt line this->showHelp(); this->showPrompt(); break; default: if(32 <= c and c <= 126) { // printable characters this->m_inputBuffer += c; - Serial.print(c); // echo the entered character back + serial->print(c); // echo the entered character back } else { - Serial.print((char) 0x07); // bell + serial->print((char) 0x07); // bell OSW_LOG_D("Unprocessable character (",(int) c, "): ", c); } } @@ -52,21 +54,23 @@ void OswServiceTaskConsole::newPrompt() { } void OswServiceTaskConsole::showPrompt() { + OswSerial* serial = OswSerial::getInstance(); if (this->m_configuring) { - Serial.print("OSW (configure) > "); + serial->print("OSW (configure) > "); } else { - Serial.print("OSW > "); + serial->print("OSW > "); } if(!this->m_inputBuffer.empty()) { - Serial.print(this->m_inputBuffer.c_str()); + serial->print(this->m_inputBuffer.c_str()); } } void OswServiceTaskConsole::runPrompt() { - Serial.println(); // finish the prompt line + OswSerial* serial = OswSerial::getInstance(); + serial->println(); // finish the prompt line if(this->m_inputBuffer.empty()) return; if(this->m_locked) { - Serial.println("Console is locked! Enter \"unlock\" to unlock."); + serial->println("Console is locked! Enter \"unlock\" to unlock."); if(this->m_inputBuffer == "unlock") { this->m_locked = false; } @@ -83,18 +87,18 @@ void OswServiceTaskConsole::runPrompt() { auto key = this->m_inputBuffer.substr(4); for (auto i = 0; i < oswConfigKeysCount; i++) { if(oswConfigKeys[i]->id == key) { - Serial.println(oswConfigKeys[i]->toString()); + serial->println(oswConfigKeys[i]->toString()); break; } } } else if (this->m_inputBuffer.find("info ") == 0 and this->m_inputBuffer.length() > 5) { auto key = this->m_inputBuffer.substr(5); - Serial.println(OswConfig::getInstance()->getFieldJson(key.c_str())); + serial->println(OswConfig::getInstance()->getFieldJson(key.c_str())); } else if (this->m_inputBuffer == "help") { this->showHelp(); } else if (this->m_inputBuffer == "list") { for (auto i = 0; i < oswConfigKeysCount; i++) { - Serial.println(oswConfigKeys[i]->id); + serial->println(oswConfigKeys[i]->id); } } else if (this->m_inputBuffer.find("reset ") == 0 and this->m_inputBuffer.length() > 7) { auto key = this->m_inputBuffer.substr(7); @@ -105,7 +109,7 @@ void OswServiceTaskConsole::runPrompt() { auto key = this->m_inputBuffer.substr(4); // " " auto space = key.find(" ", 0); if (space == std::string::npos) { - Serial.println("Invalid command."); + serial->println("Invalid command."); return; } auto value = key.substr(space + 1); // "" @@ -123,7 +127,7 @@ void OswServiceTaskConsole::runPrompt() { this->showHelp(); #ifdef OSW_FEATURE_WIFI } else if (this->m_inputBuffer == "hostname") { - Serial.println(OswConfigAllKeys::hostname.get()); + serial->println(OswConfigAllKeys::hostname.get()); #endif } else if (this->m_inputBuffer == "lock") { this->m_locked = true; @@ -133,7 +137,7 @@ void OswServiceTaskConsole::runPrompt() { ESP.restart(); #endif } else if (this->m_inputBuffer == "time") { - Serial.println(OswHal::getInstance()->getUTCTime()); + serial->println(OswHal::getInstance()->getUTCTime()); } else if (this->m_inputBuffer == "wipe") { OswConfig::getInstance()->reset(true); } else { @@ -142,8 +146,8 @@ void OswServiceTaskConsole::runPrompt() { } // show help if the command was not processed if (!processed) { - Serial.println("Unknown command."); - Serial.println(); + serial->println("Unknown command."); + serial->println(); this->showHelp(); this->m_lockCounter++; } @@ -155,33 +159,34 @@ void OswServiceTaskConsole::runPrompt() { } void OswServiceTaskConsole::showHelp() { - Serial.println("Available commands:"); + OswSerial* serial = OswSerial::getInstance(); + serial->println("Available commands:"); // let's try to be civil and show the commands in alphabetical order if (this->m_configuring) { - Serial.println(" clear - reset all keys to default values"); - Serial.println(" exit - leave configuration mode"); - Serial.println(" get - get a value for a key"); - Serial.println(" help - show this help"); - Serial.println(" info - show more information about a key"); - Serial.println(" list - show all keys"); - Serial.println(" reset - reset a key to default value"); - Serial.println(" set - set a value for a key (value is everything until the end of the line)"); + serial->println(" clear - reset all keys to default values"); + serial->println(" exit - leave configuration mode"); + serial->println(" get - get a value for a key"); + serial->println(" help - show this help"); + serial->println(" info - show more information about a key"); + serial->println(" list - show all keys"); + serial->println(" reset - reset a key to default value"); + serial->println(" set - set a value for a key (value is everything until the end of the line)"); } else { - Serial.println(" configure - enter configuration mode"); - Serial.println(" help - show this help"); + serial->println(" configure - enter configuration mode"); + serial->println(" help - show this help"); #ifdef OSW_FEATURE_WIFI - Serial.println(" hostname - show the device hostname"); + serial->println(" hostname - show the device hostname"); #endif - Serial.println(" lock - lock the console"); + serial->println(" lock - lock the console"); #ifndef OSW_EMULATOR - Serial.println(" reboot - warm-start the device forcefully"); + serial->println(" reboot - warm-start the device forcefully"); #endif - Serial.println(" time - show current UTC time"); - Serial.println(" wipe - format NVS partition and reset configuration"); + serial->println(" time - show current UTC time"); + serial->println(" wipe - format NVS partition and reset configuration"); } } void OswServiceTaskConsole::stop() { OSW_LOG_I("Console is now disabled."); OswServiceTask::stop(); -} \ No newline at end of file +} diff --git a/src/services/OswServiceTaskMemMonitor.cpp b/src/services/OswServiceTaskMemMonitor.cpp index 916573aef..560455f35 100644 --- a/src/services/OswServiceTaskMemMonitor.cpp +++ b/src/services/OswServiceTaskMemMonitor.cpp @@ -125,4 +125,4 @@ void OswServiceTaskMemMonitor::printStats() { msg.trim(); OSW_LOG_D(msg); } -#endif \ No newline at end of file +#endif diff --git a/src/services/OswServiceTaskNotifier.cpp b/src/services/OswServiceTaskNotifier.cpp index 7c62aa787..d0902bd90 100644 --- a/src/services/OswServiceTaskNotifier.cpp +++ b/src/services/OswServiceTaskNotifier.cpp @@ -108,4 +108,4 @@ void OswServiceTaskNotifier::loop() { void OswServiceTaskNotifier::stop() { OswServiceTask::stop(); -} \ No newline at end of file +} diff --git a/src/services/OswServiceTaskWebserver.cpp b/src/services/OswServiceTaskWebserver.cpp index 4311d5e59..3c2634bdb 100644 --- a/src/services/OswServiceTaskWebserver.cpp +++ b/src/services/OswServiceTaskWebserver.cpp @@ -374,4 +374,4 @@ String OswServiceTaskWebserver::getPassword() const { WebServer* OswServiceTaskWebserver::getTaskWebserver() const { return this->m_webserver; } -#endif \ No newline at end of file +#endif diff --git a/src/services/OswServiceTaskWiFi.cpp b/src/services/OswServiceTaskWiFi.cpp index 3c15dd6e1..cd1a54481 100644 --- a/src/services/OswServiceTaskWiFi.cpp +++ b/src/services/OswServiceTaskWiFi.cpp @@ -38,16 +38,9 @@ void OswServiceTaskWiFi::loop() { this->m_connectFailureCount = 0; } else if(!this->m_connectTimeout and WiFi.status() != WL_CONNECTED) { // Wifi is either disconnected or unavailable... - if(this->onlyOneModeSimultaneously and this->m_enableStation) { - // This watch does not support connecting to networks with an active AutoAP. - // It would therefore be not helpful to activate the timeout to try an other - // action, while the AutoAP is active as this will shutdown the AutoAP as the - // timeout expires! - } else { - // -> start timeout - this->m_connectTimeout = time(nullptr); - OSW_LOG_D("[Connection] Timeout activated: 10 seconds"); - } + // -> start timeout + this->m_connectTimeout = time(nullptr); + OSW_LOG_D("[Connection] Timeout activated: 10 seconds"); } // Handling in case of 10 seconds without a successful connect @@ -232,7 +225,7 @@ bool OswServiceTaskWiFi::isStationEnabled() { /** * This enables the wifi station mode * - * @param password Set the wifi password to this (at least 8 chars!), otherwise a random password will be choosen. This parameter can be ignored if the station password is inactive in the config. + * @param password Set the wifi password to this (at least 8 chars!), otherwise a random password will be chosen. This parameter can be ignored if the station password is inactive in the config. */ void OswServiceTaskWiFi::enableStation(const String& password) { const bool usePassword = OswConfigAllKeys::hostPasswordEnabled.get(); @@ -307,11 +300,8 @@ void OswServiceTaskWiFi::updateWiFiConfig() { } #endif - if(!this->onlyOneModeSimultaneously and this->m_enableWiFi and this->m_enableClient and this->m_enableStation) { - WiFi.mode(WIFI_MODE_APSTA); - OSW_LOG_D("[Mode] Station & client"); - } else if(this->m_enableWiFi and this->m_enableStation) { - //Check this BEFORE the client, so in case of onlyOneModeSimultaneously we prefer the station, when enabled! + // How about "WiFi.mode(WIFI_MODE_APSTA)"? Well, so far every ESP was unable to work with this properly. So we removed it. + if(this->m_enableWiFi and this->m_enableStation) { WiFi.mode(WIFI_MODE_AP); OSW_LOG_D("[Mode] Station"); } else if(this->m_enableWiFi and this->m_enableClient) { @@ -340,4 +330,4 @@ uint8_t OswServiceTaskWiFi::getSignalQuality() { } return quality; } -#endif \ No newline at end of file +#endif diff --git a/src/swig/.gitignore b/src/swig/.gitignore index fe17051a4..2e2de16da 100644 --- a/src/swig/.gitignore +++ b/src/swig/.gitignore @@ -1 +1 @@ -osw_wrap.cxx \ No newline at end of file +osw_wrap.cxx